网站职业技能培训学校,qt做网站,网站导航的展开与收缩怎么做的,免费网站一键生成Java SE 8 新增特性
作者#xff1a;Grey
原文地址#xff1a;
博客园#xff1a;Java SE 8 新增特性
CSDN#xff1a;Java SE 8 新增特性
源码
源仓库: Github#xff1a;java_new_features
Lambda 表达式
Java SE 8 里面最大的更新莫过于支持 Lambda 表达式Grey
原文地址
博客园Java SE 8 新增特性
CSDNJava SE 8 新增特性
源码
源仓库: Githubjava_new_features
Lambda 表达式
Java SE 8 里面最大的更新莫过于支持 Lambda 表达式Oracle 官网给了一个很好的示例说明见Lambda Expressions以下示例参考了这个官方说明文档。
假设我们定义一个 Person 类属性和方法如下
public class Person {String name;LocalDate birthday;Sex gender;String emailAddress;// 省略get/set方法public void printPerson() {// 打印Person信息}public static ListPerson createRoster() {// 获取Person列表}public enum Sex {MALE, FEMALE}
}如果要获取某个年龄段的所有 Person 信息我们可能会写出如下代码
// 查询大于age的所有人员信息
public static void printPersonsOlderThan(ListPerson roster, int age) {for (Person p : roster) {if (p.getAge() age) {p.printPerson();}}
}
// 查询年龄在[low, high)区间内的所有人员信息
public static void printPersonsWithinAgeRange(ListPerson roster, int low, int high) {for (Person p : roster) {if (low p.getAge() p.getAge() high) {p.printPerson();}}
}这样写的缺点是扩展性不好如果有新的规则我们需要增加多个同样类型的方法。
更好的一种方式是定义一个 Local Class将规则分离出来这样一来规则无论如何变化主流程的代码是不需要调整的以上述例子来说明。我们定义如下接口
interface CheckPerson {boolean test(Person p);
}这个接口用于抽象出规则的定义在主流程中我们把这个接口设计到参数中代码如下
public static void printPersons(ListPerson roster, CheckPerson tester) {for (Person p : roster) {if (tester.test(p)) {p.printPerson();}}
}这样我们就做到了规则和主流程分离比如我们要定义一个规则只需要实现 CheckPerson 接口
// 年龄在[18,25]区间内的男性人员信息
class CheckPersonEligibleForSelectiveService implements CheckPerson {public boolean test(Person p) {return p.gender Person.Sex.MALE p.getAge() 18 p.getAge() 25;}
}在调用的时候只需要把这个规则作为参数传入即可
printPersons(roster, new CheckPersonEligibleForSelectiveService());上述示例还可以转换成匿名类的写法如下
printPersons(roster,new CheckPerson() {public boolean test(Person p) {return p.getGender() Person.Sex.MALE p.getAge() 18 p.getAge() 25;}}
);也可以转换成 Java SE 8 中新增的 Lambda 表达式的写法如下
printPersons(roster,(Person p) - p.getGender() Person.Sex.MALE p.getAge() 18 p.getAge() 25
);由于 CheckPerson 这个接口只有一个方法所以这又是一个函数式接口在我们这个例子的场景下我们可以用 PredicateT 来替换 CheckPerson 接口。因为 PredicateT 接口定义就是
interface PredicateT {boolean test(T t);
}使用 PredicateT 以后代码如下
public static void printPersonsWithPredicate(ListPerson roster, PredicatePerson tester) {for (Person p : roster) {if (tester.test(p)) {p.printPerson();}}
}最后代码又可以简化成如下形式
printPersonsWithPredicate(roster,p - p.getGender() Person.Sex.MALE p.getAge() 18 p.getAge() 25
);printPersonsWithPredicate 方法重构成如下形式
public static void printPersonsWithPredicate(ListPerson roster, PredicatePerson tester) {for (Person p : roster) {if (tester.test(p)) {p.printPerson();}}
}还可以做进一步的优化我们可以指定一个不同的动作来执行那些满足条件的 Person 实例而不是直接调用 printPerson 方法。可以用一个 Lambda 表达式来指定这个动作。这里引入了 Consumer 接口。
public static void processPersons(ListPerson roster,PredicatePerson tester,ConsumerPerson block) {for (Person p : roster) {if (tester.test(p)) {block.accept(p);}}
}这样我们就把打印行为也给分离出来了主流程调用的代码可以进一步简化成
processPersons(roster,p - p.getGender() Person.Sex.MALE p.getAge() 18 p.getAge() 25,p - p.printPerson()
);经过上述重构和优化我们可以定义不同条件下的不同行为
例如
public static void processPersonsWithFunction(ListPerson roster,PredicatePerson tester,FunctionPerson, String mapper,ConsumerString block) {for (Person p : roster) {if (tester.test(p)) {String data mapper.apply(p);block.accept(data);}}
}再如
processPersonsWithFunction(roster,p - p.getGender() Person.Sex.MALE p.getAge() 18 p.getAge() 25,p - p.getEmailAddress(),email - System.out.println(email)
);可以做进一步的泛化:
public static X, Y void processElements(IterableX source,PredicateX tester,Function X, Y mapper,ConsumerY block) {for (X p : source) {if (tester.test(p)) {Y data mapper.apply(p);block.accept(data);}}
}针对的场景就是一个集合经过某些过滤取出满足条件的数据然后把这个数据进行加工例如
processElements(roster,p - p.getGender() Person.Sex.MALE p.getAge() 18 p.getAge() 25,p - p.getEmailAddress(),email - System.out.println(email)
);最后使用 Stream 让整个代码变的简洁优雅
roster.stream().filter(p - p.getGender() Person.Sex.MALE p.getAge() 18 p.getAge() 25).map(p - p.getEmailAddress()).forEach(email - System.out.println(email));除了可以使用 Lambda 表达式创建匿名方法我们还可以使用方法引用来替代 lambda 表达式这样可读性会好一些例如
public class Person {// ...public static int compareByAge(Person a, Person b) {return a.birthday.compareTo(b.birthday);}// ...
}按年龄排序我们既可以这样写
// 定义比较器
class PersonAgeComparator implements ComparatorPerson {public int compare(Person a, Person b) {return a.getBirthday().compareTo(b.getBirthday());}
}
Arrays.sort(rosterAsArray, new PersonAgeComparator());也可以使用 lambda 表达式
Arrays.sort(rosterAsArray,(Person a, Person b) - {return a.getBirthday().compareTo(b.getBirthday());}
);由于 Person 类中已经存在一个比较方法我们可以通过方法引用来替代 Lambda 表达式
Arrays.sort(rosterAsArray,(a, b) - Person.compareByAge(a, b)
);这个 compareByAge 的参数列表和 ComparatorPerson.compare 方法的参数一致可以简写成
Arrays.sort(rosterAsArray, Person::compareByAge);方法引用有如下几种类型
类型语法示例静态方法*ContainingClass*::*staticMethodName*Person::compareByAge MethodReferencesExamples::appendStrings实例方法*containingObject*::*instanceMethodName*myComparisonProvider::compareByName myApp::appendStrings2对一个特定类型的任意对象的实例方法的引用*ContainingType*::*methodName*String::compareToIgnoreCase String::concat构造方法*ClassName*::newHashSet::new
以下是示例
import java.util.function.BiFunction;/*** since 1.8*/
public class MethodReferencesExamples {public static T T mergeThings(T a, T b, BiFunctionT, T, T merger) {return merger.apply(a, b);}public static String appendStrings(String a, String b) {return a b;}public String appendStrings2(String a, String b) {return a b;}public static void main(String[] args) {MethodReferencesExamples myApp new MethodReferencesExamples();// 使用 lambda 表达式System.out.println(MethodReferencesExamples.mergeThings(Hello , World!, (a, b) - a b));// 静态方法System.out.println(MethodReferencesExamples.mergeThings(Hello , World!, MethodReferencesExamples::appendStrings));// 实例方法System.out.println(MethodReferencesExamples.mergeThings(Hello , World!, myApp::appendStrings2));// 对一个特定类型的任意对象的实例方法的引用System.out.println(MethodReferencesExamples.mergeThings(Hello , World!, String::concat));}
}接口支持默认方法和静态方法
直接看示例
import java.time.*;public interface TimeClient {void setTime(int hour, int minute, int second);void setDate(int day, int month, int year);void setDateAndTime(int day, int month, int year,int hour, int minute, int second);LocalDateTime getLocalDateTime();
}package defaultmethods;import java.time.*;
import java.lang.*;
import java.util.*;public class SimpleTimeClient implements TimeClient {private LocalDateTime dateAndTime;public SimpleTimeClient() {dateAndTime LocalDateTime.now();}public void setTime(int hour, int minute, int second) {LocalDate currentDate LocalDate.from(dateAndTime);LocalTime timeToSet LocalTime.of(hour, minute, second);dateAndTime LocalDateTime.of(currentDate, timeToSet);}public void setDate(int day, int month, int year) {LocalDate dateToSet LocalDate.of(day, month, year);LocalTime currentTime LocalTime.from(dateAndTime);dateAndTime LocalDateTime.of(dateToSet, currentTime);}public void setDateAndTime(int day, int month, int year,int hour, int minute, int second) {LocalDate dateToSet LocalDate.of(day, month, year);LocalTime timeToSet LocalTime.of(hour, minute, second); dateAndTime LocalDateTime.of(dateToSet, timeToSet);}public LocalDateTime getLocalDateTime() {return dateAndTime;}public String toString() {return dateAndTime.toString();}public static void main(String... args) {TimeClient myTimeClient new SimpleTimeClient();System.out.println(myTimeClient.toString());}
}上述代码中如果要在接口中添加一个方法那么所有实现这个接口的客户端都要重新实现这个方法非常麻烦。
public interface TimeClient {void setTime(int hour, int minute, int second);void setDate(int day, int month, int year);void setDateAndTime(int day, int month, int year,int hour, int minute, int second);LocalDateTime getLocalDateTime();// 新增一个方法所有的子类都要实现这个方法ZonedDateTime getZonedDateTime(String zoneString);
}在 Java SE 8 中接口可以支持默认方法即我们可以指定接口的某个方法的默认实现这样的话子类就不需要重写这个方法可以使用接口的默认实现同时Java SE 8 中接口也支持静态方法。
package defaultmethods;import java.time.*;public interface TimeClient {void setTime(int hour, int minute, int second);void setDate(int day, int month, int year);void setDateAndTime(int day, int month, int year,int hour, int minute, int second);LocalDateTime getLocalDateTime();// 接口也支持静态方法实现static ZoneId getZoneId (String zoneString) {try {return ZoneId.of(zoneString);} catch (DateTimeException e) {System.err.println(Invalid time zone: zoneString ; using default time zone instead.);return ZoneId.systemDefault();}}// 默认实现子类无须重写 default ZonedDateTime getZonedDateTime(String zoneString) {return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));}
}通过上述改造所有子类都具备了接口默认方法的能力子类可以直接调用接口的默认实现。
package defaultmethods;import java.time.*;
import java.lang.*;
import java.util.*;public class TestSimpleTimeClient {public static void main(String... args) {// NOTESimpleTimeClient无须做任何改动TimeClient myTimeClient new SimpleTimeClient();System.out.println(Current time: myTimeClient.toString());// 调用默认实现System.out.println(Time in California: myTimeClient.getZonedDateTime(Blah blah).toString());}
}当然默认实现也可以修改子类重写默认实现就可以了。
此外接口支持静态方法实现上述接口中的静态方法可以直接使用
TimeClient.getZoneId(zoneID);接口可以支持静态方法这一特性扩展了接口的功能但是对于实现这个接口的子类没有影响比如 Comparator 类中的 comparing 方法示例
myDeck.sort(Comparator.comparing(Card::getRank).thenComparing(Comparator.comparing(Card::getSuit)));一些增强的 API
新增的包
java.util.function
java.util.stream调整的包
包新增类有调整的类java.ioUncheckedIOExceptionBufferedReaderjava.langnot applicableAutoCloseable ThreadLocal String Iterable CharSequence Boolean Integer Long Float Doublejava.nio.filenot applicableFilesjava.utilPrimitiveIterator Spliterator DoubleSummaryStatistics IntSummaryStatistics LongSummaryStatistics Optional OptionalDouble OptionalInt OptionalLong Spliterators SplittableRandom StringJoinerArrays BitSet Collection Comparator Iterator List Map Map.Entry LinkedHashMap Random TreeMapjava.util.concurrentnot applicableThreadLocalRandomjava.util.jarnot applicableJarFilejava.util.zipnot applicableZipFilejava.util.loggingnot applicableLoggerjava.util.regexnot applicablePattern
具体可参考New and Enhanced APIs That Take Advantage of Lambda Expressions and Streams in Java SE 8
List 转 Map
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;// list转map
public class List2Map {/*** key name, value number*/static void sample1() {ListCar list new ArrayList();list.add(new Car(A, 1));list.add(new Car(B, 2));list.add(new Car(C, 3));// to map,key car name,value ,car numberMapString, Integer carMap list.stream().collect(Collectors.toMap(Car::getName, Car::getNum));System.out.println(carMap);}/*** key name value object*/static void sample2() {ListCar list new ArrayList();list.add(new Car(A, 1));list.add(new Car(B, 2));list.add(new Car(C, 3));MapString, Car carMap list.stream().collect(Collectors.toMap(Car::getName, car - car));System.out.println(carMap);}/*** 处理重复数据 包含重复数据的时候只保留最新的一条*/static void sample3() {ListCar list new ArrayList(4);list.add(new Car(A, 1));list.add(new Car(A, 2));list.add(new Car(B, 2));list.add(new Car(C, 3));MapString, Integer carMap list.stream().collect(Collectors.toMap(Car::getName, Car::getNum, (oldData, newData) - newData));System.out.println(carMap);}/*** 重复数据,包含重复数据的时候只保留最新的一条,并把结果保存到ConcurrentHashMap*/static void sample4() {ListCar list new ArrayList();list.add(new Car(A, 1));list.add(new Car(A, 2));list.add(new Car(B, 2));list.add(new Car(C, 3));MapString, Integer carMap list.stream().collect(Collectors.toMap(Car::getName, Car::getNum, (oldData, newData) - newData, ConcurrentHashMap::new));System.out.println(carMap.getClass());}
}
class Car {private String name;private Integer num;// 省略get/set和构造方法
}
forEach 遍历
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Stream;/*** for each遍历方式* since 1.8*/
public class ForEachTest {// jdk8之前常规遍历操作static void normForEach() {ListString list Arrays.asList(a, b, c);for (String item : list) {System.out.println(item);}}static void newForEach() {ListString list Arrays.asList(a, b, c);list.forEach(System.out::println);list.forEach(s - {System.out.println(新的遍历方式);System.out.println(s);});}// Map的遍历 jdk1.8之前static void mapNormForEach() {MapInteger, String map new HashMap(3);map.put(1, a);map.put(2, b);map.put(3, c);for (Map.EntryInteger, String entry : map.entrySet()) {System.out.println(entry.getKey() :\t entry.getValue());}}//jdk1.8新的Map遍历方法static void mapNewForEach() {MapInteger, String map new HashMap(3);map.put(1, a);map.put(2, b);map.put(3, c);map.forEach((k, v) - {System.out.println(k);System.out.println(v);});}// jdk1.8新增数组的遍历方法static void arrayForEach() {String[] array {a, b, c};Arrays.stream(array).forEach(System.out::println);}//不保证有序static void parallelForEach() {StreamString stream Stream.of(ab, bc, cd);stream.parallel().forEach(System.out::println);}// 可以保证有序static void parallelForEachOrder() {StreamString stream Stream.of(ab, bc, cd);stream.parallel().forEachOrdered(System.out::println);}// 使用consumerstatic void forEachUseConsumer() {StreamString s Stream.of(ab, bc);ListString l Arrays.asList(ab, cd);ConsumerString consumer s1 - {System.out.println(s1.toUpperCase());};s.forEach(consumer);l.forEach(consumer);}
}Optional 用于优雅判断空。 import java.util.Optional;/*** Optional用法* since 1.8*/
public class OptionalTest {static void handleNull() {//String s null;//OptionalString s1 Optional.of(s);// System.out.println(s1.isPresent());OptionalString hello Optional.of(hello);OptionalObject empty Optional.empty();OptionalObject nullObj Optional.ofNullable(null);System.out.println(hello.isPresent());System.out.println(empty.isPresent());System.out.println(nullObj.isPresent());}static void emptyGetException() {try {OptionalString hello Optional.of(hello);System.out.println(hello.get());OptionalObject empty Optional.empty();System.out.println(empty.get());} catch (Exception e) {e.printStackTrace();}}static void orElseException() {try {OptionalString emptyOptional Optional.empty();String value emptyOptional.orElseThrow(() - new Exception(发现空值));System.out.println(value);} catch (Exception e) {e.printStackTrace();}}static void orElseGet() {OptionalObject empty Optional.empty();Object o empty.orElseGet(() - default);System.out.println(o);Object aDefault empty.orElse(default);System.out.println(aDefault);}static void funcOptional() {OptionalInteger optional123 Optional.of(123);optional123.filter(num - num 123).ifPresent(num - System.out.println(num));OptionalInteger optional456 Optional.of(456);optional456.filter(num - num 123).ifPresent(num - System.out.println(num));// map 转换OptionalInteger optional789 Optional.of(789);optional789.map(String::valueOf).map(String::length).ifPresent(length - System.out.println(length));}
}新的时间处理类
package git.snippets.jdk8;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;import static java.time.temporal.ChronoUnit.DAYS;
/*** since 1.8*/
//参考 https://www.wdbyte.com/2019/10/jdk/jdk8-time/
public class LocalDateTest {static void errorDate() {// 不合法的日期LocalDate invalidDate LocalDate.of(2021, 2, 29);invalidDate.minusYears(1);System.out.println(invalidDate.minusYears(1));}static void until() {LocalDate birthday LocalDate.of(1989, 9, 27);System.out.println(birthday.until(LocalDate.now(), DAYS));}// 有时区的精确时间static void zone() {ZonedDateTime nowZone LocalDateTime.now().atZone(ZoneId.systemDefault());System.out.println(当前精确时间有时区 nowZone);System.out.println(当前精确时间有时区 nowZone.getYear() - nowZone.getMonthValue() - nowZone.getDayOfMonth() nowZone.getHour() - nowZone.getMinute() - nowZone.getSecond());}static void createTime() {LocalDateTime ofTime LocalDateTime.of(2019, 10, 1, 8, 8, 8);System.out.println(当前精确时间 ofTime);LocalDate localDate LocalDate.of(2019, 10, 01);System.out.println(当前日期 localDate);LocalTime localTime LocalTime.of(12, 01, 01);System.out.println(当天时间 localTime);}
}stream
数据源获取方法数据处理方法结果处理方法Collection.stream ()从集合获取流 Collection.parallelStream ()从集合获取并行流。 Arrays.stream (T array) or Stream.of ()从数组获取流。 BufferedReader.lines ()从输入流中获取流。 IntStream.of ()从静态方法中获取流。 Stream.generate ()自己生成流map (mapToInt, flatMap等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unorderedforEach、forEachOrdered、toArray、reduce、collect、min、max、count、anyMatch、allMatch、noneMatch、findFirst、findAny、iterator
先看一个最简单的示例
private static void generateHandle() {// 不使用流操作ListString names Arrays.asList(A, BBBB, CCCC, D);// 筛选出长度为4的名字ListString subList new ArrayList();for (String name : names) {if (name.length() 4) {subList.add(name);}}// 把值用逗号分隔StringBuilder sbNames new StringBuilder();for (int i 0; i subList.size() - 1; i) {sbNames.append(subList.get(i));sbNames.append(, );}// 去掉最后一个逗号if (subList.size() 1) {sbNames.append(subList.get(subList.size() - 1));}System.out.println(sbNames);}用stream来做就简洁很多
private static void useStream() {ListString names Arrays.asList(A, BBBB, CCCC, D);String nameString names.stream().filter(num - num.length() 4).collect(Collectors.joining(, ));System.out.println(nameString);}package git.snippets.jdk8;import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;/*** stream使用* 数据源source - 数据处理 / 转换intermedia - 结果处理terminal * author a hrefmailto:410486047qq.comGrey/a* date 2021/11/21* since 1.8*/
public class StreamTest {static void demo1() {ListString nameList Arrays.asList(A, B, AASDSD, ABCD);nameList.stream().filter(name - name.length() 4).map(name - This is name).forEach(System.out::println);}static void mathTest() {ListInteger list Arrays.asList(1, 2, 3, 4, 5, 6);IntSummaryStatistics stats list.stream().mapToInt(x - x).summaryStatistics();System.out.println(最小值 stats.getMin());System.out.println(最大值 stats.getMax());System.out.println(个数 stats.getCount());System.out.println(和 stats.getSum());System.out.println(平均数 stats.getAverage());}static void groupByTest() {ListInteger ageList Arrays.asList(11, 22, 13, 14, 25, 26);MapString, ListInteger groupMap ageList.stream().collect(Collectors.groupingBy(age - String.valueOf(age / 10)));groupMap.forEach((k, v) - {System.out.println(年龄 k 0多岁的有 v);});}static void partitioningByTest() {ListInteger ageList Arrays.asList(11, 22, 13, 14, 25, 26);MapBoolean, ListInteger ageMap ageList.stream().collect(Collectors.partitioningBy(age - age 18));System.out.println(未成年人 ageMap.get(false));System.out.println(成年人 ageMap.get(true));}static void generateTest() {// 生成自己的随机数流Random random new Random();StreamInteger generateRandom Stream.generate(random::nextInt);generateRandom.limit(5).forEach(System.out::println);// 生成自己的 UUID 流StreamUUID generate Stream.generate(UUID::randomUUID);generate.limit(5).forEach(System.out::println);}
}函数式接口 有且仅有一个抽象方法的接口就是函数式接口。可以通过FunctionalInterface标识对于只有单个抽象方法(single abstract method)的接口需要这种接口的对象时就可以提供Lambda表达式。 最简单的一个函数式接口示例
FunctionalInterface
public interface FunctionDemo {void say(String name, int age);default void hi(String name, int age) {say(name, age);}
}
package git.snippets.jdk8;public class FunctionInterfaceDemo {public static void main(String[] args) {function0();}// 最简单的函数式接口static void function0() {FunctionDemo demo (name, age) - System.out.println(我叫 name 我今年 age 岁);demo.say(zhangsan, 20);demo.hi(zhanshang, 20);}
}Predicate 可以过滤出满足条件的特定元素 示例
package git.snippets.jdk8;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;/*** author a hrefmailto:410486047qq.comGrey/a* date 2021/11/24* since 1.8*/
public class PredicateTest {public static void main(String[] args) {ListInteger numberList Arrays.asList(3, 4, 5, 6, 7, 8, 9, 10);PredicateInteger lessThan5 number - number 5;PredicateInteger greaterThan9 number - number 9;// 小于等于 5System.out.println(filter(numberList, lessThan5));// 大于 5System.out.println(filter(numberList, lessThan5.negate()));// 小于等于 5 或者大于等于 9System.out.println(filter(numberList, lessThan5.or(greaterThan9)));// ! (小于等于 5 AND 大于等于 9)System.out.println(filter(numberList, lessThan5.and(greaterThan9).negate()));}// 过滤出满足条件条件可以自定义的特定集合元素private static T ListT filter(ListT numberList, PredicateT p) {ListT result new ArrayList();for (T t : numberList) {if (p.test(t)) {result.add(t);}}return result;}
}Consumer
Consumer有如下类型
类型作用BiConsumer传入两个任意类型参数无返回值DoubleConsumer传入一个 double 参数无返回值IntConsumer传入一个 int 参数无返回值LongConsumer传入一个 long 参数无返回值ObjDoubleConsumer传入一个任意类型参数一个 double 参数无返回值ObjIntConsumer传入一个任意类型参数一个 int 参数无返回值ObjLongConsumer传入一个任意类型参数一个 long 参数无返回值
示例代码
package git.snippets.jdk8;import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.ObjIntConsumer;/*** Consumer测试* p* BiConsumer 传入两个任意类型参数无返回值* p* DoubleConsumer 传入一个 double 参数无返回值* p* IntConsumer 传入一个 int 参数无返回值* p* LongConsumer 传入一个 long 参数无返回值* p* ObjDoubleConsumer 传入一个任意类型参数一个 double 参数无返回值* p* ObjIntConsumer 传入一个任意类型参数一个 int 参数无返回值* p* ObjLongConsumer 传入一个任意类型参数一个 long 参数无返回值** author a hrefmailto:410486047qq.comGrey/a* date 2021/11/26* since 1.8*/
public class ConsumerTest {public static void main(String[] args) {t1();t2();t3();t4();}// 多个Consumer结合使用static void t1() {ConsumerString c System.out::println;ConsumerString len s - System.out.print(s.length());len.andThen(c).accept(hello);}private static void t4() {ListString list Arrays.asList(ab, abcd);// 某个字符串串的长度大于给定的value值就打印list.forEach(s - {if (s.length() 3) {System.out.println(s);}});}// 打印map中的value满足条件的key值private static void t3() {MapString, Integer map new HashMap();map.put(zhangshang, 17);map.put(list, 21);map.put(wangwu, 18);BiConsumerString, Integer consumer (s, i) - {// value大于18的记录打印其value值if (i 18) {System.out.println(s);}};map.forEach(consumer);}private static void t2() {ListString list Arrays.asList(ab, cd);// 打印字符串list.forEach(System.out::println);// 打印每个字符串的长度list.forEach(s - System.out.println(s.length()));}
}Supplier Supplier是一个功能接口代表结果的提供者。Supplier的功能方法是get()。一个Supplier可以通过lambda表达式、方法引用或默认构造函数来实例化。 示例代码如下 private static void s1() throws InterruptedException {// 定义一个Supplier可以生成区间为[0,10)的随机数SupplierInteger supplier () - new Random().nextInt(10);System.out.println(supplier.get());System.out.println(supplier.get());// 获取当前时间SupplierLocalDateTime s2 LocalDateTime::now;System.out.println(s2.get());Thread.sleep(1000);System.out.println(s2.get());}此外使用Supplier还可以优雅实现工厂模式见
package git.snippets.jdk8;import java.time.LocalDateTime;
import java.util.Random;
import java.util.UUID;
import java.util.function.Supplier;/*** Supplier使用** author a hrefmailto:410486047qq.comGrey/a* date 2021/11/27* since*/
public class SupplierTest {public static void main(String[] args) throws InterruptedException {System.out.println(factory(() - new Sharp(abc)));}// supplier实现工厂模式static Sharp factory(Supplier? extends Sharp supplier) {Sharp sharp supplier.get();sharp.name sharp.name UUID.randomUUID();return sharp;}
}class Sharp {String name;Sharp(String name) {this.name name;}Overridepublic String toString() {return Sharp{ name name \ };}
}UnaryOperator UnaryOperator接受一个参数并返回与其输入参数相同类型的结果。 示例代码
package git.snippets.jdk8;import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;/*** UnaryOperator使用** author a hrefmailto:410486047qq.comGrey/a* date 2021/11/28* see UnaryOperator* since 1.8*/
public class UnaryOperatorTest {public static void main(String[] args) {ListString list Arrays.asList(abcddd, 12233243);// 将List元素先转大写然后截取前3位最后打印出来mapAndConsumer(list, System.out::println, String::toUpperCase, s - s.substring(0, 3));unaryOperator2();}// 接收多个UnaryOperator对List元素进行处理得到的结果执行传入consumer中public static T void mapAndConsumer(ListT list, ConsumerT consumer, UnaryOperatorT... unaryOperator) {for (T t : list) {for (UnaryOperatorT operator : unaryOperator) {t operator.apply(t);}consumer.accept(t);}}static void unaryOperator2() {FunctionString, String upperFun1 String::toUpperCase;UnaryOperatorString upperFun2 String::toUpperCase;ListString list Arrays.asList(abc, efg);// Function.identity() 和 UnaryOperator.identity()都不对结果进行任何操作MapString, String map1 list.stream().collect(Collectors.toMap(upperFun1, Function.identity()));MapString, String map2 list.stream().collect(Collectors.toMap(upperFun2, UnaryOperator.identity()));MapString, String map3 list.stream().collect(Collectors.toMap(upperFun2, t - t));System.out.println(map1);System.out.println(map2);System.out.println(map3);}
}惰性计算
package git.snippets.jdk8;import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;/*** 惰性计算** author a hrefmailto:410486047qq.comGrey/a* date 2021/11/23* since 1.8*/
public class LazyTest {public static void main(String[] args) {lazyTest();}private static void lazyTest() {ListInteger numberLIst Arrays.asList(1, 2, 3, 4, 5, 6);// 找出偶数StreamInteger integerStream numberLIst.stream().filter(number - {int temp number % 2;if (temp 0) {System.out.println(number);}return temp 0;});System.out.println(分割线);// 到这里才调用ListInteger collect integerStream.collect(Collectors.toList());}
}如上代码打印的结果是
分割线
2
4
6说明调用filter的过程是在integerStream.collect(Collectors.toList());执行才触发这就是惰性计算。
JUC 包中的 CompletableFuture 其中的anyOf()可以实现“任意个CompletableFuture只要一个成功”allOf()可以实现“所有CompletableFuture都必须成功”这些组合操作可以实现非常复杂的异步流程控制。 用法参考如下代码
package git.snippets.juc;import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;/*** 假设你能够提供一个服务* 这个服务查询各大电商网站同一类产品的价格并汇总展示*/
public class CompletableFutureUsage {public static void main(String[] args) throws ExecutionException, InterruptedException {way1();way2();}public static void way1() {long start System.currentTimeMillis();System.out.println(p1 priceOfJD());System.out.println(p2 priceOfTB());System.out.println(p3 priceOfTM());long end System.currentTimeMillis();System.out.println(串行执行耗时(ms): (end - start));}public static void way2() throws ExecutionException, InterruptedException {long start System.currentTimeMillis();CompletableFutureDouble p1 CompletableFuture.supplyAsync(() - priceOfJD());CompletableFutureDouble p2 CompletableFuture.supplyAsync(() - priceOfTB());CompletableFutureDouble p3 CompletableFuture.supplyAsync(() - priceOfTM());CompletableFuture.allOf(p1, p2, p3).join();System.out.println(p1 p1.get());System.out.println(p2 p2.get());System.out.println(p3 p3.get());long end System.currentTimeMillis();System.out.println(使用CompletableFuture并行执行耗时(ms): (end - start));}private static double priceOfTM() {delay();return 1.00;}private static double priceOfTB() {delay();return 2.00;}private static double priceOfJD() {delay();return 3.00;}/*private static double priceOfAmazon() {delay();throw new RuntimeException(product not exist!);}*/private static void delay() {int time new Random().nextInt(500);try {TimeUnit.MILLISECONDS.sleep(time);} catch (InterruptedException e) {e.printStackTrace();}// System.out.printf(After %s sleep!\n, time);}
}
JUC 包中的 WorkStealingPool 每个线程都有单独的队列每个线程队列执行完毕后就会去其他的线程队列里面拿过来执行, 底层是ForkJoinPool会自动启动cpu核数个线程去执行任务 示例代码
package git.snippets.juc;import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;public class WorkStealingPoolUsage {public static void main(String[] args) throws IOException {int core Runtime.getRuntime().availableProcessors();// 会自动启动cpu核数个线程去执行任务 ,其中第一个是1s执行完毕,其余都是2s执行完毕,// 有一个任务会进行等待,当第一个执行完毕后,会再次偷取最后一个任务执行ExecutorService service Executors.newWorkStealingPool();service.execute(new R(1000));for (int i 0; i core; i) {service.execute(new R(2000));}//由于产生的是精灵线程守护线程、后台线程主线程不阻塞的话看不到输出System.in.read();}static class R implements Runnable {int time;R(int t) {this.time t;}Overridepublic void run() {try {TimeUnit.MILLISECONDS.sleep(time);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(time Thread.currentThread().getName());}}
}
更多
Java SE 7及以后各版本新增特性持续更新中…
参考资料
Java 新特性教程
Java Language Updates
Enhancements in Java SE 8
New and Enhanced APIs That Take Advantage of Lambda Expressions and Streams in Java SE 8
Java多线程学习笔记
Spring in Action, 5th
Java核心技术·卷 I原书第11版
Java核心技术·卷 II原书第11版