Java SE Stream流
目录
Java8 API添加了一个新的抽象称为流 Stream ,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对Java 集合运算和表达的高阶抽象。
Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。
1、定义
对数据源中的数据,进行运行|计算的元素序列。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminaloperation)得到前面处理的结果。
Stream(流)是一个来自数据源的元素队列并支持聚合操作
- 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源 流的来源。 可以是集合,数组等。
- 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
注意:
- 数组|集合可以作为存储数据的数据源,stream不能存储数据,只能对数据源中的数据进行计算,得到新的结果,得到一个新的stream
- stream不会影响数据源中的数据
- 流是一次性的流,使用过一次以后不能再次使用,每次会得到一个新的流
- stream流特点: 延迟执行|惰性加载 : 进行一些列中见操作的时候,如果没有进行终止行为,就不会执行中间操作,会在进行终止行为的时候统一执行
2、Stream的操作三个步骤
1、创建Stream
一个数据源(如:集合、数组),获取一个流
2、中间操作
一个中间操作链,对数据源的数据进行处理
3、终止操作
一个终止操作,执行中间操作链,并产生结果
2.1、创建Stream
使用步骤:
- 1.根据数据源获取流
- 2.一些列流式的中间操作
- 3.终止行为
注意:
- 1、Stream自己不会存储元素·
- 2、Stream不会改变源对象。相反,会返回一个持有结果的新Stream。
- 3、Stream操作是延迟执行的,这意味着他们会等到需要结果的时候才执行。
/*** StreamAPI三个操作步骤:
* 1、创建Stream *
2、中间操作 *
3、终止操作
*/
//1.Arrays.stream(数组)
int[] arr = {1,2,3,4,5,6};
IntStream stream1 = Arrays.stream(arr);
//2.Collection的实现类 stream()
List<String> ls = List.of("aaa","bbb","ccc");
Stream<String> stream2 = ls.stream();
//parallelStream 并行流
stream2 = ls.parallelStream();
//3.Stream.of(数据1,数据2,数据3)
Stream<Integer> s = Stream.of(1,2,3,4,5);
//终止行为
stream1.forEach(System.out::println);
stream2.forEach(System.out::println);
s.forEach(System.out::println);
2.2、中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理,而在终止操作时一次性全部处理,称为”惰性求值”。
2.2.1、筛选与切片
- filter;过滤
- limit;截断流,使其元素不超过给定数量
- skip;跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流。
- distinct;去重
public static void main(String[] args) {
//
Set<User> list=Set.of(
new User(101,"张三",18),
new User(102,"李四",20),
new User(103,"王五",30),
new User(104,"赵六",16),
new User(105,"孙七",20)
);
//获取流
Stream<User> stream = list.stream();
//过滤filter
//条件: 找到年龄》=18随的用户信息
// limit(num)-截断流,使其元素不超过给定数量
skip-跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流。
//distinct 去重 (按照重写hashcode与equals方法相等去重)
stream.filter(user -> {
System.out.println("过滤年龄》=18随的用户信息");
return user.getMoney()>=18;
}).limit(3).skip(1).distinct().forEach(System.out::println);
}
2.2.2 、排序
sorted(Comparable)-自然排序
sorted(Comparator)-定制排序
public static void main(String[] args) {
List<User> lst=List.of(
new User(101,"张三",18),
new User(102,"李四",20),
new User(103,"王五",30),
new User(104,"赵六",16),
new User(105,"孙七",20)
);
Stream<User> stm=lst.stream();
// //默认根据内部比较器排序
stm.sorted().forEach(System.out::println);
//默认根据外部比较器排序
stm.sorted((o1,o2)->Integer.compare(o2.getNo(), o1.getNo())).forEach(System.out::println);
}
2.2.3 map排序(重要)
-
中间操作 map : 把流操作的每一个数据,当作function接口中抽象的参数传递,根据指定的实现行为(lambda)得到一个结果,最终把所有的结果返回一个新的流。
- 如果每一个结果都是一个流,最终会返回一个存放每一个流的一个新的流-》流中存放流
-
flatMap: 作用与map相等,特点中每一个数据必须返回一个流,最终会结合称为一个整个流 --》 流中存放数据
public static void main(String[] args) {
List<User> lst=List.of(
new User(101,"张三",18),
new User(102,"李四",20),
new User(103,"王五",30),
new User(104,"赵六",16),
new User(105,"孙七",20)
);
Stream<User> stm=lst.stream();
//获取所有用户的年龄,然后升序排序 Map
//stm.map(user -> user.getName()).sorted().forEach(System.out::println);
//流中放流
stm.map(user -> {
List<Character> ls=new ArrayList<>();
char[] arr=user.getName().toCharArray();
for (char ch:arr) {
ls.add(ch);
}
return ls.stream();
}).sorted().forEach(System.out::println);
//{{a,b,c},{a,b,d},{a,a,a}}
//flatMap 返回值比逊是个流
stm.flatMap(u->{
List<Character> ls = new ArrayList<>();
char[] arr = u.getName().toCharArray();
for(char ch:arr){
ls.add(ch);
}
return ls.stream();
}).forEach(System.out::println); //{{zhang,san,b,c}
2.3、终止操作
2.3.1、reduce 归约
public static void main(String[] args) {
List<User> list = Arrays.asList(
new User(01 ,"张三", 18),
new User(02 ,"李四", 38),
new User(02 ,"李四", 38),
new User(05 ,"王五", 50),
new User(04 ,"赵六", 16),
new User(03 ,"田七", 28)
);
Stream<User> stream = list.stream();
//Optional<T> reduce(BinaryOperator<T> accumulator)
// 把流操作的前两个数据作为抽象方法的参数,经过运算得到结果,
// 结果作为下一次计算的第一个参数,流操作的下一个数据作为第二个参数,重复,最终得到结果返回
Double sum=stream.map(User::getMoney)
.distinct().sorted()
.reduce((x,y)-> x+y).get();
System.out.println(sum);
// // T reduce(T identity, BinaryOperator<T> accumulator);
// 把第参数100作为抽象方法的第一个参数,流操作的数据作为第二个参数,
// 经过运算得到结果,结果作为下一次计算的第一个参数,流操作的下一个数据作为第二个参数,重复,最终得到结果返回
Double ssum = stream.map(User::getMoney)
.distinct().sorted()
.reduce(1000D,(x,y)->{
System.out.println(x+"-->"+y);
return x+y;
});
System.out.println(ssum);
//了解
//并行流
System.out.println(List.of(1,2,3,4,5).parallelStream()
.reduce(1000,(x,y)->{
System.out.println(Thread.currentThread().getName()+" : "+x+"-->"+y);
return x+y;
},(x,y)->{
System.out.println("结果:"+" : "+x+"-->"+y);
return x+y;
}));
}
2.3.2 查找与匹配
public static void main(String[] args) {
List<User> list = Arrays.asList(
new User(01 ,"张三", 18),
new User(02 ,"李四", 38),
new User(02 ,"李四", 38),
new User(05 ,"王五", 50),
new User(04 ,"赵六", 16),
new User(03 ,"田七", 28)
);
Stream<User> stream = list.stream();
// allMatch-检查是否匹配所有元素
System.out.println(stream.allMatch(u->u.getAge()>=0));;
// noneMatch-检查是否没有匹配所有元素
// findFirst-返回第一个元素
// findAny-返回当前流中的任意元素
// count-返回流中元素的总个数
// max-返回流中最大值
// 需求:获取工资最高的员工信息
System.out.println(stream.max((x,y)->x.getAge()-y.getAge()).get());;
//收集所有用户的姓名,返回一个存储姓名的集合
/* List<String> names = stream.map(User::getName).collect(Collectors.toList());
System.out.println(names);*/
//自动去重
System.out.println(stream.map(User::getName).collect(Collectors.toSet()));
//手动去重
Map<Integer,String> map = stream.distinct().collect(Collectors.toMap(User::getId,User::getName));
System.out.println(map);
}
2.3.3、收集(了解)
收集-将流转换为其他形式,接收一个Collertor接口的实现,用于给Stream中元素做汇总的方法
// 需求:获取当前公司所有员工的姓名添加到集合中
// List-把流中所有元素收集到List中
List<String> list = emps.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
// Set-把流中所有元素收集到Set中,删除重复项
Set<String> set = emps.stream()
.map(Employee::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);
// Map-把流中所有元素收集到Map中,当出现相同的key时会抛异常
Map<String, Integer> map = emps.stream()
.collect(Collectors.toMap(Employee::getName, Employee::getAge));
System.out.println(map);