Stream
标签:Java基础

Stream

流 是 "从 支 持 数 据 处 理 操 作 的 源 生 成 的 一 系 列 元 素 " 。

  • 流利用内部迭代:迭 代 通 过 filter、map、sorted 等操作被抽象掉了 。
  • 流操作有两类 : 中间操作和终端操作。
  • filter和map等中间操作会返回一个流,并可以链接在一起 。可以用它们来设置一条流水线,但并不会生成任何结果。
  • forEach和 count等终端操作会返回一个非流的,并处理流水线以返回结果。
  • 流中的元素是按需计算的 。

1. 使用流

1.1 筛选和切片

numbers.stream().filter(i -> i%2==0).distinct().forEach(System.out.println());
numbers.stream().limit(3).collect(toList);
numbers.stream().skip(3).collect(toList);

1.2 映射

menu.stream().map(Dish::getName).collect(toList);
// words={"hello","world"}
words.stream().map(w->w.split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList);

1.3 查找和匹配

上面这三个方法都使用到了Java中的短路操作。

1.4 归约

元素求和:

int sum=numbers.stream().reduce(0,(a,b)->a+b);
//或者
int sum=numbers.stream().reduce(0,Integer::sum);

最大值,最小值

int sum=numbers.stream().reduce(0,Integer::max);
int sum=numbers.stream().reduce(0,Integer::min);

1.5 其他

2. 生成流

2.1 由值创建(Stream.of)

Stream<String> stream = Stream.of("sadffd", "sfdf", "asfsdfd");
stream.map(String::toUpperCase).forEach(System.out::println);

2.2 由数组创建(Arrays.stream)

int[] numbers = {1, 2, 3,4,54,5};
int sum=Arrays.stream(numbers).sum();
System.out.println(sum);

2.3 由文件创建(Files.lines)

long uniqueWords=0;
try(Stream<String> lines= Files.lines(Paths.get("E:\\06\\Projects\\Java8\\src\\stream\\data.txt"), Charset.defaultCharset())){
            uniqueWords=lines.flatMap(line -> Arrays.stream(line.split(" "))).distinct().count();
}catch (IOException e){
    System.out.println(e);
}
System.out.println(uniqueWords);

2.4 由函数生成

迭代

Stream.iterate(0,n->n+2).limit(10).forEach(System.out::println); // 取10个偶数
Stream.iterate(new int[]{0,1},t->new int[]{t[1],t[0]+t[1]}).limit(20).forEach(t->System.out.println(t[0]+","+t[1])); //去前20个斐波拉契数

生成

Stream.generate(Math::random).limit(5).forEach(System.out::println);//随机取得5个0到1之间的数

3. 收集器

3.1 归约与汇总

写声明Dish类:

public class Dish {

    private final String name;
    private final boolean vegetarian;
    private final int calories;
    private final Type type;
    
    // getter and setter ...
    
    public static final List<Dish> menu =
            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, 400, Dish.Type.FISH),
                    new Dish("salmon", false, 450, Dish.Type.FISH));
}

下面这些代码,需要默认先导入 import static java.util.stream.Collectors.*;

reduce和collect方法区别:

  1. reduce方法旨在把两个值结合起来生成一个新值,是一个不可变的归约;而collect方法的设计就是要改变容器,从而累计要输出的结果。
  2. 使用reduce方法这个归约操作是不能并行工作的,因为如果多个线程同时修改一个数据结构将会破坏List的本身。要想不产生线程安全问题,将会每次分配一个新的List,而分配又会导致性能问题。故采用collect来处理这种可变容器的归约,collect更适合并行操作。
  • 6 min read

CONTRIBUTORS


  • 6 min read