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中对于 ...
-
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中的新特性.流可以实现对集 ...
-
java8新特性,使用流遍历集合
在这篇“Java 8新特性教程”系列文章中,我们会深入解释,并通过代码来展示,如何通过流来遍历集合,如何从集合和数组来创建流,以及怎么聚合流的值. 在之前的文章“遍历.过滤.处理集合及使用Lambda ...
-
Java8 新特性 Lambda &; Stream API
目录 Lambda & Stream API 1 Lambda表达式 1.1 为什么要使用lambda表达式 1.2 Lambda表达式语法 1.3 函数式接口 1.3.1 什么是函数式接口? ...
-
Java8新特性之Stream
原文链接:http://ifeve.com/stream/ Java8初体验(二)Stream语法详解 感谢同事[天锦]的投稿.投稿请联系 tengfei@ifeve.com上篇文章Java8初体验( ...
随机推荐
-
容器--Map和AbstractMap
一.前言 前面我们介绍了Collection接口的定义及一系列实现,并重点介绍了List体系下的一些实现,对于Collection来说,其实还有Set系列同样很重要,但由于Set是依赖于Map实现的, ...
-
angularjs+jasmine单元测试入门
使用cordova.angularjs.ionic开发hybrid App有一段时间了.为了做单元测试,之前一直是把要测的某一部分产品代码复制到另一个单独的工程中来写测试代码,测好了以后再复制回去.弊 ...
-
Oracle管道函数示例
Oracle的管道函数需要定义下面的三样: Record/Object Type:定义一个Record或Object类型的变量,这个变量用于表示返回结果集的一行数据,有点像C#中的DataRow类. ...
-
SAP MM A工厂下的PR可以转成B工厂下的PO?
SAP MM A工厂下的PR可以转成B工厂下的PO? 答案是可能的,这也是SAP标准行为之一. 如下图采购申请单据, PR中的Plant是GENL.该PR 已经转成了PO,如上图. 看这个PO,工厂代 ...
-
第七节:WebApi与Unity整合进行依赖注入和AOP的实现
一. IOC和DI 1. 通过Nuget引入Unity程序集. PS:[版本:5.8.6] 2. 新建DIFactory类,用来读取Unity的配置文件并创建Unity容器,需要注意的是DIFacto ...
-
3-7 Vue中的列表渲染
举个案例:循环data中的list的值在div中,并显示相应的index值. 关于数组的循环: //显示效果如下图: //一般的列表渲染最好带一个key值,要把key值设置为唯一值的话,可以选择in ...
-
re_test
https://www.cnblogs.com/zhaof/p/6925674.html#4152933 https://www.cnblogs.com/lanyinhao/p/9165747.htm ...
-
告诉你们!我是怎么与Linux系统接触的!
最开始接触Linux是在15年来北京后,刚来北京机缘巧合,从事了实施工程师的工作.实施工作是一个面很广的工作.业务.技术.沟通等等方方面面的.技术一直是我是的短板.刚开始,公司在要在阿里云上部署APP ...
-
用JS 和 jQery获取屏幕的高度和宽度
用的时候,网上找了下,放在一起,方便以后查阅 document.body.clientWidth document.body.offsetWidth(包括线宽)//网页可见区域宽 document.b ...
-
Oracle APEX 5.1 with Ords 17 in Tomcat 9&ndash;Error tips: 请求无法映射到任何数据库。请确保请求 URL 正确, 并且已正确配置 URL 到数据库的映射
一次意外关机引发的血案 1.重新开机打开 tomcat 9, 一切正常 2.打开 ords,异常报错: 404 Not Found 请求无法映射到任何数据库.请确保请求 URL 正确, 并且已正确配置 ...