0%

java8-使用流

流介绍

流是java API的新成员,他允许你以声明的方式处理数据集合(通过查询语句,而不是临时编写一个实现)

使用流

集合是流最容易上手的方式,Java8 中的集合支持一个新的stream方法,他会放回一个流对象(接口定义在java.util.stream.Stream)中

使用流可以完成什么事?他可以让我们以一种流水线的方法处理集合数据

像我们前面处理苹果集合时那样,可以实现一个方法来收集或处理某些数据,比如过滤颜色不是红色的苹果,收集苹果的重量列表,但是每一次都需要调用一个方法,流为我们处理这种“一系列”数据提供了一些方法,可以像工厂流水线的方法对流数据进行处理

比如要收集颜色是红色苹果的重量集合,可以想这样写

inventory.stream().filter(apple -> apple.getColor().equals("red")).map(Apple::getWeight).forEach(System.out::println);

这里先通过方法stream()生成一个流对象,再使用filter方法过滤掉颜色不是红色的苹果,接着通过map将所有颜色是红色的苹果的重量返回成一个数值流也就是剩下苹果重量的集合,接着调用forEach方法打印剩下苹果的重量。可以读作先过滤掉颜色不是红色的苹果,接着返回所有苹果重量的集合,然后打印
如果使用上一节自定义方法实现这些操作书写格式如下:

inventory = filter(inventory,apple -> apple.getColor().equals("red"));
List<Integer> weights = map(inventory,Apple::getWeight);
forEach(weights, System.out::println);

可以看见流的可读性以及书写性都要高于自定义实现

流方法

流的方法分为两类,一类是中间操作,一类是终端操作,中间操作是对流完成操作之后还会返回一个流对象,而终端操作的返回结果是任何不是流的值,前面的filter,map就是中间操作,forEach就是终端操作

使用流方法对苹果库存进行操作

  1. 使用forEach打印数据

    inventory.stream().forEach(System.out::println);
    
  2. 筛选颜色为红色的苹果

    inventory.stream().filter(apple -> apple.getColor().equals("red")).forEach(System.out::println);
    
  3. 对苹果颜色进行排序,如果个颜色相同,根据重量大小由小到大排序

    Comparator<Apple> colorSort = (a1,a2) -> a1.getColor().compareTo(a2.getColor());
    Comparator<Apple> weightSort = (a1,a2) -> a1.getWeight() - a2.getWeight();
    inventory.stream().sorted(colorSort.thenComparing(weightSort)).forEach(System.out::println);
    
  4. 去除颜色和重量相同的苹果

    inventory.stream().distinct().forEach(System.out::println);
    
  5. 只获取前三个苹果

    inventory.stream().limit(3).forEach(System.out::println);
    
  6. 跳过前面两个苹果,只获取后面三个

    inventory.stream().skip(2).forEach(System.out::println);
    
  7. 不要第一个苹果也不要最后一个苹果

    inventory.stream().skip(1).limit(inventory.size() - 2).forEach(System.out::println);
    
  8. 将所有苹果的重量加10

    inventory.stream().peek(apple -> apple.setWeight(apple.getWeight() + 10)).forEach(System.out::println);
    
  9. 查看有没有重量是20,颜色是红色的苹果

    System.out.println(inventory.stream().anyMatch(apple -> apple.getColor().equals("red")));
    
  10. 查看是不是所有苹果的重量是20,颜色是红色

    System.out.println(inventory.stream().allMatch(apple -> apple.getColor().equals("red")));
    
  11. 查看是不是没有苹果是红色的

    System.out.println(inventory.stream().noneMatch(apple -> apple.getColor().equals("red")));
    
  12. 查看第一个苹果

    System.out.println(inventory.stream().findFirst());
    
  13. 返回苹果的总重量

    System.out.println(inventory.stream().map(Apple::getWeight).reduce(0, (a,b) -> (a + b)));
    
  14. 返回苹果的最小重量

    System.out.println(inventory.stream().map(Apple::getWeight).min((n1,n2) -> n1 - n2));
    
  15. 返回苹果的最大重量

    System.out.println(inventory.stream().map(Apple::getWeight).max((n1,n2) -> n1 - n2));
    

流的终端操作

    方法                                                                                                            作用
boolean allMatch(Predicate<? super T> predicate)                                                    如果流对象都可以匹配谓词,返回true,否则返回false
boolean anyMatch(Predicate<? super T> predicate)                                                    如果流对象中有一个或多个匹配谓词,返回true,否则返回false
boolean noneMatch(Predicate<? super T> predicate)                                                    如果流对象中任何一个都没有匹配谓词,返回true,否则返回false
Optional<T> max(Comparator<? super T> comparator)                                                    自定义比较方法,返回流对象中比较方法比较出来的最大值
Oprional<T> min(Comparator<? super T> comparator)                                                    自定义比较方法,返回流对象中比较方法比较出来的最小值
Optional<T> findAny()                                                                                未知
Optional<T> findFirst()                                                                                返回流对象中的第一个值
long count()                                                                                        返回流中数据的个数
<R,A> R collect(Collecotr<? super T,A,R> collector)                                                    未知
<R> R collecot(Supplier<R> supplier,BiConsumer<R,? super T> accumulator,BiConsumer<R,R> combiner)    未知
void forEach(Consumer<? super T> action)                                                            未知
void forEachOrDered(Consumer<? super T> action)                                                        未知
Oprional<T> reduce<T identity,BinaryOperator<T> accumulator)                                        未知
<U> U reduce(U identity,BiFunction<U,? super T,U> accumulator,BinaryOperator<U> combiner)            未知
Object[] toArray()                                                                                    未知
<A> A[] toArray(IntFunction<A[]> generator)                                                            未知

流的中间操作

        方法                                                                                                            作用
    distinct()                                                            去重,流中的对象需要实现equlas方法
    filter(Predicate<? super T> predicate)                                按照规则过滤,满足规则的留下,不满足的去掉
    limit(long maxSize)                                                    返回数据的最大个数,10表示返回10个数据,5表示返回5个
    map(Function<? super T,? extends R> mapper)                            将每个流对象作为函数的参数,并且将返回值填充流对象
    flatMap(Function<? super T,? extends Stream<? extends R>> mapper)    将每个流对象作为函数的参数,但是只返回一个流对象    
    peek(Consumer<? super T> action)                                    可以在流处理时对每个流数据进行操作,并返回Stream对象
    skip(long n)                                                        跳过n个数据,n等于10,表示跳过前面10个数据,和limit方法一起使用效果更好
    sorted()                                                            默认排序,排序类需要实现默认排序接口
    sorted(Comparator<? super T> comparator)                            使用自定义排序对流数据进行排序
值得注意的是flatMap方法,这个方法和map方法不同,map方法会将每一个流对象都作用于Function<? super T,? extends R>返回一个R对象,flatMap方法也会将所有的流对象作用于Function的方法,但是只会返回一个`流对象`,这个方法可以用作一个流中的对象的属性是集合,并且需要将所有流对象为集合的属性收集起来的情况,比如收集几个字符串中所有不重复的字符。