lambda表达式

  1. Thread t = new Thread(new Runnable() {
  2. public void run(){
  3. System.out.println("Hello world");
  4. }
  5. });
  6. //用lamba表达式表示
  7. Thread t = new Thread(() -> System.out.println("Hello world"));

Lambda表达式允许直接以内联的形式为函数式接口的抽象,方法提供实现,并把整个表达式作为函数式接口的实例
简单来说就是将表达式作为方法的实现,并内联直接实例化
1、行为参数化:需要一个接收BufferedReader并返回String的Lambda
2、函数式接口传递行为

  1. @FunctionalInterface
  2. public interface BufferedReaderProcessor {
  3. String process(BufferedReader b) throws IOException;
  4. }
  5. public static String processFile(BufferedReaderProcessor p) throwsIOException {
  6. }

3、执行行为

  1. public static String processFile(BufferedReaderProcessor p) throwsIOException {
  2. try (BufferedReader br =new BufferedReader(new FileReader("data.txt"))) {
  3. return p.process(br);
  4. }
  5. }

4、传递lambda
String result = processFile((BufferedReader br) ->br.readLine() + br.readLine());

  1. int a = 10;
  2. // Lambda的类型取决于它的上下文
  3. Runnable r1 = () -> {
  4. int a = 2; // lambda表达式不能屏蔽类变量,编译出错
  5. };
  6. // 匿名类的类型是在初始化时确定的
  7. Runnable r2 = new Runnable(){
  8. public void run(){
  9. int a = 2; // 编译正常
  10. }
  11. };

采用函数接口(默认)
重构方式

  1. // 有条件的延迟执行
  2. public void log(Level level, Supplier<String> msgSupplier){
  3. if(logger.isLoggable(level)){
  4. log(level, msgSupplier.get());
  5. }
  6. }
  7. // 环绕执行
  8. String oneLine = processFile((BufferedReader b) -> b.readLine());
  9. String twoLines = processFile((BufferedReader b) -> b.readLine() + b.readLine());
  10. public static String processFile(BufferedReaderProcessor p) throws IOException {
  11. try(BufferedReader br = new BufferedReader(new FileReader("java8inaction/chap8/data.txt"))){
  12. return p.process(br);
  13. }
  14. }
  15. public interface BufferedReaderProcessor{
  16. String process(BufferedReader b) throws IOException;
  17. }

函数式接口

1、Predicate返回boolean函数式接口,如filter

  1. // 定义接收String对象的函数式接口
  2. @FunctionalInterface
  3. public interface Predicate<T>{
  4. boolean test(T t);
  5. }
  6. public static <T> List<T> filter(List<T> list, Predicate<T> p) {
  7. List<T> results = new ArrayList<>();
  8. for(T s: list){
  9. if(p.test(s)){
  10. results.add(s);
  11. }
  12. }
  13. return results;
  14. }
  15. // 创建boolean函数式接口Predicate,过滤list中为空的对象
  16. Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
  17. List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);

2、Consumer访问类型T的对象,并执行其操作,如foreach

  1. @FunctionalInterface
  2. public interface Consumer<T>{
  3. void accept(T t);
  4. }
  5. public static <T> void forEach(List<T> list, Consumer<T> c){
  6. for(T i: list){
  7. c.accept(i);
  8. }
  9. }
  10. forEach( Arrays.asList(1,2,3,4,5), (Integer i) -> System.out.println(i) )

3、Function 接受一个泛型T的对象,并返回一个泛型R的对象将输入对象的信息映射到输出,如map

  1. @FunctionalInterface
  2. public interface Function<T, R>{
  3. R apply(T t);
  4. }
  5. public static <T, R> List<R> map(List<T> list, Function<T, R> f) {
  6. List<R> result = new ArrayList<>();
  7. for(T s: list){
  8. result.add(f.apply(s));
  9. }
  10. return result;
  11. }
  12. // [7, 2, 6]
  13. List<Integer> l = map(Arrays.asList("lambdas","in","action"), (String s) -> s.length());

4、针对专门的输入参数类型的函数式接口的名称都要加上对应的原始类型前缀

  1. public interface IntPredicate{
  2. boolean test(int t);
  3. }
  4. IntPredicate evenNumbers = (int i) -> i % 2 == 0;
  5. evenNumbers.test(1000); // true 无装箱
  6. Predicate<Integer> oddNumbers = (Integer i) -> i % 2 == 1;
  7. oddNumbers.test(1000); // false装箱
Predicate T->boolean IntPredicate,LongPredicate, DoublePredicate
Consumer T->void IntConsumer,LongConsumer, DoubleConsumer
Function T->R IntFunction,
IntToDoubleFunction,
IntToLongFunction,
LongFunction,
LongToDoubleFunction,
LongToIntFunction,
DoubleFunction,
ToIntFunction,
ToDoubleFunction,
ToLongFunction
Supplier ()->T BooleanSupplier,IntSupplier, LongSupplier,DoubleSupplier
UnaryOperator T->T IntUnaryOperator,
LongUnaryOperator,
DoubleUnaryOperator
BinaryOperator (T,T)->T IntBinaryOperator,
LongBinaryOperator,
DoubleBinaryOperator
BiPredicate (L,R)->boolean
BiConsumer (T,U)->void ObjIntConsumer,
ObjLongConsumer,
ObjDoubleConsumer
BiFunction (T,U)->R ToIntBiFunction,
ToLongBiFunction,
ToDoubleBiFunction

image.png

Optional

读取Optional实例中的变量值

  1. get() // 这些方法中最简单但又最不安全的方法。如果变量存在,它直接返回封装的变量值,否则就抛出一个NoSuchElementException异常
  2. orElse(T other) //在Optional对象不包含值时提供一个默认值。
  3. orElseGet(Supplier<? extends T> other) //Supplier方法只有在Optional对象不含值时才执行调用
  4. orElseThrow(Supplier<? extends X> exceptionSupplier) //Optional对象为空时都会抛出一个异常
  5. ifPresent(Consumer<? super T>) //在变量值存在时执行一个作为参数传入的方法,否则就不进行任何操作。

image.png
image.png

  1. // map.get() 不存在key对应的值
  2. // 对潜在为null的对象进行转换,替换为Optional对象
  3. Optional<Object>value=Optional.ofNullable(map.get("key"));

基础类型的Optional对象OptionalInt、OptionalLong以及OptionalDouble
不支持map、flatMap、filter方法,也不能作为这些方法的传参

异常

任何函数式接口都不允许抛出受检异常(checked exception)。如果你需要Lambda表达式来抛出异常,有两种办法

  1. // 1、定义一个自己的函数式接口,并声明受检异常
  2. @FunctionalInterface
  3. public interface BufferedReaderProcessor {
  4. String process(BufferedReader b) throws IOException;
  5. }
  6. // 2、把Lambda包在一个try/catch块中。
  7. Function<BufferedReader, String> f = (BufferedReader b) -> {
  8. try {
  9. return b.readLine();
  10. }catch(IOException e) {
  11. throw new RuntimeException(e);
  12. }
  13. };

类型检查

test方法描述了一个函数描述符,它可以接受一个Apple,并返回一个boolean
image.png

方法引用

构造函数引用

ClassName::new 适合Supplier的签名() -> ClassName

  1. //构造函数引用指向默认的Apple()构造函数
  2. Supplier<Apple> c1 = Apple::new;
  3. Apple a1 = c1.get();
  4. Supplier<Apple> c1 = () -> new Apple();
  5. Apple a1 = c1.get();
  6. //指向Apple(Integer weight)的构造函数引用
  7. Function<Integer, Apple> c2 = Apple::new;
  8. Apple a2 = c2.apply(110);
  9. //指向Apple(String color,Integer weight)的构造函数引用
  10. BiFunction<String, Integer, Apple> c3 = Apple::new;
  11. Apple c3 = c3.apply("green", 110);

排序方法

  1. //传递Comparator对象
  2. public class AppleComparator implements Comparator<Apple> {
  3. public int compare(Apple a1, Apple a2){
  4. return a1.getWeight().compareTo(a2.getWeight());
  5. }
  6. }
  7. inventory.sort(new AppleComparator());
  8. //使用匿名类
  9. inventory.sort(new Comparator<Apple>() {
  10. public int compare(Apple a1, Apple a2){
  11. return a1.getWeight().compareTo(a2.getWeight());
  12. }
  13. });
  14. // lambda表达式
  15. inventory.sort((Apple a1, Apple a2)-> a1.getWeight().compareTo(a2.getWeight()));
  16. inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight()));
  17. //Comparator具有一个叫作comparing的静态辅助方法,
  18. //它可以接受一个Function来提取Comparable键值,并生成一个Comparator对象
  19. Comparator<Apple> c = Comparator.comparing((Apple a) -> a.getWeight());
  20. import static java.util.Comparator.comparing;
  21. inventory.sort(comparing((a) -> a.getWeight()));
  22. //方法引用
  23. inventory.sort(comparing(Apple::getWeight));
  24. inventory.sort(comparing(Apple::getWeight)
  25. .reversed() //反序
  26. .thenComparing(Apple::getCountry)); //排序先后
  27. Predicate<Apple> redAndHeavyAppleOrGreen = redApple.and(a -> a.getWeight() > 150) // and谓词
  28. .or(a -> "green".equals(a.getColor()) // or谓词
  29. .negate()); //非

Function接口

提供andThen和compose两个默认方法,返回Function的一个实例

  1. Function<Integer, Integer> f = x -> x + 1;
  2. Function<Integer, Integer> g = x -> x * 2;
  3. Function<Integer, Integer> h = f.andThen(g); //g(f(x))
  4. int result = h.apply(1); // 4
  5. Function<Integer, Integer> h = f.compose(g); // f(g(x))
  6. int result = h.apply(1); // 3

静态辅助方法

  1. // 方法引用增强可读性
  2. Map<CaloricLevel, List<Dish>> dishesByCaloricLevel = menu.stream().collect(groupingBy(Dish::getCaloricLevel));
  3. public class Dish{
  4. public CaloricLevel getCaloricLevel(){
  5. if (this.getCalories() <= 400) return CaloricLevel.DIET;
  6. else if (this.getCalories() <= 700) return CaloricLevel.NORMAL;
  7. else return CaloricLevel.FAT;
  8. }
  9. }
  10. // 静态辅助方法:
  11. inventory.sort(comparing(Apple::getWeight));
  12. int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));

操作方法

分组 Collectors.groupingBy

  1. // 分组统计
  2. Map<String, List<Student>> collect = stuList.stream()
  3. .collect(Collectors.groupingBy(Student::getInstitution));
  4. // 自定义分组类别
  5. public enum CaloricLevel { DIET, NORMAL, FAT }
  6. Map<CaloricLevel, List<Dish>> dishesByCaloricLevel = menu.stream().collect(
  7. groupingBy(dish -> {
  8. if (dish.getCalories() <= 400) return CaloricLevel.DIET;
  9. else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
  10. else return CaloricLevel.FAT;
  11. } ));
  12. //多级分组(多个类别)
  13. Map<Dish.Type, Map<CaloricLevel, List<Dish>>> dishesByTypeCaloricLevel = menu.stream().collect(
  14. groupingBy(Dish::getType, //默认类型条件
  15. groupingBy(dish -> { //自定义类型条件(做为外层分组的第二个参数)
  16. if (dish.getCalories() <= 400) return CaloricLevel.DIET;
  17. else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
  18. else return CaloricLevel.FAT;
  19. })
  20. )
  21. );
  22. // 子组收集数据
  23. //groupingBy工厂方法的第二个传递的参数会对分到同一组中的所有流元素执行进一步归约操作
  24. Map<Dish.Type, Long> typesCount = menu.stream()
  25. .collect(groupingBy(Dish::getType, counting())); // 统计子组的数量,作为第二个参数
  26. Map<Dish.Type, Integer> totalCaloriesByType = menu.stream()
  27. .collect(groupingBy(Dish::getType, summingInt(Dish::getCalories))); //对分组的所有流元素进一步进行归约操作
  28. Map<Dish.Type, Dish> mostCaloricByType = menu.stream()
  29. .collect(groupingBy(Dish::getType, collectingAndThen( //collectingAndThen 对收集器的类型进行转换
  30. maxBy(comparingInt(Dish::getCalories)),Optional::get)));
  31. // 分组映射 mapping
  32. Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType = menu.stream()
  33. .collect(groupingBy(Dish::getType, mapping( //第二个分组结果成为分组映射的值
  34. dish -> { if (dish.getCalories() <= 400) return CaloricLevel.DIET;
  35. else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
  36. else return CaloricLevel.FAT; }, toSet() ))); //第一个参数分组,第二个参数结果对象收集
  37. // toSet()可以修改为toCollection(HashSet::new) 保证结果的类型
  38. // 多字段分组
  39. Function<Student, List<Object>> compositeKey = t -> Arrays.<Object>asList(t.age(), wlb.sex());
  40. Map<Object, List<Student>> map = stuList.stream()
  41. .collect(Collectors.groupingBy(compositeKey, Collectors.toList()));
  42. // 分区(分区为true和false两组)
  43. Map<Boolean, List<Dish>> partitionedMenu = menu.stream()
  44. .collect(partitioningBy(Dish::isVegetarian));
  45. List<Dish> vegetarianDishes = menu.stream()
  46. .filter(Dish::isVegetarian).collect(toList());
  47. Map<Boolean, Map<Dish.Type, List<Dish>>> vegetarianDishesByType =
  48. menu.stream().collect(partitioningBy(Dish::isVegetarian, groupingBy(Dish::getType)));
  49. // 分组并取最大
  50. Map<Integer,NurseVitalSignsRec>maxMap=list.parallelStream()
  51. .filter(Objects::nonNull)
  52. .collect(Collectors.groupingBy(NurseVitalSignsRec::getVisitId,
  53. Collectors.collectingAndThen(
  54. Collectors.reducing((t1,t2)->t1.getVisitId()>t2.getVisitId()?t1:t2),Optional::get)
  55. )
  56. );

排序sorted

  1. // 对map的排序
  2. Map<Date,List<NurseVitalSignsRec>> finalMap = newLinkedHashMap<>();
  3. vitalSigns.entrySet().stream()
  4. .sorted(Map.Entry.comparingByKey()).limit(10)
  5. .forEachOrdered(x->finalMap.put(x.getKey(),x.getValue()));
  6. vitalSigns.entrySet().stream()
  7. .sorted(Map.Entry.<Date,List<NurseVitalSignsRec>>comparingByKey().reversed()).limit(10)
  8. .forEachOrdered(x->finalMap.put(x.getKey(),x.getValue()));
  9. //reversed() 正序
  10. // limit(2) 取出前两条数据
  11. // 先倒序后正序
  12. List<Student> collect = list.stream()
  13. .sorted(Comparator.comparing(Student::getNum).reversed()).limit(2)).collect(Collectors.toList());
  14. // 按属性降序排序
  15. list.stream().sorted(Comparator.comparing(Student::getNum, Comparator.reverseOrder()));
  16. // 按属性num降序,再按name属性降序
  17. list.stream().sorted(Comparator.comparing(Student::getNum).thenComparing(Student::getName));

取值/计算

  1. // 最大/最小值
  2. Person maxAgePerson = personList.stream()
  3. .max(Comparator.comparing(Person::getAge)).get();
  4. personList.stream()
  5. .max((o1, o2) -> o1.compareTo(o2));
  6. double max = list.stream()
  7. .mapToDouble(User::getHeight).max().getAsDouble();
  8. Optional<Integer> min = numbers.stream()
  9. .reduce(Integer::min);
  10. //求和
  11. double sum = list.stream()
  12. .mapToDouble(User::getHeight).sum(); //DoubleStream 推荐使用,避免拆箱
  13. int sum = numbers.stream()
  14. .reduce(0, (a, b) -> a + b);
  15. int product = numbers.stream()
  16. .reduce(1, (a, b) -> a * b);
  17. int sum = numbers.stream(). // 集合求和
  18. reduce(0, Integer::sum);
  19. Optional<Integer> sum = numbers.stream()
  20. .reduce((a, b) -> (a + b)); //无初始值,考虑到没有元素相加结果,返回Optional对象
  21. //平均数
  22. double average = list.stream()
  23. .mapToDouble(User::getHeight).average().getAsDouble();
  24. //计数
  25. long howManyDishes = menu.stream()
  26. .collect(Collectors.counting());
  27. long howManyDishes = menu.stream()
  28. .count();
  29. int count = menu.stream()
  30. .map(d -> 1).reduce(0, (a, b) -> a + b); //流中的每个元素都映射为1
  31. //归约/汇总收集
  32. transactions.stream()
  33. .collect(Collectors.maxBy(Comparator.comparingInt(Transaction::getValue)));
  34. transactions.stream() // 遍历流时,把每一个对象映射为累加字段,并累加到累加器
  35. .collect(Collectors.summingInt(Transaction::getValue));
  36. menu.stream() // 平均值
  37. .collect(averagingInt(Dish::getCalories));
  38. IntSummaryStatistics menuStatistics = menu.stream()
  39. .collect(summarizingInt(Dish::getCalories)); // 一次获取总和、平均值、最大值和最小值
  40. int totalCalories = menu.stream()
  41. .collect(reducing(0, Dish::getCalories, (i, j) -> i + j));
  42. String shortMenu = menu.stream().map(Dish::getName)
  43. .collect(reducing( (s1, s2) -> s1 + s2 )).get();
  44. Optional<Dish> mostCalorieDish = menu.stream() // 相加没有初始值,返回Optional对象
  45. .collect(reducing((d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2));
  46. int totalCalories = menu.stream() // 对象求和
  47. .collect(reducing(0, Dish::getCalories, Integer::sum)); // Optional<Integer>

过滤

  1. // 去重
  2. list.stream()
  3. .filter(i -> i % 2 == 0).distinct().forEach(System.out::println);
  4. //截断(limit)
  5. list.stream()
  6. .filter(d -> d.getCalories() > 300).limit(3).collect(toList());
  7. //跳过元素
  8. menu.stream()
  9. .filter(d -> d.getCalories() > 300).skip(2).collect(toList());
  10. // 数值范围:使用IntStream和LongStream的静态方法,range和rangeClosed
  11. IntStream evenNumbers = IntStream.rangeClosed(1, 100); // 1-100
  12. IntStream evenNumbers = IntStream.range(1, 100); // 1-99
  13. // 三元素是否符合条件
  14. // 1-100 三元数(a*a, b*b, a*a+b*b)是否符合勾股数
  15. Stream<double[]> pythagoreanTriples2 = IntStream.rangeClosed(1,100)
  16. .boxed()
  17. .flatMap(a -> IntStream.rangeClosed(a, 100)
  18. .mapToObj(b -> new double[]{a, b, Math.sqrt(a*a + b*b)})
  19. .filter(t -> t[2] % 1 == 0));

映射集合

  1. // 映射
  2. List<String> words = Arrays.asList("Java 8", "Lambdas", "In", "Action");
  3. // getName()返回的是String,map输出流的类型为Stream<String>,并且每个String元素可以使用String的方法/可以对元素操作
  4. List<Integer> wordLengths = words.stream()
  5. .map(String::length).collect(toList());
  6. String[] arrayOfWords = {"Goodbye", "World"};
  7. Stream<String> streamOfwords = Arrays.stream(arrayOfWords); // 接收数组并转为字符流
  8. words.stream()
  9. .map(word -> word.split("")) // Stream<String[]>
  10. .map(Arrays::stream) // 返回多个Stream<String>
  11. .distinct()
  12. .collect(toList());
  13. words.stream()
  14. .map(w -> w.split(""))
  15. .flatMap(Arrays::stream) //将多个Stream<String>合并为一个Stream<String>
  16. .distinct()
  17. .collect(Collectors.toList());
  18. // 连接字符串
  19. String shortMenu = menu.stream() //内部使用了StringBuilder来把生成的字符串逐个追加起来
  20. .map(Dish::getName).collect(joining());
  21. String shortMenu = menu.stream()
  22. .collect(joining()); // 不对原流进行映射,通过toString()返回得到结果

查找

  1. // 至少匹配一个元素(终端操作)
  2. menu.stream()
  3. .anyMatch(Dish::isVegetarian) // 返回boolean
  4. //是否配置所有元素
  5. menu.stream()
  6. .allMatch(d -> d.getCalories() < 1000);
  7. //没有任何元素匹配
  8. menu.stream()
  9. .noneMatch(d -> d.getCalories() >= 1000);
  10. //返回流中任意元素,Optional<T>类(java.util.Optional)是一个容器类,代表一个值存在或不存在,若没有元素会出现nullPoint异常
  11. Optional<Dish> dish = menu.stream()
  12. .filter(Dish::isVegetarian).findAny();
  13. //查找第一个元素: findFirst()

创建流

  1. // 创建流
  2. // 值 Stream.of
  3. Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");
  4. stream.map(String::toUpperCase).forEach(System.out::println);
  5. // 数组 Arrays.stream
  6. int[] numbers = {2, 3, 5, 7, 11, 13};
  7. int sum = Arrays.stream(numbers).sum(); //IntStream
  8. // 文件 NIO API Files.lines,它会返回一个由指定文件中的各行构成的字符串流
  9. longuniqueWords=0;
  10. try(Stream<String> lines = Files.lines(Paths.get("copy.txt"), Charset.defaultCharset())){
  11. uniqueWords=lines.flatMap(line->Arrays.stream(line.split(""))) // 每个流都是文件的一行,并拆分为单词,将每个流拆分的单词都合并为一个流
  12. .distinct()
  13. .count();
  14. }catch(Exceptione){
  15. e.getStackTrace();
  16. }
  17. // 函数 创建无限流(没有固定大小的流) Stream.iterate和Stream.generate
  18. Stream.iterate(0, n -> n + 2) //接受一个UnaryOperator<t>作为参数
  19. .limit(10)
  20. .forEach(System.out::println);
  21. Stream.generate(Math::random)
  22. .limit(5)
  23. .forEach(System.out::println);
  24. IntStream ones = IntStream.generate(() -> 1); // 值都为1的无限流
  25. IntStream twos = IntStream.generate(new IntSupplier(){
  26. public int getAsInt(){ //显示传递对象
  27. return 2;
  28. }
  29. });

转换

  1. // map转list
  2. map.entrySet().stream()
  3. .map(e -> new Person(e.getKey(),e.getValue())).collect(Collectors.toList());
  4. // list转map
  5. Map<Integer, String> result = list.stream()
  6. .collect(Collectors.toMap(Hosting::getId, Hosting::getName));
  7. Map<String, FormDict> map = list.stream()
  8. .collect(Collectors.toMap(Dict::getCode, Dict->Dict));

Guava、Apache和lambdaj库提供了声明性操作集合的工具
数据处理的形式:
1、元素的操作
2、元素转换形式或提取信息
3、终端操作(返回结果)

  1. // 流只能遍历一次
  2. Stream<String> s = title.stream();
  3. s.forEach(System.out::println);
  4. s.forEach(System.out::println); //异常,流已被操作或关闭

image.png
Optional提供可以显式地检查值是否存在或处理值不存在的情形的方法

  • isPresent()将在Optional包含值的时候返回true, 否则返回false。
  • ifPresent(Consumer block)会在值存在的时候执行给定的代码块。
  • T get()会在值存在时返回值,否则抛出一个NoSuchElement异常。
  • T orElse(T other)会在值存在时返回值,否则返回一个默认值。

无状态:不存储任何状态
有状态:需要存储状态才能进行下一步操作
image.png

  1. //数值流
  2. //流转换 mapToInt、mapToDouble和mapToLong 将Stream<Integer> 转换返回IntStream
  3. //流为空,默认返回为0
  4. Stream<Integer> stream = intStream.boxed(); // 可以流转换为非特化流
  5. //Optional原始类型特化
  6. OptionalIntOptionalDoubleOptionalLong //会判断没有最大值(流为空)或最大值为0时,定义一个默认值

自定义收集器的实现

T是流中要收集的项目的泛型。
A是累加器的类型,累加器是在收集过程中用于累积部分结果的对象。
R是收集操作得到的对象(通常但并不一定是集合)的类型。

  1. public interface Collector<T, A, R> {
  2. Supplier<A> supplier();
  3. BiConsumer<A, T> accumulator();
  4. Function<A, R> finisher();
  5. BinaryOperator<A> combiner();
  6. Set<Characteristics> characteristics();
  7. }
  8. // 1. 建立新的结果容器:supplier方法,将累加器本身作为结果返回
  9. public Supplier<List<T>> supplier() {
  10. return () -> new ArrayList<T>();
  11. }
  12. public Supplier<List<T>> supplier() {
  13. return ArrayList::new;
  14. }
  15. // 2. 将元素添加到结果容器:accumulator方法,返回执行归约操作的函数
  16. public BiConsumer<List<T>, T> accumulator() {
  17. return List::add;
  18. }
  19. // 3. 对结果容器应用最终转换:finisher方法,返回在累积过程的最后要调用的一个函数,以便将累加器对象转换为整个集合操作的最终结果
  20. public Function<List<T>, List<T>> finisher() {
  21. return Function.identity();
  22. }
  23. // 4. 合并两个结果容器:combiner方法,各个子部分归约所得的累加器要如何合并
  24. public BinaryOperator<List<T>> combiner() {
  25. return (list1, list2) -> {
  26. list1.addAll(list2);
  27. return list1;
  28. }
  29. }
  30. //5. characteristics方法,定义了收集器的行为——尤其是关于流是否可以并行归约
  31. UNORDERED
  32. CONCURRENT
  33. IDENTITY_FINISH
  34. public Set<Characteristics> characteristics() {
  35. return Collections.unmodifiableSet(EnumSet.of(
  36. IDENTITY_FINISH, CONCURRENT));
  37. }

image.png

同步/异步

同步API:阻塞式调用
调用方需要等待被调用方继续运行,当前任务和调用任务是同一线程
异步API:非阻塞调用
调用方的计算任务和调用任务是异步操作,计算任务的线程会将结果返回给调用方(回调函数、再次调用等待计算任务完成的方法)

  1. public double getPrice(String product) {
  2. return calculatePrice(product);
  3. }
  4. private double calculatePrice(String product) {
  5. delay();
  6. return random.nextDouble() * product.charAt(0) + product.charAt(1);
  7. }
  8. public Future<Double> getPriceAsync(String product) {
  9. CompletableFuture<Double> futurePrice = new CompletableFuture<>();
  10. new Thread( () -> { // 另一个线程异步方式执行
  11. try {
  12. double price = calculatePrice(product);//长时间计算的任务并得出结果
  13. futurePrice.complete(price);// 设置返回值
  14. } catch (Exception ex) {
  15. futurePrice.completeExceptionally(ex); // 抛出异常
  16. }
  17. }).start();
  18. return futurePrice;
  19. }
  20. Future<Double> futurePrice = shop.getPriceAsync("my favorite product");
  21. double price = futurePrice.get(); // 需要依赖到价格的计算时,调用Future的get方法,要么直接获取返回值,要么等待异步任务完成。
  22. // 使用工厂方法supplyAsync创建CompletableFuture对象
  23. public Future<Double> getPriceAsync(String product) {
  24. return CompletableFuture.supplyAsync(() -> calculatePrice(product));
  25. }

CompletableFuture实现

  1. public List<String> findPrices(String product) {
  2. List<CompletableFuture<String>> priceFutures = shops.stream()
  3. .map(shop -> CompletableFuture.supplyAsync(() -> shop.getName() + " price is " + shop.getPrice(product)))
  4. .collect(Collectors.toList());
  5. return priceFutures.stream()
  6. .map(CompletableFuture::join) // 等待所有异步操作结束
  7. .collect(toList());
  8. }

高阶函数

接受函数作为参数的方法或者返回一个函数的方法
调试:使用peek() 输出流中每一步的操作结果

默认方法:
1、在接口内声明静态方法
2、默认方法:让类可以自动地继承接口的一个默认实现。

接口和工具辅助类的同时定义:
Collections就是处理Collection对象的辅助类
可以将工具类中与接口实例协作的静态方法定义在接口内

抽象接口和抽象类的区别:
1、一个类只能继承一个抽象类,但是一个类可以实现多个接口。
2、一个抽象类可以通过实例变量(字段)保存一个通用状态,而接口是不能有实例变量的。

默认方法解决的问题
可选方法:不需要实现无用的方法,直接使用默认实现
行为的多继承:可以实现多个有默认方法的接口

自定义默认方法,实现java中的多继承
如在Collction添加removeIf,ArrayList、TreeSet、LinkedList以及其他集合类型都会使用removeIf方法的默认实现

  1. default boolean removeIf(Predicate<? super E> filter) {
  2. boolean removed = false;
  3. Iterator<E> each = iterator();
  4. while(each.hasNext()) {
  5. if(filter.test(each.next())) {
  6. each.remove();
  7. removed = true;
  8. }
  9. }
  10. return removed;
  11. }

API不同类型的兼容性:

  • 二进制级的兼容:表示现有的二进制执行文件能无缝持续链接(包括验证、准备和解析)和运行

向接口添加一个方法,新的方法不会调用,已经实现的方法可以调用,不会报错

  • 源代码级的兼容:表示引入变化之后,现有的程序依然能成功编译通过

向接口添加默认方法

  • 函数行为的兼容:表示变更发生之后,程序接受同样的输入能得到同样的结果

为接口添加新的方法也是函数行为兼容的

源码

  1. // 默认方法,使用default关键子表示
  2. defaultvoidsort(Comparator<? super E> c) {
  3. Collections.sort(this, c);
  4. }
  5. Optional<T> NullPointer // 异常处理

(结构)模式匹配

行为参数化:让方法接受多种行为(或战略)作为参数,并在内部使用,来完成不同的行为。
根据传递参数的类型,可以是类对象、方法、代码块参数化
还可以是匿名类

调试

image.pngimage.png