1 前言
1.1 对Stream流的个人理解:
- 它和IO流是不一样的;
- 它是对数据源(集合,数组等)进行一系列的中间操作,产生一个新的流或者说我们想要的结果,并且对数据源不产生影响。
- 集合讲的是数据,流讲的是计算。
1.2Stream流操作的三个步骤
- 创建Stream
- 中间操作:对数据源数据进行处理
- 终端操作:执行中间操作,并产生结果
注意: 从终端操作可以看出stream流是延迟执行的,只有执行终端操作(想要需要的结果)的时候才执行中间操作
2 下面我们对Stream的三个步骤一一说明
2.1创建Stream
/**
* 创建流
*/
@Test
public void test01(){
/**
* 集合流
* - Collection.stream() 穿行流
* - Collection.parallelStream() 并行流
*/
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//数组流
//Arrays.stream(array)
String[] strings = new String[10];
Stream<String> stream2 = Arrays.stream(strings);
//Stream 静态方法
//Stream.of(...)
Stream<Integer> stream3 = Stream.of(1, 2, 3);
//无限流
//迭代
Stream<Integer> stream4 = Stream.iterate(0, (i) -> ++i+i++);
stream4.forEach(System.out::println);
//生成
Stream.generate(() -> Math.random())
.limit(5)
.forEach(System.out::println);
}
2.2中间操作
创建一个list集合,这个集合只是下面例子中用,方便区别各API的用途,可不要误会
List<Employee> emps = Arrays.asList(
new Employee(101, "Z3", 19, 9999.99),
new Employee(102, "L4", 20, 7777.77),
new Employee(103, "W5", 35, 6666.66),
new Employee(104, "Tom", 44, 1111.11),
new Employee(105, "Jerry", 60, 4444.44)
new Employee(105, "Jerry", 60, 4444.44)
);
- filter:接收 Lambda ,从流中排除某些元素
@Test
public void test2() {
emps.stream()
.filter((emp)->emp.getAge()>20)
.forEach(System.out::println);
}
//输出
Employee(id=103, name=W5, age=35, salary=6666.66)
Employee(id=104, name=Tom, age=44, salary=1111.11)
Employee(id=105, name=Jerry, age=60, salary=4444.44)
Employee(id=105, name=Jerry, age=60, salary=4444.44)
- limit:截断流,使其元素不超过给定数量
@Test
public void test2() {
emps.stream()
.filter((emp)->emp.getAge()>20)
.limit(2)
.forEach(System.out::println);
}
//输出
Employee(id=103, name=W5, age=35, salary=6666.66)
Employee(id=104, name=Tom, age=44, salary=1111.11)
- skip(n):跳过元素,返回一个舍弃了前n个元素的流;若流中元素不足n个,则返回一个空流;与 limit(n) 互补
@Test
public void test2() {
emps.stream()
.filter((emp)->emp.getAge()>20)
.limit(2)
.skip(1)
.forEach(System.out::println);
}
//输出
Employee(id=104, name=Tom, age=44, salary=1111.11)
- distinct:筛选,通过流所生成的 hashCode() 与 equals() 取除重复元素
@Test
public void test2() {
emps.stream()
.filter((emp)->emp.getAge()>20)
.distinct()
.forEach(System.out::println);
}
//输出
Employee(id=103, name=W5, age=35, salary=6666.66)
Employee(id=104, name=Tom, age=44, salary=1111.11)
Employee(id=105, name=Jerry, age=60, salary=4444.44)
- map:接收 Lambda ,将元素转换为其他形式或提取信息;接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
@Test
public void test2() {
emps.stream()
.map((emp)->emp.getAge())
.forEach(System.out::println);
}
//输出 19 20 35 44 60 60
-
flatMap(难点):接收一个函数作为参数,将流中每一个值都换成另一个流,然后把所有流重新连接成一个流,可以看做是两层for循环
-
个人理解:与map()可以看做是一层for循环,flatMap()可以看做是两层for循环
-
例如下面例子(将两个集合合并为一个集合)
-
flatMap()操作的一个作用就是将两个集合合并为一个集合,相当于join操作,若没有filter操作,会产生笛卡尔积现象。
//例子中boys和stus分别是boy对象集合和stu对象集合
List<String> collect = boys.stream().flatMap(b -> stus.stream().
//第二层for循环中处理数据
filter(s -> b.getName().equals(s.getName())).
//将数据放入到一个新的集合中
map(Student::getName)
//结束第二层循环
).collect(Collectors.toList());
//等效于
List<String> data=new ArrayList<>();
//双层for循环处理数据
for (Boy boy : boys) {
for (Student student : stus) {
//filter条件
if(boy.getName().equals(student.getName())){
//map子句,将元素放入到新集合中
data.add(student.getName());
}
}
}
//参考网址https://www.jianshu.com/p/279967ceb45f
- sorted():自然排序
SortList.java
package com.concretepage;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class SortList {
public static void main(String[] args) {
List<Student> list = new ArrayList<Student>();
list.add(new Student(1, "Mahesh", 12));
list.add(new Student(2, "Suresh", 15));
list.add(new Student(3, "Nilesh", 10));
System.out.println("---Natural Sorting by Name---");
List<Student> slist = list.stream().sorted().collect(Collectors.toList());
slist.forEach(e -> System.out.println("Id:"+ e.getId()+", Name: "+e.getName()+", Age:"+e.getAge()));
System.out.println("---Natural Sorting by Name in reverse order---");
slist = list.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
slist.forEach(e -> System.out.println("Id:"+ e.getId()+", Name: "+e.getName()+", Age:"+e.getAge()));
System.out.println("---Sorting using Comparator by Age---");
slist = list.stream().sorted(Comparator.comparing(Student::getAge)).collect(Collectors.toList());
slist.forEach(e -> System.out.println("Id:"+ e.getId()+", Name: "+e.getName()+", Age:"+e.getAge()));
System.out.println("---Sorting using Comparator by Age with reverse order---");
slist = list.stream().sorted(Comparator.comparing(Student::getAge).reversed()).collect(Collectors.toList());
slist.forEach(e -> System.out.println("Id:"+ e.getId()+", Name: "+e.getName()+", Age:"+e.getAge()));
}
}
Output *
—Natural Sorting by Name—
Id:1, Name: Mahesh, Age:12
Id:3, Name: Nilesh, Age:10
Id:2, Name: Suresh, Age:15
—Natural Sorting by Name in reverse order—
Id:2, Name: Suresh, Age:15
Id:3, Name: Nilesh, Age:10
Id:1, Name: Mahesh, Age:12
—Sorting using Comparator by Age—
Id:3, Name: Nilesh, Age:10
Id:1, Name: Mahesh, Age:12
Id:2, Name: Suresh, Age:15
—Sorting using Comparator by Age with reverse order—
Id:2, Name: Suresh, Age:15
Id:1, Name: Mahesh, Age:12
Id:3, Name: Nilesh, Age:10
- sorted(Comparator c):定制排序
@Test
public void test2() {
emps.stream()
.sorted((e1,e2)->{
if (e1.getAge().equals(e2.getAge())){
return e1.getName().compareTo(e2.getName());
} else {
return e1.getAge().compareTo(e2.getAge());
}
})
.limit(2)
.forEach(System.out::println);
}
//输出
Employee(id=101, name=Z3, age=19, salary=9999.99)
Employee(id=102, name=L4, age=20, salary=7777.77)
2.3 终端操作(中间操作可以几个中间操作API连用,而终端操作不能几个终端操作API连用,只能用一个)
- forEach(): 遍历输出
@Test
public void test2() {
emps.stream()
.map((emp)->emp.getAge())
.forEach(System.out::println);
}
//输出 19 20 35 44 60 60
- allMatch:检查是否匹配所有元素
@Test
public void test2() {
boolean b = emps.stream()
.allMatch(e -> e.getAge() == 19);
System.out.println(b);//不可以使用forEach(System.out::println);,因为allMatch(e -> e.getAge() == 19);属于终端操作
//输出flase
}
- allMatch:检查是否匹配所有元素
- anyMatch:检查是否至少匹配一个元素
- noneMatch:检查是否没有匹配所有元素
- findFirst:返回第一个元素
- findAny:返回当前流中的任意元素
- count:返回流中元素的总个数
- max:返回流中最大值
- min:返回流中最小值
- reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以将流中的数据反复结合起来,得到一个值
/**
* Java:
* - reduce:需提供默认值(初始值)
*/
@Test
public void test01(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
Integer integer = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(integer);
}
- collect:将流转换成其他形式(如利用Collectors转化为list,set,map等好多常用API)
@Test
public void test2() {
//转list集合
List<String> collect = emps.stream()
.map(employee -> employee.getName())
.collect(Collectors.toList());
System.out.println(collect);
//输出 [Z3, L4, W5, Tom, Jerry, Jerry]
}
//转map集合
@Test
public void test2() {
Map<Integer, List<Employee>> collect = emps.stream()
.collect(Collectors.groupingBy(Employee::getId));
System.out.println(collect);
}
//输出(从输出可以看出,应该先去重,再转换)
{101=[Employee(id=101, name=Z3, age=19, salary=9999.99)],
102=[Employee(id=102, name=L4, age=20, salary=7777.77)],
103=[Employee(id=103, name=W5, age=35, salary=6666.66)],
104=[Employee(id=104, name=Tom, age=44, salary=1111.11)],
105=[Employee(id=105, name=Jerry, age=60, salary=4444.44), Employee(id=105, name=Jerry, age=60, salary=4444.44)]}
//总结
@Test
public void test2() {
//总结
DoubleSummaryStatistics dss = emps.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println( dss);
System.out.println(dss.getMax());
System.out.println(dss.getMin());
System.out.println(dss.getSum());
System.out.println(dss.getCount());
System.out.println(dss.getAverage());
}
//输出
DoubleSummaryStatistics{count=6, sum=34444.410000, min=1111.110000, average=5740.735000, max=9999.990000}
9999.99
1111.11
34444.409999999996
6
5740.735
//其他API
@Test
public void test02(){
//放入Set
Set<String> set = emps.stream()
.map(Employee::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);
//放入LinkedHashSet
LinkedHashSet<String> linkedHashSet = emps.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(LinkedHashSet::new));
linkedHashSet.forEach(System.out::println);
}
@Test
public void test03(){
//总数
Long count = emps.stream()
.collect(Collectors.counting());
System.out.println(count);
//平均值
Double avg = emps.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avg);
//总和
Double sum = emps.stream()
.collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sum);
//最大值
Optional<Employee> max = emps.stream()
.collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(max.get());
//最小值
Optional<Double> min = emps.stream()
.map(Employee::getSalary)
.collect(Collectors.minBy(Double::compare));
System.out.println(min.get());
}
@Test
public void test04(){
//分组
Map<Integer, List<Employee>> map = emps.stream()
.collect(Collectors.groupingBy(Employee::getId));
System.out.println(map);
//多级分组
Map<Integer, Map<String, List<Employee>>> mapMap = emps.stream()
.collect(Collectors.groupingBy(Employee::getId, Collectors.groupingBy((e) -> {
if (e.getAge() > 35) {
return "开除";
} else {
return "继续加班";
}
})));
System.out.println(mapMap);
//分区
Map<Boolean, List<Employee>> listMap = emps.stream()
.collect(Collectors.partitioningBy((e) -> e.getSalary() > 4321));
System.out.println(listMap);
}
@Test
public void test05(){
//总结
DoubleSummaryStatistics dss = emps.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getMax());
System.out.println(dss.getMin());
System.out.println(dss.getSum());
System.out.println(dss.getCount());
System.out.println(dss.getAverage());
//连接
String str = emps.stream()
.map(Employee::getName)
.collect(Collectors.joining("-")); //可传入分隔符
System.out.println(str);
}
- 完结