java8新特性之stream流
Stream 流是 Java 8 提供给开发者一套新的处理集合的API,他把我们将要处理的集合作为流,就像流水线一样,我们可以对其中的元素进行筛选,过滤,排序等中间操作,只不过这种操作更加简洁高效。
Stream的创建:
- 1.可以通过Collection系列的集合提供的stream()或者parallelStream()方法,集合的stream方法创建的是串行流,parallelStream方法创建的是并行流(并行流就是多线程进行操作,这个时候就要考虑线程安全问题了)
- 2.可以通过Arrays.stream()获取数组流
- 3.通过Stream类中的静态方法of()可以创建流对象
- 当创建一个无限流使用Stream.iterate()方法,是一个死循环
//Stream 的创建
//1.通过集合的stream()方法创建串行流
ArrayList<Object> list = new ArrayList<>();
Stream<Object> stream = list.stream();
//2.也可以通过集合的parallelStream创建并行流
Stream<Object> parallelStream = list.parallelStream();
//3.通过Arrays.stream(T[] t),将数组转换成流
IntStream stream1 = Arrays.stream(new int[10]);
//4.通过Stream的静态方法of创建流
Stream<String> stringStream = Stream.of("aaa", "bbb", "ddd", "ccc");
//创建无限流 迭代
Stream<Integer> iterate = Stream.iterate(1, (x) -> x + 2);
iterate.limit(10).forEach(System.out::println);//生成奇数从一开始往后的10位
//生成
Stream.generate(()->(int)(Math.random()*100))//随机生成10个100以内的int类型数
.limit(10)
.forEach(System.out::println);
Stream的中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线线上触发终止操作,否则中间操作就不会执行任何处理,并不会显示处理结果。而在终止操作时一次性全部处理,称为惰性求值。
- 筛选与切片
filter-接收Lambda,从流中排除某些元素
limit–截断流,使其元素不超过给定数量
skip(n) – 跳过元素,返回一个扔掉了前n个元素的流。若流中的元素个数小于n,则返回null,与limit()互补
distinct–筛选通过流所生成元素的hashCode(),equals()方法来去掉重复的元素
public class StreamAPITest {
List<Employee> employees = Arrays.asList(
new Employee("小明", 12000, 32),
new Employee("小红", 8000, 23),
new Employee("小刚", 5000, 19),
new Employee("小凉", 7000, 40),
new Employee("小凉", 7000, 40),
new Employee("小凉", 7000, 40)
);
@Test
public void test2() {
//filter是内部迭代,
//也就是StreamAPI内部实现的迭代不需要使用者再次手写迭代
employees.stream()
.filter((e) -> {
//System.out.println("进入过滤器");
return e.getSalary() > 7000.0;
})
.forEach((e) -> System.out.println(e.getSalary()));
System.out.println("-----------------------");
//测试limit(n)取前n个元素
employees.stream()
.limit(3)
.forEach((e) -> System.out.println(e));
System.out.println("-----------------------");
//skip(n)测试 舍掉前n个元素,去剩下后面的
employees.stream()
.skip(3)
.forEach((e) -> System.out.println(e));
System.out.println("=============================");
//distinct()去除重复,按照streamAPI中的hashCode和equals方法
employees.stream()
.distinct()
.forEach((e) -> System.out.println(e));
}
}
注意:distinct方法去除重复,需要实现pojo的hashCode()和equals().
控制台输出:
12000.0
8000.0
-----------------------
Employee{name='小明', salary=12000.0, age=32}
Employee{name='小红', salary=8000.0, age=23}
Employee{name='小刚', salary=5000.0, age=19}
-----------------------
Employee{name='小凉', salary=7000.0, age=40}
Employee{name='小凉', salary=7000.0, age=40}
Employee{name='小凉', salary=7000.0, age=40}
=============================
Employee{name='小明', salary=12000.0, age=32}
Employee{name='小红', salary=8000.0, age=23}
Employee{name='小刚', salary=5000.0, age=19}
Employee{name='小凉', salary=7000.0, age=40}
映射:
map——接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap——接收一个函数作为参数,将流中的每个值都转换成另一个流,然后把所有流连接成一个流。
public static Stream<Character> getCharacter(String str) {
List<Character> list = new ArrayList<>();
for (Character character : str.toCharArray()) {
list.add(character);
}
return list.stream();
}
@Test
public void test3() {
/**
* map,flapMap
*/
List<String> list = Arrays.asList("cvt", "aer", "ktv", "dbms");
//1.将list中的每个元素都转换成大写
list.stream()
.map((e) -> e.toUpperCase())
.forEach(System.out::println);
System.out.println("------水平分割线---------");
//2.取出employees中的每个员工姓名输出
employees.stream()
.map((e) -> e.getName())
.forEach(System.out::println);
System.out.println("------水平分割线---------");
Stream<Character> sm = list.stream()
.flatMap(StreamAPITest::getCharacter);
sm.forEach(System.out::println);
}
排序
这个默认的是从小到大,可以自定义排序
//排序
List<Integer> list = Arrays.asList(12, 32, 2, 45, 38, 29);
list.stream()
.sorted()
.forEach(System.out::println);//默认排序,从小到大
System.out.println("-------------------------");
//定制排序 employees 先按照月薪排序,如果月薪相等按照年龄排序
employees.stream()
.sorted((e1, e2) -> {
if (e1.getSalary() == e2.getSalary()) {
return e1.getAge().compareTo(e2.getAge()) ;
} else {
return e1.getSalary().compareTo( e2.getSalary());
}
})
.forEach(System.out::println);
运行结果:
12
29
32
38
45
-------------------------
Employee{name='小刚', salary=5000.0, age=19}
Employee{name='小凉', salary=7000.0, age=40}
Employee{name='小谷', salary=7000.0, age=20}
Employee{name='小红', salary=8000.0, age=23}
Employee{name='小明', salary=12000.0, age=32}
查找与匹配
allMatch ——检查是否匹配所有元素
anyMatch——检查是否至少匹配一个元素
noneMatch——检查是否没有匹配所有元素
findFirst——返回第一个元素
findAny——返回当前流中的任意元素
count——返回流中元素的总个数
max——返回流中最大值
min——返回流中最小值
private List<Employee> employees = Arrays.asList(
new Employee("小明", 12000.0, 32, Employee.Status.VOCATION),
new Employee("小红", 8000.0, 23, Employee.Status.FREE),
new Employee("小刚", 5000.0, 19, Employee.Status.BUSY),
new Employee("小凉", 7000.0, 40, Employee.Status.BUSY),
new Employee("小谷", 7000.0, 20, Employee.Status.FREE)
);
//匹配、查找、最大值、最小值、
@Test
public void test5() {
//allMatch,如果所有的元素都匹配返回true,否则返回false
boolean b1 = employees.stream()
.allMatch((e) -> {
return e.getStatus() == Employee.Status.BUSY;
});
System.out.println("b1 = " + b1);
//anyMatch 匹配中的任意元素满足条件返回true
boolean b2 = employees.stream()
.anyMatch((e) -> e.getStatus() == Employee.Status.VOCATION);
System.out.println("b2 = "+b2);
//noneMatch 如果所有元素都满足条件返回true,否则返回false
boolean b3 = employees.stream()
.noneMatch((e) -> e.getStatus() == Employee.Status.FREE);
//并不是所有的员工状态都是free所以返回false
System.out.println("b3 = "+b3);
//findFirst 查找第一个元素
Optional<Employee> employee1 = employees.stream()
.sorted((e1,e2)->-e1.getSalary().compareTo(e2.getSalary()))//salary 从高到低,返回最高工资的员工对象
.findFirst();
System.out.println("firstSalaryEmployee : "+employee1);
//findAny 返回当前流中任意一个元素
Optional<Employee> any = employees.parallelStream()//parallelStream 并行流
.findAny();
System.out.println("any : "+any);
//max
Optional<Employee> max = employees.stream()
.max((e1, e2) -> e1.getAge().compareTo(e2.getAge()));
System.out.println("max age employee "+max);
//min
Optional<Employee> min = employees.stream()
.min((e1, e2) -> e1.getAge().compareTo(e2.getAge()));
System.out.println("min age employee "+min);
//count
long count = employees.stream()
.count();
System.out.println("count: "+count);
}
运行结果输出:
b1 = false
b2 = true
b3 = false
firstSalaryEmployee : Optional[Employee{name='小明', salary=12000.0, age=32}]
any : Optional[Employee{name='小刚', salary=5000.0, age=19}]
max age employee Optional[Employee{name='小凉', salary=7000.0, age=40}]
min age employee Optional[Employee{name='小刚', salary=5000.0, age=19}]
count: 5
归约
reduce(T identity,BinaryOperator)
reduce(BinaryOperator)
作用:可以将流中元素反复结合起来,得到一个值。
List<Integer> list = Arrays.asList(23,12,3,45,67,29,98);
Integer sum = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println("sum = "+sum);
//先从employees中取出salary,然后reduce做处理,将员工工资求和
Optional<Double> optionalDouble = employees.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(optionalDouble.get());
收集
collect——将流转成其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。
public void test7(){
//收集员工名字返回集合
//返回List
List<String> names = employees.stream()
.map(Employee::getName)
.collect(Collectors.toList());
names.forEach(System.out::println);
//返回指定集合
HashSet<String> strings = employees.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(HashSet::new));
System.out.println(strings);
}
结果:
小明
小红
小刚
小凉
小谷
[小刚, 小凉, 小谷, 小明, 小红]
使用collect从employees 中获取最大工资的人,最小工资,平均工资,员工工资总和,员工人数
@Test
public void test1() {
//count
Long count = employees.stream()
.collect(Collectors.counting());
System.out.println("count = " + count);
//max employee
Optional<Employee> maxSalary = employees.stream()
.collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(maxSalary.get());
//min
Optional<Employee> minSal = employees.stream()
.collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(minSal.get());
//avg salary
Double avgSal = employees.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println("avg salary = "+avgSal);
//sum salary
Double sumSal = employees.stream()
.collect(Collectors.summingDouble(Employee::getSalary));
System.out.println("sum salary = "+sumSal);
}
输出结果:
count = 5
Employee{name=‘小明’, salary=12000.0, age=32}
Employee{name=‘小刚’, salary=5000.0, age=19}
avg salary = 7800.0
sum salary = 39000.0
分组
@Test
public void test2(){
String collect = employees.stream()
.map(Employee::getName)
.collect(Collectors.joining(",","---","---"));//将取出的name连接在一起,中间用,隔开,前缀是‘---’,后缀也是'---'.
System.out.println(collect);
Map<Employee.Status, List<Employee>> collect1 = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println("按状态分组:"+collect1);
}
输出结果:
—小明,小红,小刚,小凉,小谷—
按状态分组:{BUSY=[Employee{name=‘小刚’, salary=5000.0, age=19}, Employee{name=‘小凉’, salary=7000.0, age=40}], VOCATION=[Employee{name=‘小明’, salary=12000.0, age=32}], FREE=[Employee{name=‘小红’, salary=8000.0, age=23}, Employee{name=‘小谷’, salary=7000.0, age=20}]}
java8新特性之stream流的更多相关文章
- 乐字节-Java8新特性之Stream流(上)
上一篇文章,小乐给大家介绍了<Java8新特性之方法引用>,下面接下来小乐将会给大家介绍Java8新特性之Stream,称之为流,本篇文章为上半部分. 1.什么是流? Java Se中对于 ...
- 【Java8新特性】- Stream流
Java8新特性 - Stream流的应用 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! ...
- Java8新特性之Stream流(含具体案例)
一.概述 Stream 流是 Java 8 新提供给开发者的一组操作集合的 API,将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选.排序.聚合等.元素 ...
- JDK8新特性关于Stream流
在Java1.8之前还没有stream流式算法的时候,我们要是在一个放有多个User对象的list集合中,将每个User对象的主键ID取出,组合成一个新的集合,首先想到的肯定是遍历,如下: 1 2 3 ...
- Java 8 新特性之 Stream 流基础体验
Java 8 新特性之 Stream 流基础体验 package com.company; import java.util.ArrayList; import java.util.List; imp ...
- Java8 新特性之Stream API
1. Stream 概述 Stream 是Java8中处理集合的关键抽象概念,可以对集合执行非常复杂的查找,过滤和映射数据等操作; 使用 Stream API 对集合数据进行操作,就类似于使用 SQL ...
- java1.8新特性之stream流式算法
在Java1.8之前还没有stream流式算法的时候,我们要是在一个放有多个User对象的list集合中,将每个User对象的主键ID取出,组合成一个新的集合,首先想到的肯定是遍历,如下: List& ...
- 【Java8新特性】Stream API有哪些中间操作?看完你也可以吊打面试官!!
写在前面 在上一篇<[Java8新特性]面试官问我:Java8中创建Stream流有哪几种方式?>中,一名读者去面试被面试官暴虐!归根结底,那哥儿们还是对Java8的新特性不是很了解呀!那 ...
- Java8新特性 1——利用流和Lambda表达式操作集合
Java8中可以用简洁的代码来操作集合,比如List,Map,他们的实现ArrayList.以此来实现Java8的充分利用CPU的目标. 流和Lambda表达式都是Java8中的新特性.流可以实现对集 ...
随机推荐
- nginx学习之——虚拟主机配置
例子1: 基于域名的虚拟主机 server { listen 80; #监听端口 server_name a.com; #监听域名 location / { root /var/www/a.com; ...
- 自己编写k8s
## 基于Docker和Kubernetes的企业级DevOps实践训练营 ### 课程准备 1. 离线镜像包 百度:https://pan.baidu.com/s/1N1AYGCYftYGn6L0Q ...
- js实现刮刮卡抽奖
刮刮卡抽奖是前端活动页常见的功能: 链接:图像擦除插件(下载及教程讲解) 推荐理由:无缝刮痕,兼容性好,上手简单 插件有些要修改的地方,打开图像擦除插件后可以看下方网友讨论,或者直接下载本博 ...
- K8s 终将废弃 docker,TKE 早已支持 containerd
近日 K8s 官方称最早将在 1.23版本弃用 docker 作为容器运行时,并在博客中强调可以使用如 containerd 等 CRI 运行时来代替 docker.本文会做详细解读,并介绍 dock ...
- ant-design 基础格式
1 格式 <template> <div> <center><h1>这是·注册页面</h1></center> <a-fo ...
- Salesforce LWC学习(二十九) getRecordNotifyChange(LDS拓展增强篇)
本篇参考: https://developer.salesforce.com/docs/component-library/documentation/en/lwc/data_ui_api https ...
- 职场PUA,管理者的五宗罪
在目前的社会环境下,程序员似乎成了"弱势群体".我们经常谈论的职场PUA已经成为程序员的代名词. 我一直在想,为什么这么多管理者能力会这么差. 但最后最吃亏的还是可怜的程序员. 也 ...
- APEX-数据导出/打印
前言: 由于公司使用了Oracle APEX构建应用,且在APEX新版本v20.2版本中增强了相关报表导出数据相关功能:正好现在做的事情也需要类似的功能,就先来学习一下Oracle的APEX相关功能及 ...
- C# 锁与死锁
什么是死锁: 所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进. 因此我们举个例子来描述,如果此时有一个线程A,按照先锁a再 ...
- C# 中国日历 农历 阳历 星座 二十四节气 二十八星宿 节日 天干地支
using System; namespace DotNet.Utilities { /// <summary> /// 农历属性 /// </summary> public ...