一、什么是流stream
1.可理解为高级版本的 Iterator
不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的。
2.单向,不可往复
数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。
3.可并行化操作
迭代器:只能命令式地、串行化操作。当使用串行方式去遍历时,每个 item 读完后再读下一个 item。和迭代器不同,stream使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。
4.数据源本身可以是无限的
二、流的构成
1.构成的三个步骤
a.获取一个数据源(source)
b.数据转换
c.执行操作获取想要的结果。<每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道>。如下图所示:
eg:Student<id, name> List<Student> students = Lists.newArrayList(new Student(1, "学生1"), new Student(2, "学生2"), new Student(3, "学生3")); --- Source Stream<Student> studentStream = students.stream(); --- Stream Stream<Long> idStream = studentStream.map(student -> student.getId); --- Transforming List<Long> ids = idStream.collect(Collectors.toList()); --- Operations
三、流的常见3种方法
- Collection.stream()
- Collection.parallelStream()
- Arrays.stream(T array) or Stream.of()
- Stream.generate(Supplier<T> s)。<创建无限流,不常用>
// 1. Individual values
Stream stream = Stream.of("a", "b", "c");
// 2. Arrays
String [] strArray = new String[] {"a", "b", "c"};
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
// 3. Collections
List<String> list = Arrays.asList(strArray);
stream = list.stream();
四、基本类型的流的构造
三种对应的包装类型 Stream。
IntStream、LongStream、DoubleStream
或者
Stream<Integer>、Stream<Long>、Stream<Double>
eg:
IntStream.of(new int[]{1, 2, 3}).forEach(System.out::println);
IntStream.range(1, 3).forEach(System.out::println);
IntStream.rangeClosed(1, 3).forEach(System.out::println);
五、流转换为其它数据结构
// 1. Array
String[] strArray1 = stream.toArray(String[]::new);
// 2. Collection
List<String> list1 = stream.collect(Collectors.toList());
List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
Set set1 = stream.collect(Collectors.toSet());
Stack stack1 = stream.collect(Collectors.toCollection(Stack::new));
// 3. String
String str = stream.collect(Collectors.joining()).toString();
六、流的操作
- Intermediate:
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
- Terminal:
forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
- Short-circuiting:
anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit
七、典型用法
1.map:
map 生成的是个 1:1 映射,每个输入元素,都按照规则转换成为另外一个元素。作用:对流中的每一个元素进行操作。
1. 转换大写
List<String> output = wordList.stream().
map(String::toUpperCase).
collect(Collectors.toList());
说明:这段代码把每个单词转换为大写。
2. 平方数
List<Integer> nums = Arrays.asList(1, 2, 3, 4);
List<Integer> squareNums = nums.stream().
map(n -> n * n).
collect(Collectors.toList());
2.filter:
注意:这里要注意的是“过滤出”,而不是“过滤”,这是两个不同的意思!
1.留下偶数
Integer[] sixNums = {1, 2, 3, 4, 5, 6};
Integer[] evens = Stream.of(sixNums).filter(n -> n%2 == 0).toArray(Integer[]::new);
注意:stream也是可以foreach的,没必要一定要转化成集合再foreach
3.forEach
作用:对stream中的每一个元素做聚合操作。
List<Integer> numbers = Lists.newArrayList(1, 2, 3, 4);
System.out.println(numbers.stream().mapToInt(Integer::intValue).sum()); --输出10
4.reduce
作用:对stream中的每一个元素做聚合操作。
Stream<Integer> reduceStream = Stream.of(1,2,3,4,5);
Optional<Integer> sumOption = reduceStream.reduce((x,y)->x+y);//计算1+2+3+4+5,即对元素中的元素进行聚合计算,而map是对元素中的每一个元素分别计算(注意:如果stream为null的话,就会产生无效的结果,需要使用Optional接收)
//Optional<Integer> sumOption = reduceStream.reduce(Integer::sum);//计算1+2+3+4+5,即对元素中的元素进行聚合计算,而map是对元素中的每一个元素分别计算
Integer result = reduceStream.reduce(0, Integer::sum);//0为标识值,即计算:0+1+2+。。+5,如果整个stream为null,就返回标识值。
System.out.println(result);
注意:以上是reduce的简单形式,即内联函数是(T,T)->T,即返回值和参数类型是一样的,返回值和参数类型不同的场景需要自己编写函数(用的较少)
5、Optional两种用法:
ifPresent(xxx):存在的就执行xxx,不存在就什么都不执行
orElse(xxx):存在就返回存在的值,不存在就返回xxx(可以理解为是默认值)
Stream<String> optionalStream = Stream.of("java","python","basic");
Optional<String> optionValue = optionalStream.filter(str->str.startsWith("p")).findFirst();
optionValue.ifPresent(str->System.out.println(str));//if optionalValue为true,即str存在,则输出str,当然也可以使用如下
String str = optionValue.orElse("xxx");//如果optionValue为false,即不存在以p开头的字符串时,使用"xxx"来替代
System.out.println(str);
5、limit skip contact1、limit(long size)作用:截取stream的前size个元素。
Stream<String> streamSelf = Stream.of("python","basic","php");
streamSelf.limit(2).forEach(System.out::println);//截取前两个
2、skip(long size)作用:跳过stream的钱size个元素
Stream<String> streamSelf = Stream.of("python","basic","php");
streamSelf.skip(2).forEach(System.out::println);//跳过前两个
3、contact(Stream<T>,Stream<T>)作用:拼接两个stream
Stream<String> streamSelf = Stream.of("python","basic","php");
Stream<String> streamSelf2 = Stream.of("python2","basic2","php2");
Stream.concat(streamSelf, streamSelf2).forEach(System.out::println);
6.聚合函数
count max min findFirst findAny anyMatch allMatch noneMatch
Stream<String> streamSelf = Stream.of("python","basic","php","b");
System.out.println(streamSelf.count());//计算流中的元素个数
Optional<String> largest = streamSelf.max(String::compareToIgnoreCase);//寻找最大值
if(largest.isPresent()){
System.out.println(largest.get());
}
说明:min函数也一样。注意:Optional的使用,上边的是最差的一种形式,见"六"。
Optional<String> firstMatch = streamSelf.filter(str->str.startsWith("b")).findFirst();//寻找第一个符合条件的元素
firstMatch.ifPresent(System.out::println);//这是Optional的第一种用法
Optional<String> anyMatch = streamSelf.parallel().filter(str->str.startsWith("b")).findAny();//返回集合中符合条件的任意一个元素,对于并行处理非常好(因为多个线程只要有一个线程找到了,整个计算就会结束)
if(anyMatch.isPresent()){
System.out.println(anyMatch.get());//这里的结果可能是b,有可能是basic
}
boolean isAnyMatch = streamSelf.parallel().anyMatch(str->str.startsWith("c"));//集合中是否有一个满足条件
System.out.println(isAnyMatch);
Stream<String> streamSelf3 = Stream.of("basic","b");
boolean isAllMatch = streamSelf3.parallel().allMatch(str->str.startsWith("b"));//集合中是否所有元素都满足条件
System.out.println(isAllMatch);
boolean isAllNotMatch = streamSelf.parallel().noneMatch(str->str.startsWith("p"));//集合中是否没有一个元素满足条件
System.out.println(isAllNotMatch);
注意:
optional的最佳用法:ifPresent()-->如果有就输出,如果没有,什么都不做
parallel():将stream转为并行流,并行流的使用一定要注意线程安全
七、java8 :: 用法 (JDK8 双冒号用法)
就是把方法当做参数传到stream内部,使stream的每个元素都传入到该方法里面执行一下。
尽量用::去代替->,培养良好的代码习惯。
双冒号运算就是Java中的[方法引用],[方法引用]的格式是:
类名::方法名
注意,没有()号。
案例:
使用前:
person -> person.getAge();
使用双冒号后:
Person::getAge 使用前:
new HashMap<>()
使用双冒号后:
HsahMap :: new 使用前:
MyTest.printValur(x));
使用双冒号后:
MyTest :: printValur
参考链接
Streams API详解
https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/
Stream API
https://www.cnblogs.com/sunny3096/p/7159521.html