Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
Stream和Collection集合的区别:Collection是一种静态的内存数据结构,讲的是数据,而Stream是有关计算的,讲的是计算。集合主要面向内存,储存在内存中。Stream主要面向CPU,通过CPU实现计算。
Stream API关注的是多个数据的计算(排序、查找、过滤、映射、遍历等)。
集合关注的是数据的存储。
Stream自己不会存储元素。
Stream不会改变源对象,而是会返回一个持有结果的新的Stream。
Stream操作是延迟执行的。要等到需要的结果的时候才执行。一旦执行终止操作,就执行中间操作,并产生结果。
Stream一旦执行了终止操作,就不能再调用其他中间操作或终止操作了。
List list = new ArrayList<>();
list.add(new Person(19,"limingmao"));
list.add(new Person(17,"qiuqiuren"));
list.add(new Person(18,"pianpianhua"));
//default Stream Stream():返回一个顺序流
Stream stream = list.stream();
//default Stream Stream():返回一个并行流
Stream stream1 = list.parallelStream();
//调用Arrays类的static Stream stream(T[] array):返回一个流
Integer[] arr = new Integer[]{1,3,4,5,6,7,};
Stream stream = Arrays.stream(arr);
int[] arr1 = new int[]{1,2,3,4,5};
IntStream stream1 = Arrays.stream(arr1);
//通过Stream的静态方法of()
Stream stringStream = Stream.of("aa", "bb", "cc", "DD");
filter(Predicate p):接受lambda,从流中排除某些元素。
limit(n):截断流,使得元素不超过指定量。
skip(n):跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。
distinct( ):筛选,通过流所生成元素的hashCode( )和equals( )去除重复元素。
map(Function f):接收一个函数作为参数,将元素转换为其他形式或提取信息,该函数会被应用到每一个元素上。
操作,例:
List list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
list.add("dd");
Stream stream = list.stream();
stream.map(str -> str.toUpperCase());
sorted( ):自然排序。要求类实现Comparable接口。
sorted(Comparator com):定制排序,参数传入实现Comparator接口的对象,指定排序方式。
终止操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如,List、Integer,也可以是void。
流进行了终止操作后不能再次使用。
allMatch(Predicate p):检查是否匹配所有元素。
anyMatch(Predicate p):检查是否至少匹配一个元素。
findFirst( ):返回第一个元素。
count( ):返回元素中的总个数。
max(Comparator c):返回流中的最大值。
min(Comparator c):返回流中的最小值。
forEach(Consumer c):内部迭代。
reduce(T identity,BinaryOperator):可以将流中的元素反复结合起来,得到一个值。
reduce(BinaryOperator):可以将流中的元素反复结合起来,得到一个值。
collection(Collection c):将流转换为其他形式。接收一个Collection接口的实现,用于给Stream中元素做汇总的方法。
Stream的使用中会用到较多的接口哦,使用Lambda表达式和方法引用的方式会更方便。
以两个例子为例
例一,比如:要打印出存放Person的对象的集合list里的对象的年龄的总和
System.out.println(list.stream().map(Person::getAge).reduce(Integer::sum));
map方法的参数中放的是一个Function的实现类对象,此时应用到每一个元素上的操作是调用每一个Person对象的getAge方法得到每一个对象的年龄,apply方法的参数是一个Person类的对象A,apply方法中,A调用了getAge方法,而getAge方法没有参数,满足方法n和n - 1的关系,可以使用方法引用的类 :: 实例方法 的方式表示,即为 Person :: getAge 。reduce方法中同理。
例二,比如:要打印所有大于十七岁的Person对象的信息
stream.filter(emp -> emp.getAge() > 17).forEach(System.out::println);
filter方法的参数中放的是一个Predicate的实现类对象,只有一个参数,所以->左边放一个变量,返回值是一个boolean类型的值,只有一条return语句,所以直接将return后面的emp.getAge( ) > 17放在->后面,便形成了lambda表达式。
forEach方法中放入的是一个Consumer的实现类对象,accept方法的返回值(类型推断后)与System.out对象调用的Println方法的返回值一致。便可以使用方法引用的方式,表示为System.out :: println 。