Java 8 实战 -- 函数式数据处理 (二)

引入流

1 流简介
流是Java API的新成员,它允许你以声明性方式处理数据集合,可以把它们看成遍历数据集的高级迭代器。

 List<Dish> menu = Arrays.asList(
            new Dish("pork", false, 800, Dish.Type.MEAT),
            new Dish("beef", false, 700, Dish.Type.MEAT),
            new Dish("chicken", false, 400, Dish.Type.MEAT),
            new Dish("french fries", true, 530, Dish.Type.OTHER),
            new Dish("rice", true, 350, Dish.Type.OTHER),
            new Dish("season fruit", true, 120, Dish.Type.OTHER),
            new Dish("pizza", true, 550, Dish.Type.OTHER),
            new Dish("prawns", false, 300, Dish.Type.FISH),
            new Dish("salmon", false, 450, Dish.Type.FISH) );

 //获取>400的 高热量菜单的名称
 List<String> threeHighCaloricDishNames = menu.stream().filter(d -> d.getCalories() > 400).sorted().map(Dish::getName).collect(Collectors.toList());

2 流操作

java.util.stream.Stream中的Stream接口定义了许多操作。它们可以分为两大类。

  • 中间操作 :中间操作会返回另一个流。
    这里写图片描述
  • 终端操作 :终端操作会从流的流水线生成结果。其结果是任何不 是流的值,比如List、 Integer,甚至void。
    这里写图片描述

    使用流

    1.筛选和切片

  • 使用谓词筛选-filter(boolean):接受一个谓词(一个返回boolean的函数)作为参数

stream().filter(Dish::isVegetarian).collect(toList());
  • 筛选各异的元素-distinct
stream().filter(i -> i % 2 == 0)
        .distinct().forEach(System.out::println);
  • 截短流-limit(n):返回一个指定长度的流
stream().filter(d -> d.getCalories() > 300)
        .limit(3).collect(toList());
  • 跳过元素-skip(n):跳过前n个元素
stream().filter(d -> d.getCalories() > 300)
        .skip(2).collect(toList());

2.映射
一个非常常见的数据处理套路就是从某些对象中选择信息。比如在SQL里,你可以从表中选择一列。 Stream API也通过map和flatMap方法提供了类似的工具。

  • 对流中每一个元素应用函数 - map
List<String> words = Arrays.asList("Java 8", "Lambdas", "In", "Action");
List<Integer> wordLengths = words.stream()
                                .map(String::length)
                                .collect(toList());
  • 流的扁平化 - flatMap
    flatMap和map有什么区别呢?flatMap的作用是将所有使用流集合合并起来,扁平化为一个流。
Stream<String[]>      -> flatMap  ->   Stream<String>
Stream<Set<String>>   -> flatMap  ->   Stream<String>
Stream<List<String>>  -> flatMap  ->   Stream<String>
Stream<List<Object>>  -> flatMap  ->   Stream<Object>

这里写图片描述


这里写图片描述

List<Integer> numbers1 = Arrays.asList(1, 2, 3);
List<Integer> numbers2 = Arrays.asList(3, 4);
Stream<Stream<int[]>> stream3 = numbers1.stream().map(i -> numbers2.stream().map(j -> {return new int[]{i,j};}));//map 

Stream<int[]> stream4 = numbers1.stream().flatMap(i -> numbers2.stream().map(j -> {return new int[]{i,j};}));//flatMap的作用是将多个流合并为一个流

3.查找和匹配

  • anyMatch: T-> boolean
  • allMatch: T-> boolean
  • noneMatch: T-> boolean
  • findAny: () -> Optional<?>
  • findFirst: () -> Optional<?>
boolean existFlag = menu.stream()
                        .anyMatch(Dish::isVegetarian);
boolean allMatchFlag = menu.stream()
                        .allMatch(Dish::isVegetarian);
boolean noneMatchFlag = menu.stream()
                        .noneMatch(Dish::isVegetarian);
Optional<Dish> anyVegetarian = menu.stream()
                .filter(Dish::isVegetarian).findAny();
boolean firstVegetarianFlag = menu.stream()
.filter(Dish::isVegetarian).findFirst().isPresent();

4.规约

  1. 元素求和
  2. 最大值和最小值
List<Integer> numbers1 = Arrays.asList(1, 2, 3);
int sum = numbers1.stream().reduce(0, (a, b) -> a + b);
sum =  numbers1.stream().reduce(0, Integer::sum);

int multi = numbers1.stream().reduce(1, (a, b) -> a * b);

int max = numbers1.stream().reduce(0, (a, b) -> a > b ? a : b);
max = numbers1.stream().reduce(0, Integer::max);

//无初始值时,返回的为Optional<?>
Optional<Integer> sumOpt = numbers1.stream().reduce( Integer::sum);

迄今为止,我们看到了很多流的操作,在这里做个总结:这里写图片描述]![这里写图片描述

5.数值流
Java 8引入了三个原始类型特化流接口来解决这个问题: IntStream、 DoubleStream和LongStream,分别将流中的元素特化为int、 long和double。每个接口都带来了进行常用数值归约的新方法,比如对数值流求和的sum,min,max,average等。

  • 数值流与对象流相互转换

  • OptionalInt,OptionalDouble,OptionalLong

IntStream intStream = menu.stream()
        .mapToInt(Dish::getCalories);//转换为数值流
Stream<Integer> stream = intStream.boxed();//转换回对象流

OptionalInt maxCalories = intStream.max();
  • 数值范围rangeClosed,range
IntStream.rangeClosed(1,3); //[1,3]
IntStream.range(1,3); //[1,3)

6.构建流

  • 由值创建流
  • 由数组创建流
Stream<String> emptyStream = Stream.empty();//获取空流
Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");

int[] numbers = {2, 3, 5, 7, 11, 13};
//数组构建流,可以将原始的数组转换为一个IntStream
int sum = Arrays.stream(numbers).sum();
  • 由函数生成流:创建无限流
Stream.iterate(0, n -> n + 2).limit(10); //迭代

Stream.generate(Math::random).limit(10); //生成

用流收集数据
这里写图片描述

参考资料

  • java8 in action

猜你喜欢

转载自blog.csdn.net/it_freshman/article/details/74001648