Java8—新特性汇总.md

2020年4月9日 | 作者 Siran | 4900字 | 阅读大约需要10分钟
归档于 Java | 标签 #Java

1.Lambda

1.1 方法引用

  • 指向静态方法的方法引用(例如Integer的parseInt方法,写作Integer::parseInt)。

  • 指向任意类型实例方法的方法引用(例如String的length方法,写作 String::length)。

  • 指向现有对象的实例方法的方法引用(假设你有一个局部变量expensiveTransaction 用于存放Transaction类型的对象,它支持实例方法getValue,那么你就可以写expensive- Transaction::getValue)。

        List<String> str = Arrays.asList("a", "b", "A", "B");
        str.sort((s1,s2) -> s1.compareToIgnoreCase(s2));
        str.sort(String::compareToIgnoreCase);

        Function<String,Integer> stringToInteger = (String s) -> Integer.parseInt(s);
        Function<String,Integer> sti = Integer::parseInt;

        BiPredicate<List<String>, String> contains = (list, element) ->    list.contains(element);
        BiPredicate<List<String>, String> c = List::contains;

构造函数引用

public class Apple {
    private Integer weight;
    private String color;

    public Apple(Integer weight) {
        this.weight = weight;
    }

    public Apple(String color, Integer weight) {
        this.weight = weight;
        this.color = color;
    }
}
public static List<Apple> map(List<Integer> list,
                                  Function<Integer, Apple> f){
        List<Apple> result = new ArrayList<>();
        for(Integer e: list){
            result.add(f.apply(e));
        }
        return result;
    }
public static List<Apple> mapTwo(List<Integer> list,
                                  BiFunction<String,Integer, Apple> f){
        List<Apple> result = new ArrayList<>();
        for(Integer e: list){
            result.add(f.apply("green",e));
        }
        return result;
}
public static void main(String[] args) {
        List<Integer> weights = Arrays.asList(7, 3, 4, 10);
        List<Apple> apples =  map(weights, Apple::new);

        BiFunction<String,Integer,Apple> c3 = Apple::new;
        Apple green = c3.apply("green", 10);
        List<Apple> two = mapTwo(weights, Apple::new);
    }

排序:

//1. 
public class AppleComparator implements Comparator<Apple> {
        public int compare(Apple a1, Apple a2){
            return a1.getWeight().compareTo(a2.getWeight());
        }
    }
    inventory.sort(new AppleComparator());
//2.
inventory.sort(new Comparator<Apple>() {
        public int compare(Apple a1, Apple a2){
            return a1.getWeight().compareTo(a2.getWeight());
        }
});
//3.
inventory.sort((Apple a1, Apple a2)
                -> a1.getWeight().compareTo(a2.getWeight())
);
inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight()));
Comparator<Apple> c = Comparator.comparing((Apple a) -> a.getWeight());
inventory.sort(comparing((a) -> a.getWeight()));
//4. 方法引用
inventory.sort(comparing(Apple::getWeight));

1.2 复合Lambda表达式

1.2.1 比较器复合

  • 逆序

    //苹果按重量递减排序
    Comparator<Apple> c = Comparator.comparing(Apple::getWeight);
    inventory.sort(comparing(Apple::getWeight).reversed());
    
  • 比较器链

    //两个苹果一样重怎么办?哪个苹果应该排在前面呢?你可能 需要再提供一个Comparator来进一步定义这个比较
    inventory.sort(comparing(Apple::getWeight)
             .reversed()
             .thenComparing(Apple::getCountry)) //一样重是按国家排序
    

1.2.2 谓词复合 negate、and、or

//苹果不是红的
Predicate<Apple> notRedApple = redApple.negate(); 
//一个苹果是红的 重量大于150
Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight() > 150); 
//表达要么是重(150克以上)的红苹果,要么是绿苹果:
Predicate<Apple> redAndHeavyAppleOrGreen =
  redApple.and(a -> a.getWeight() > 150)
          .or(a -> "green".equals(a.getColor())); 

1.2.3 函数复合 andThen、compose

  • andThen : 会返回一个函数,它先对输入应用一个给定函数,再对输出应用另一个函数。

    Function<Integer,Integer> f = x -> x + 1;
    Function<Integer,Integer> g = x -> x * 2;
    Function<Integer,Integer> h = f.andThen(g);
    int result = h.apply(1);  //4
    
  • compose : 先把给定的函数用作compose的参数里面给的那个函数,然后再把函数本身用于结果。

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

案例: 用String 标识的一封信做文本转换:

 public class Letter{
        public static String addHeader(String text){
            return "From Raoul, Mario and Alan: " + text;
        }
        public static String addFooter(String text){
            return text + " Kind regards";
        }
        public static String checkSpelling(String text){
            return text.replaceAll("labda", "lambda");
        } 
}
public static void main(String[] args){
  Function<String, String> addHeader = Letter::addHeader;
  //先加上 抬头,然后进行拼写检查,最后加上一个落款
  Function<String, String> transformationPipeline
        = addHeader.andThen(Letter::checkSpelling)
                   .andThen(Letter::addFooter);
  //只加抬头、落款,而不做拼写检查:
  Function<String, String> transformationPipeline
        = addHeader.andThen(Letter::addFooter);
}

1.3 Lambda 小结

  • Lambda表达式可以理解为一种匿名函数:它没有名称,但有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常的列表。
  • Lambda表达式让你可以简洁地传递代码。
  • 函数式接口就是仅仅声明了一个抽象方法的接口。
  • 只有在接受函数式接口的地方才可以使用Lambda表达式。
  • Lambda表达式允许你直接内联,为函数式接口的抽象方法提供实现,并且将整个表达式作为函数式接口的一个实例。
  • Java 8自带一些常用的函数式接口,放在java.util.function包里,包括Predicate、Function<T,R>、Supplier、Consumer和BinaryOperator,如表3-2所述。
  • 为了避免装箱操作,对Predicate和Function<T, R>等通用函数式接口的原始类型特化:IntPredicate、IntToLongFunction等。
  • 环绕执行模式(即在方法所必需的代码中间,你需要执行点儿什么操作,比如资源分配 和清理)可以配合Lambda提高灵活性和可重用性。
  • Lambda表达式所需要代表的类型称为目标类型。
  • 方法引用让你重复使用现有的方法实现并直接传递它们。
  • Comparator、Predicate和Function等函数式接口都有几个可以用来结合Lambda表达式的默认方法

2. Stream

//单核处理
List<String> lowCaloricDishesName =
               menu.stream()
                   .filter(d -> d.getCalories() < 400) //选出400卡路里 以下的菜肴
                   .sorted(comparing(Dish::getCalories)) //按照卡路;里排序
                   .map(Dish::getName) //提取菜肴的名称
                   .collect(toList());//将所有名称保存在List中
//多核处理
List<String> lowCaloricDishesName =
               menu.parallelStream()
                   .filter(d -> d.getCalories() < 400) //选出400卡路里 以下的菜肴
                   .sorted(comparing(Dish::getCalories)) //按照卡路;里排序
                   .map(Dish::getName) //提取菜肴的名称
                   .collect(toList());//将所有名称保存在List中
 

2.1 流与集合

2.1.1 流只能遍历一次

List<String> title = Arrays.asList("Java8", "In", "Action");
        Stream<String> s = title.stream();
        s.forEach(System.out::println);  //只能被消费一次
        s.forEach(System.out::println); //java.lang.IllegalStateException:流已被操作 或关闭

2.1.2 外部迭代与内部迭代

  • 集合:外部迭代

    //用for-each循环
    List<String> names = new ArrayList<>();
        for(Dish d: menu){
         names.add(d.getName());
    }
    //用背后的迭代器做外部迭代
    List<String> names = new ArrayList<>();
        Iterator<String> iterator = menu.iterator();
        while(iterator.hasNext()) {
            Dish d = iterator.next();
            names.add(d.getName());
        }
    
  • 流:内部迭代

    List<String> names = menu.stream()
                             .map(Dish::getName)
                             .collect(toList());
    

2.1.3 流操作—中间操作

诸如filter或sorted等中间操作会返回另一个流

2.1.4 流操作—中端操作

终端操作会从流的流水线生成结果。

2.1.5 流操作—使用流

  • 一个数据源(如集合)来执行一个查询;
  • 一个中间操作链,形成一条流的流水线;
  • 一个终端操作,执行流水线,并能生成结果。

2.2 流操作

2.2.1 筛选和切片

用谓词筛选,筛选出各不相同的元素,忽略流中的头几个元素,或将流截短至指定长度。

  • 用谓词筛选

    List<Dish> vegetarianMenu = menu.stream()
                                     //方法引用检查菜肴是否适合素食者
                                    .filter(Dish::isVegetarian) 
                                    .collect(toList());
    
  • 去重

    List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
    numbers.stream()
      .filter(i -> i % 2 == 0)
      .distinct() //去重
      .forEach(System.out::println);
    
  • 截短流

    List<Dish> dishes = menu.stream()
                                .filter(d -> d.getCalories() > 300)
                                .limit(3)
                                .collect(toList());
    
  • 跳过元素

    List<Dish> dishes = menu.stream()
                                .filter(d -> d.getCalories() > 300)
                                .skip(2) //跳过
                                .collect(toList());
    

2.2.2 映射

  • 对流中每一个元素应用函数

    List<String> dishNames = menu.stream()
                                     .map(Dish::getName) //提取菜肴的名字
                                     .collect(toList());
    
  • 流的扁平化

    List<String> uniqueCharacters =
        words.stream()
             .map(w -> w.split("")) //将每个单词转换为由 其字母构成的数组
             .flatMap(Arrays::stream) //将各个生成流扁平化为单个流
             .distinct()
             .collect(Collectors.toList());
    

    案例一:给定一个数字列表,如何返回一个由每个数的平方构成的列表呢?例如,给定[1, 2, 3, 4,5],应该返回[1, 4, 9, 16, 25]

    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
            List<Integer> collect1 = list.stream()
                    .map(i -> i * i)
                    .collect(toList());
            System.out.println(collect1);
    

    案例二:给定两个数字列表,如何返回所有的数对呢?例如,给定列表[1, 2, 3]和列表[3, 4],应 该返回[(1, 3), (1, 4), (2, 3), (2, 4), (3, 3), (3, 4)]。

     List<Integer> numbers1 = Arrays.asList(1, 2, 3);
            List<Integer> numbers2 = Arrays.asList(3, 4);
            List<int[]> pairs =
                    numbers1.stream()
                            .flatMap(i -> numbers2.stream()
                                    .map(j -> new int[]{i, j})
                            )
                            .collect(toList());
    

    案例三:扩展前一个例子,只返回总和能被3整除的数对呢?例如(2, 4)和(3, 3)是可以的

    List<int[]> collect =
                    numbers1.stream()
                    .flatMap(i -> numbers2.stream()
                            .filter(j -> (i + j) % 3 == 0)
                            .map(j -> new int[]{i, j}))
                            .collect(toList());
    

2.2.3 查找和匹配

  • 检查谓词是否至少匹配一个元素

    //anyMatch
    if(menu.stream().anyMatch(Dish::isVegetarian)){
         System.out.println("The menu is (somewhat) vegetarian friendly!!");
    }
    
  • 检查谓词是否匹配所有元素

    //allMatch
    boolean isHealthy = menu.stream()
                                .allMatch(d -> d.getCalories() < 1000);
    //noneMatch
     boolean isHealthy = menu.stream()
                                .noneMatch(d -> d.getCalories() >= 1000);
    
  • 查找元素

    Optional<Dish> dish =
            menu.stream()
                .filter(Dish::isVegetarian)
                .findAny();  //返回当前流中的任意元素
    
  • 查找第一个元素

     List<Integer> someNumbers = Arrays.asList(1, 2, 3, 4, 5);
        Optional<Integer> firstSquareDivisibleByThree =
            someNumbers.stream()
                       .map(x -> x * x)
                       .filter(x -> x % 3 == 0)
                       .findFirst(); // 9
    

2.2.4 归约

  • 元素求和

    int sum = numbers.stream().reduce(0, (a, b) -> a + b);
    int sum = numbers.stream().reduce(0, Integer::sum);
    
  • 最大值和最小值

    //最大值
    Optional<Integer> max = numbers.stream().reduce(Integer::max);
    //最小值
    Optional<Integer> min = numbers.stream().reduce(Integer::min);
    

    案例:

    public class Trader {
        private final String name;
        private final String city;
    }
    public class Transaction {
        private final Trader trader;
        private final int year;
        private final int value;
    }
    public class TradeTest {
        private static List<Transaction> transactions;
      
        static {
            Trader raoul = new Trader("Raoul", "Cambridge");
            Trader mario = new Trader("Mario", "Milan");
            Trader alan = new Trader("Alan", "Cambridge");
            Trader brian = new Trader("Brian", "Cambridge");
            transactions = Arrays.asList(
                    new Transaction(brian, 2011, 300),
                    new Transaction(raoul, 2012, 1000),
                    new Transaction(raoul, 2011, 400),
                    new Transaction(mario, 2012, 710),
                    new Transaction(mario, 2012, 700),
                    new Transaction(alan, 2012, 950)
            );
        }
      
        public static void main(String[] args) {
            //1.找出2011年发生的所有交易,并按交易额排序(从低到高)。
            List<Transaction> case1 = transactions.stream()
                    .filter(t -> t.getYear() == 2011)
                    .sorted(comparing(Transaction::getValue))
                    .collect(Collectors.toList());
      
            //2.交易员都在哪些不同的城市工作过?
            List<String> case2 = transactions.stream()
                    .map(Transaction::getTrader)
                    .map(Trader::getCity)
                    .distinct()
                    .collect(Collectors.toList());
            //3.查找所有来自于剑桥的交易员,并按姓名排序。
            List<Trader> case3 = transactions.stream()
                    .map(Transaction::getTrader)
                    .filter(trader -> trader.getCity().equals("Cambridge"))
                    .distinct()
                    .sorted(comparing(Trader::getName))
                    .collect(Collectors.toList());
            //4.返回所有交易员的姓名字符串,按字母顺序排序。
            String case4 = transactions.stream()
                    .map(transaction -> transaction.getTrader().getName())
                    .distinct()
                    .sorted()
                    .reduce("",(name1,name2) ->name1 + name2); //reduce(joining())
            //5.有没有交易员是在米兰工作的?
            boolean case5 = transactions.stream()
                    .anyMatch(transaction ->    transaction.getTrader().getCity().equals("Milan"));
            //6.打印生活在剑桥的交易员的所有交易额。
            transactions.stream()
                    .filter(transaction -> transaction.getTrader().getCity().equals("Cambridge"))
                    .map(Transaction::getValue)
                    .forEach(System.out::println);
            //7.所有交易中,最高的交易额是多少?
            Optional<Integer> case7 = transactions.stream()
                    .map(Transaction::getValue)
                    .reduce(Integer::max);
            //8.找到交易额最小的交易。
            Optional<Integer> case8 = transactions.stream()
                    .map(Transaction::getValue)
                    .reduce(Integer::min);
        }
    

2.2.5 数值流

//这段代码的问题是,它有一个暗含的装箱成本。每个Integer都必须拆箱成一个原始类型再进行求和
transactions.stream()
                .map(Transaction::getValue)
                .reduce(Integer::min);
    }
  • 原始类型流特化 IntStreamDoubleStreamLongStream

    • 映射到数值流

      int calories = menu.stream()//返回一个Stream<Dish>
                         .mapToInt(Dish::getCalories) // 返回一个 IntStream
                         .sum();
      
    • 转换回对象流

      //将 Stream 转 换为数值流
      IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
      //将数值流转 换为Stream
      Stream<Integer> stream = intStream.boxed();
      
    • 默认值 OptionalInt

      OptionalInt maxCalories = menu.stream()
                                        .mapToInt(Dish::getCalories)
                                        .max();
      //现在,如果没有最大值的话,你就可以显式处理OptionalInt去定义一个默认值了:
      int max = maxCalories.orElse(1);
      
  • 数值范围

    IntStream evenNumbers = IntStream.rangeClosed(1, 100)  //表示范围[1, 100] 
                                     .filter(n -> n % 2 == 0); //一个从1到 100的偶数流
    //range是不包含结束值的。[1,100)
    
  • 数值流应用:勾股数

2.2.6 构建流

  • 由值创建流

    Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action"); stream.map(String::toUpperCase).forEach(System.out::println);
    //你可以使用empty得到一个空流,如下所示: 
    Stream<String> emptyStream = Stream.empty();
    
  • 由数组创建流

    int[] numbers = {2, 3, 5, 7, 11, 13}; 
    int sum = Arrays.stream(numbers).sum();
    
  • 由文件生成流

    long uniqueWords = 0;
    try(Stream<String> lines =
            //流会自动 关闭
            Files.lines(Paths.get("data.txt"), Charset.defaultCharset())){ 
                  //生成单词流
                  uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))
                                     .distinct() //删除重复项
                                     .count();//数一数有多少各 不相同的单词
       }catch(IOException e){
    }
    
  • 由函数生成流:创建无限流

    • 迭代

      Stream.iterate(0, n -> n + 2)
            .limit(10)
            .forEach(System.out::println);
      
    • 生成

      Stream.generate(Math::random)
                .limit(5)
                .forEach(System.out::println);
      

2.3 用流收集数据

2.3.1 归纳与汇总

  • 查找流中的最大值和最小值

    Comparator<Dish> dishCaloriesComparator =
                    Comparator.comparingInt(Dish::getCalories);
      
            Optional<Dish> mostCalorieDish =
                    menu.stream()
                            .collect(maxBy(dishCaloriesComparator));//maxBy 最大 minBy最小
    
  • 汇总

    //总和
    int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));
    //平均
    double avgCalories = menu.stream().collect(averagingInt(Dish::getCalories));
    //IntSummaryStatistics{count=9, sum=4300, min=120,average=477.777778, max=800}
    //个数,并得 总和、平均值、最大值和最小值:
    IntSummaryStatistics menuStatistics = menu.stream().collect(summarizingInt(Dish::getCalories));
    
  • 连接字符串

    String shortMenu = menu.stream().map(Dish::getName).collect(joining());
    //逗号分隔的名称列表:
    String shortMenu = menu.stream().map(Dish::getName).collect(joining(", "));
    
  • 广义的归约总汇

    Optional<Dish> mostCalorieDish =
        menu.stream().collect(reducing(
                (d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2));
    
    • 收集框架的灵活性:以不同的方法执行同样的操作

      int totalCalories = menu.stream().collect(reducing(0, //初始值
       Dish::getCalories,  //转换函数
       Integer::sum)); //累积函数
      

2.3.2 分组

Map<Dish.Type, List<Dish>> dishesByType =
                          menu.stream().collect(groupingBy(Dish::getType));
//{FISH=[prawns, salmon], OTHER=[french fries, rice, season fruit, pizza], MEAT=[pork, beef, chicken]}

//你可能想把热量不到400卡路里的菜划分为“低热量”(diet),热量400到700 卡路里的菜划为“普通”(normal),高于700卡路里的划为“高热量”(fat)。
public enum CaloricLevel { DIET, NORMAL, FAT }
Map<CaloricLevel, List<Dish>> dishesByCaloricLevel = menu.stream().collect( 
  groupingBy(dish -> {
               if (dish.getCalories() <= 400) 
                 return CaloricLevel.DIET;
               else if (dish.getCalories() <= 700) 
                 return CaloricLevel.NORMAL;
               else return CaloricLevel.FAT;
         } ));
  • 多级分组

    要实现多级分组,我们可以使用一个由双参数版本的Collectors.groupingBy工厂方法创 建的收集器,它除了普通的分类函数之外,还可以接受collector类型的第二个参数。那么要进 行二级分组的话,我们可以把一个内层groupingBy传递给外层groupingBy,并定义一个为流 中项目分类的二级标准

    Map<Dish.Type, Map<CaloricLevel, List<Dish>>> dishesByTypeCaloricLevel = menu.stream().collect(
        groupingBy(Dish::getType, // 一级分类函数
            groupingBy(dish -> {//二级分类函数
              if (dish.getCalories() <= 400) return CaloricLevel.DIET;
              else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
              else return CaloricLevel.FAT;
             } ));
    //  这个二级分组的结果就是像下面这样的两级Map:
    //{MEAT={DIET=[chicken], NORMAL=[beef], FAT=[pork]}, FISH={DIET=[prawns], NORMAL=[salmon]},
    //OTHER={DIET=[rice, seasonal fruit], NORMAL=[french fries, pizza]}}
    
  • 按子组收集数据

    //1.要数一数菜单中每类菜有多少个
    Map<Dish.Type, Long> typesCount = menu.stream().collect(
                       groupingBy(Dish::getType, counting()));
    //{MEAT=3, FISH=2, OTHER=4}
      
    //2. 查找菜单中热量最高的菜肴的收集器改一改
    Map<Dish.Type, Optional<Dish>> mostCaloricByType =
        menu.stream()
            .collect(groupingBy(Dish::getType,
                                maxBy(comparingInt(Dish::getCalories))));
    //{FISH=Optional[salmon], OTHER=Optional[pizza], MEAT=Optional[pork]}
      
    //3. 去掉返回值的Optional
     Map<Dish.Type, Dish> mostCaloricByType =
        menu.stream()
            .collect(groupingBy(Dish::getType,
                                maxBy(comparingInt(Dish::getCalories)),
                                Optional::get
                               ));
    //4. 对每一组的菜肴热量求总和
     Map<Dish.Type, Integer> totalCaloriesByType =
                       menu.stream().collect(groupingBy(Dish::getType,
                                summingInt(Dish::getCalories)));
      
    //5. 对于每种类型的Dish, 菜单中都有哪些CaloricLevel
     Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType =
        menu.stream().collect(
           groupingBy(Dish::getType, mapping(
           dish -> { if (dish.getCalories() <= 400) return CaloricLevel.DIET;
                   else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
                   else return CaloricLevel.FAT; },
                    toSet() )));
    

2.3.3 分区

由一个谓词(返回一个布尔值的函数)作为分类函数,它称分区函 数

//1. 菜单按照素食和非素食分开
Map<Boolean,List<Dish>> partitionedMenu = 
             menu.stream().collect(partitioningBy(Dish::isVegetarian))//分区函数 
//2. 将数字按质数和非质数分区 它接受参数int n,并将前n个自然数分为质数和非质数
   public boolean isPrime(int candidate) {
        int candidateRoot = (int) Math.sqrt((double) candidate);
        return IntStream.rangeClosed(2, candidateRoot)
                        .noneMatch(i -> candidate % i == 0);
}

  public Map<Boolean, List<Integer>> partitionPrimes(int n) {
        return IntStream.rangeClosed(2, n).boxed()
                        .collect(
                            partitioningBy(candidate -> isPrime(candidate)));
}

Collectors类的静态工厂方法

  • toList :用于把流中所有项目收集到一个

    ListList<Dish> dishes = menuStream.collect(toList());
    
  • toSet : 把流中所有项目收集到一个 Set,删除重复项

    Set<Dish> dishes = menuStream.collect(toSet());
    
  • toCollection :把流中所有项目收集到给定的供应源创建的集合

    Collection<Dish> dishes = menuStream.collect(toCollection(), ArrayList::new);
    
  • counting 计算流中元素的个数

    long howManyDishes = menuStream.collect(counting()); 
    
  • summingInt 对流中项目的一个整数属性求和

    int totalCalories = menuStream.collect(summingInt(Dish::getCalories));
    
  • averagingInt 计算流中项目 Integer 属性的平均值

    double avgCalories = menuStream.collect(averagingInt(Dish::getCalories));
    
  • summarizingInt 收集关于流中项目 Integer 属性的统计值,例如最大、最小、总和与平均值

    IntSummaryStatistics menuStatistics =
               menuStream.collect(summarizingInt(Dish::getCalories));
    
  • joining 连接对流中每个项目调用 toString 方法所生成的字符串

    String shortMenu = menuStream.map(Dish::getName).collect(joining(", "));
    
  • maxBy 一个包裹了流中按照给定比较器选出的最大元素的 Optional, 或如果流为空则为 Optional.empty()

    Optional<Dish> fattest = menuStream.collect(maxBy(comparingInt(Dish::getCalories)));
    
  • minBy 一个包裹了流中按照给定比较器选出的最小元素的 Optional, 或如果流为空则为 Optional.empty()

    Optional<Dish> lightest = menuStream.collect(minBy(comparingInt(Dish::getCalories)));
    
  • reducing 从一个作为累加器的初始值开始,利用 BinaryOperator 与流 中的元素逐个结合,从而将流归约为单个值

    int totalCalories = menuStream.collect(reducing(0, Dish::getCalories, Integer::sum));
    
  • collectingAndThen 包裹另一个收集器,对其结果应用转换函数

    int howManyDishes =menuStream.collect(collectingAndThen(toList(), List::size));
    
  • groupingBy 根据项目的一个属性的值对流中的项目作问组,并将属性值作 为结果 Map 的键

    Map<Dish.Type,List<Dish>> dishesByType = menuStream.collect(groupingBy(Dish::getType));
    
  • partitioningBy 根据对流中每个项目应用谓词的结果来对项目进行分区

    Map<Boolean,List<Dish>> vegetarianDishes =Map<Boolean,List<T>> = 
                     menuStream.collect(partitioningBy(Dish::isVegetarian));
    

2.3.4 收集器接口

 public interface Collector<T, A, R> {
        Supplier<A> supplier();
        BiConsumer<A, T> accumulator();
        Function<A, R> finisher();
        BinaryOperator<A> combiner();
        Set<Characteristics> characteristics();
}
  • T是流中要收集的项目的泛型。
  • A是累加器的类型,累加器是在收集过程中用于累积部分结果的对象。
  • R是收集操作得到的对象(通常但并不一定是集合)的类型。

2.3.5 开发你自己的收集器


2.4 并行数据处理与性能

2.4.1 并行流

2.4.2 分支/合并框架

2.4.3 Spliterator


2.5 Stream 小结