Java8新特性之Stream流的使用
Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找、过滤、筛选等操作,在新版的JPA中,也已经加入了Stream。
1、Stream的操作步骤
Stream有如下三个操作步骤:
一、创建Stream
从一个数据源,如集合、数组、值、文件中获取流。
//集合
//这种数据源较为常用,通过stream()方法即可获取流对象:
List<Person> list = new ArrayList<Person>();
Stream<Person> stream = list.stream();//数组
//通过Arrays类提供的静态函数stream()获取数组的流对象:
String[] names = {"chaimm","peter","john"};
Stream<String> stream = Arrays.stream(names);//值
//直接将几个值变成流对象:
Stream<String> stream = Stream.of("chaimm","peter","john");//文件
try(Stream lines = Files.lines(Paths.get(“文件路径名”),Charset.defaultCharset())){
//可对lines做一些操作
}catch(IOException e){
}
二、中间操作
一个操作的中间链,对数据源的数据进行操作。
三、终止操作
一个终止操作,执行中间操作链,并产生结果。
要注意的是,对流的操作完成后需要进行关闭操作(或者用JAVA7的try-with-resources,Java7简化了IO操作,把打开IO操作放在try后的括号中即可省略关闭IO的代码)。
举个例子:
有一个Person类和一个Person对象集合,需求:1)找到年龄大于18岁的人并输出;2)找出所有中国人的数量。
@Data
class Person {private String name;private Integer age;private String country;private char sex;public Person(String name, Integer age, String country, char sex) {this.name = name;this.age = age;this.country = country;this.sex = sex;}
}
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("小梅",20,"中国",'F'));
personList.add(new Person("何雪",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
在JDK8以前,我们可以通过遍历列表来完成。但是在有了Stream API后,可以这样来实现:
public static void main(String[] args) {// 1)找到年龄大于18岁的人并输出;personList.stream().filter((p) -> p.getAge() > 18).forEach(System.out::println);System.out.println("-------------------------------------------");// 2)找出所有中国人的数量long chinaPersonNum = personList.stream().filter((p) -> p.getCountry().equals("中国")).count();System.out.println("中国人有:" + chinaPersonNum + "个");
}
输出结果:
Person(name=Tom, age=24, country=美国, sex=M)
Person(name=Harley, age=22, country=英国, sex=F)
Person(name=向天笑, age=20, country=中国, sex=M)
Person(name=李康, age=22, country=中国, sex=M)
Person(name=小梅, age=20, country=中国, sex=F)
Person(name=何雪, age=21, country=中国, sex=F)
Person(name=李康, age=22, country=中国, sex=M)
-------------------------------------------
中国人有:6
personList.stream()是创建流,filter()属于中间操作,forEach、count()是终止操作。
2、Stream中间操作--筛选与切片
- filter:接收Lambda,从流中排除某些操作;
- limit:截断流,使其元素不超过给定对象
- skip(n):跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补
- distinct:筛选,通过流所生成元素的hashCode()和equals()去除重复元素。
2.1 limit举例
从Person列表中取出两个女性。
personList.stream().filter((p) -> p.getSex() == 'F').limit(2).forEach(System.out::println);
输出结果:
Person(name=欧阳雪, age=18, country=中国, sex=F)
Person(name=Harley, age=22, country=英国, sex=F)
2.2 skip举例
从Person列表中从第2个女性开始,取出所有的女性。
personList.stream().filter((p) -> p.getSex() == 'F').skip(1).forEach(System.out::println);
输出结果:
Person(name=Harley, age=22, country=英国, sex=F)
Person(name=小梅, age=20, country=中国, sex=F)
Person(name=何雪, age=21, country=中国, sex=F)
2.3 distinct举例
从Person列表中取出所有男性并过滤掉名字重复的。
personList.stream().filter((p) -> p.getSex() == 'M').distinct().forEach(System.out::println);
输出结果:
Person(name=Tom, age=24, country=美国, sex=M)
Person(name=向天笑, age=20, country=中国, sex=M)
Person(name=李康, age=22, country=中国, sex=M)
3、Stream中间操作--映射
- map--接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
- flatMap--接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
3.1 map举例
例1:我们用一个PersonCountry类来接收所有的国家信息:
@Data
class PersonCountry {private String country;
}personList.stream().map((p) -> {PersonCountry personName = new PersonCountry();personName.setCountry(p.getCountry());return personName;
}).distinct().forEach(System.out::println);
输出结果:
PersonName(country=中国)
PersonName(country=美国)
PersonName(country=英国)
例2:有一个字符列表,需要提出每一个字符
List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","ddd");
根据字符串获取字符方法:
public static Stream<Character> getCharacterByString(String str) {List<Character> characterList = new ArrayList<>();for (Character character : str.toCharArray()) {characterList.add(character);}return characterList.stream();
}
List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","ddd");
final Stream<Stream<Character>> streamStream = list.stream().map(TestStreamAPI::getCharacterByString);
streamStream.forEach(System.out::println);
输出结果:
java.util.stream.ReferencePipeline$Head@3f91beef
java.util.stream.ReferencePipeline$Head@1a6c5a9e
java.util.stream.ReferencePipeline$Head@37bba400
java.util.stream.ReferencePipeline$Head@179d3b25
java.util.stream.ReferencePipeline$Head@254989ff
从输出结果及返回结果类型(Stream<Stream<Character>>)可以看出这是一个流中流,要想打印出我们想要的结果,需要对流中的每个流进行打印:
streamStream.forEach(sm -> sm.forEach(System.out::print));
输出结果:
aaabbbcccdddddd
但我们希望的是返回的是一个流,而不是一个包含了多个流的流,而flatMap可以帮助我们做到这一点。
3.2 flatMap举例
改写上面的方法,将map改成flatMap:
final Stream<Character> characterStream = list.stream().flatMap(TestStreamAPI::getCharacterByString);
characterStream.forEach(System.out::print);
输出结果:
aaabbbcccdddddd
3.3 map和flatMap的图解
map图解:
map在接收到流后,直接将Stream放入到一个Stream中,最终整体返回一个包含了多个Stream的Stream。
flatMap图解:
flatMap在接收到Stream后,会将接收到的Stream中的每个元素取出来放入一个Stream中,最后将一个包含多个元素的Stream返回。
4、Stream中间操作--排序
- sorted()--自然排序(Comparable)
- sorted(Comparator com)--定制排序(Comparator)
对前面的personList按年龄从小到大排序,年龄相同,则再按姓名排序:
final Stream<Person> sorted = personList.stream().sorted((p1, p2) -> {if (p1.getAge().equals(p2.getAge())) {return p1.getName().compareTo(p2.getName());} else {return p1.getAge().compareTo(p2.getAge());}
});
sorted.forEach(System.out::println);
输出结果:
Person(name=欧阳雪, age=18, country=中国, sex=F)
Person(name=向天笑, age=20, country=中国, sex=M)
Person(name=小梅, age=20, country=中国, sex=F)
Person(name=何雪, age=21, country=中国, sex=F)
Person(name=Harley, age=22, country=英国, sex=F)
Person(name=李康, age=22, country=中国, sex=M)
Person(name=李康, age=22, country=中国, sex=M)
Person(name=Tom, age=24, country=美国, sex=M)
5、终止操作--查找与匹配
- allMatch--检查是否匹配所有元素
- anyMatch--检查是否至少匹配一个元素
- noneMatch--检查是否没有匹配所有元素
- findFirst--返回第一个元素
- findAny--返回当前流中的任意元素
- count--返回流中元素的总个数
- max--返回流中最大值
- min--返回流中最小值
5.1 allMatch
判断personList中的人是否都是成年人:
final boolean adult = personList.stream().allMatch(p -> p.getAge() >= 18);
System.out.println("是否都是成年人:" + adult);final boolean chinaese = personList.stream().allMatch(p -> p.getCountry().equals("中国"));
System.out.println("是否都是中国人:" + chinaese);
输出结果:
是否都是成年人:true
是否都是中国人:false
5.2 max、min
获取personList中年龄最大的人信息和年龄最小的人信息:
final Optional<Person> maxAge = personList.stream().max((p1, p2) -> p1.getAge().compareTo(p2.getAge()));
System.out.println("年龄最大的人信息:" + maxAge.get());final Optional<Person> minAge = personList.stream().min((p1, p2) -> p1.getAge().compareTo(p2.getAge()));
System.out.println("年龄最小的人信息:" + minAge.get());
输出结果:
年龄最大的人信息:Person(name=Tom, age=24, country=美国, sex=M)
年龄最小的人信息:Person(name=欧阳雪, age=18, country=中国, sex=F)
6、归约
Stream API的归约操作可以将流中元素反复结合起来,得到一个值:
Optional<T> reduce(BinaryOperator<T> accumulator);
T reduce(T identity, BinaryOperator<T> accumulator);
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);
6.1 求一个1到100的和
List<Integer> integerList = new ArrayList<>(100);
for(int i = 1;i <= 100;i++) {integerList.add(i);
}
final Integer reduce = integerList.stream().reduce(0, (x, y) -> x + y);
System.out.println("结果为:" + reduce);
输出结果:
结果为:5050
这里用到了reduce第二个方法:T reduce(T identity, BinaryOperator<T> accumulator)
把这个动作拆解一下,其运算步骤模拟如下:
0 (1,2) -> 1 + 2 + 0
3 (3,4) -> 3 + 4 + 3
10 (5,6) -> 5 + 6 + 10
.
.
.
运算步骤是:每次将列表的两个元素相加,并将结果与前一次的两个元素的相加结果进行累加。在开始时,将identity设为0,因为第1个元素和第2个元素在相加的时候,前面还没有元素操作过。
6.2 求所有人的年龄之和
final Optional<Integer> reduce = personList.stream().map(Person::getAge).reduce(Integer::sum);
System.out.println("年龄总和:" + reduce);
输出结果:
年龄总和:169
7、收集
collect:将流转换为其他形式,接收一个Collector接口实现 ,用于给Stream中汇总的方法
<R, A> R collect(Collector<? super T, A, R> collector);
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);
collect不光可以将流转换成其他集合等形式,还可以进行归约等操作,具体实现也很简单,主要是与Collectors类搭配使用。
7.1 改写3.1 map举例中的的例子,将国家收集起来转换成List
final List<String> collect = personList.stream().map(p -> p.getCountry()).distinct().collect(Collectors.toList());
System.out.println(collect);
输出结果:
[中国, 美国, 英国]
7.2 计算出平均年龄
final Double collect1 = personList.stream().collect(Collectors.averagingInt(p -> p.getAge()));
System.out.println("平均年龄为:" + collect1);
输出结果:
平均年龄为:21.125
7.3 找出最小年龄、最大年龄
final Optional<Integer> maxAge2 = personList.stream().map(Person::getAge).collect(Collectors.maxBy(Integer::compareTo));
System.out.println("最大年龄:" + maxAge2.get());final Optional<Integer> minAge2 = personList.stream().map(Person::getAge).collect(Collectors.minBy(Integer::compareTo));
System.out.println("最小年龄:" + minAge2.get());
输出结果:
最大年龄:24
最小年龄:18
还有其他很操作,可以参考java.util.stream.Collectors。
8、注意流的关闭
try(final Stream<Integer> integerStream = personList.stream().map(Person::getAge)) {final Optional<Integer> minAge = integerStream.collect(Collectors.minBy(Integer::compareTo));System.out.println(minAge.get());
}
最好将流的操作放到try-with-resources,本章前面内容为了方便,没有放到try-with-resources中。
9、完整测试代码
import lombok.Data;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;public class TestStreamAPI {public static void main(String[] args) {List<Person> personList = new ArrayList<>();personList.add(new Person("欧阳雪",18,"中国",'F'));personList.add(new Person("Tom",24,"美国",'M'));personList.add(new Person("Harley",22,"英国",'F'));personList.add(new Person("向天笑",20,"中国",'M'));personList.add(new Person("李康",22,"中国",'M'));personList.add(new Person("小梅",20,"中国",'F'));personList.add(new Person("何雪",21,"中国",'F'));personList.add(new Person("李康",22,"中国",'M'));// 1)找到年龄大于18岁的人并输出;personList.stream().filter((p) -> p.getAge() > 18).forEach(System.out::println);System.out.println("-------------------------------------------");// 2)找出所有中国人的数量long chinaPersonNum = personList.stream().filter((p) -> p.getCountry().equals("中国")).count();System.out.println("中国人有:" + chinaPersonNum);// limitpersonList.stream().filter((p) -> p.getSex() == 'F').limit(2).forEach(System.out::println);System.out.println();// skippersonList.stream().filter((p) -> p.getSex() == 'F').skip(1).forEach(System.out::println);// distinctpersonList.stream().filter((p) -> p.getSex() == 'M').distinct().forEach(System.out::println);// mappersonList.stream().map((p) -> {PersonCountry personName = new PersonCountry();personName.setCountry(p.getCountry());return personName;}).distinct().forEach(System.out::println);// map2List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","ddd");final Stream<Stream<Character>> streamStream= list.stream().map(TestStreamAPI::getCharacterByString);
// streamStream.forEach(System.out::println);streamStream.forEach(sm -> sm.forEach(System.out::print));// flatMapfinal Stream<Character> characterStream = list.stream().flatMap(TestStreamAPI::getCharacterByString);characterStream.forEach(System.out::print);// sortfinal Stream<Person> sorted = personList.stream().sorted((p1, p2) -> {if (p1.getAge().equals(p2.getAge())) {return p1.getName().compareTo(p2.getName());} else {return p1.getAge().compareTo(p2.getAge());}});sorted.forEach(System.out::println);// allMatchfinal Stream<Person> stream = personList.stream();final boolean adult = stream.allMatch(p -> p.getAge() >= 18);System.out.println("是否都是成年人:" + adult);final boolean chinaese = personList.stream().allMatch(p -> p.getCountry().equals("中国"));System.out.println("是否都是中国人:" + chinaese);// max minfinal Optional<Person> maxAge = personList.stream().max((p1, p2) -> p1.getAge().compareTo(p2.getAge()));System.out.println("年龄最大的人信息:" + maxAge.get());final Optional<Person> minAge = personList.stream().min((p1, p2) -> p1.getAge().compareTo(p2.getAge()));System.out.println("年龄最小的人信息:" + minAge.get());// reduceList<Integer> integerList = new ArrayList<>(100);for(int i = 1;i <= 100;i++) {integerList.add(i);}final Integer reduce = integerList.stream().reduce(0, (x, y) -> x + y);System.out.println("结果为:" + reduce);final Optional<Integer> totalAge = personList.stream().map(Person::getAge).reduce(Integer::sum);System.out.println("年龄总和:" + totalAge);// collectfinal List<String> collect = personList.stream().map(p -> p.getCountry()).distinct().collect(Collectors.toList());System.out.println(collect);final Double collect1 = personList.stream().collect(Collectors.averagingInt(p -> p.getAge()));System.out.println("平均年龄为:" + collect1);final Optional<Integer> maxAge2 = personList.stream().map(Person::getAge).collect(Collectors.maxBy(Integer::compareTo));System.out.println(maxAge2.get());try(final Stream<Integer> integerStream = personList.stream().map(Person::getAge)) {final Optional<Integer> minAge2 = integerStream.collect(Collectors.minBy(Integer::compareTo));System.out.println(minAge2.get());}}public static Stream<Character> getCharacterByString(String str) {List<Character> characterList = new ArrayList<>();for (Character character : str.toCharArray()) {characterList.add(character);}return characterList.stream();}
}@Data
class PersonCountry {private String country;
}@Data
class Person {private String name;private Integer age;private String country;private char sex;public Person(String name, Integer age, String country, char sex) {this.name = name;this.age = age;this.country = country;this.sex = sex;}
}
Java8新特性之Stream流的使用相关推荐
- 使用Java8新特性(stream流、Lambda表达式)实现多个List 的笛卡尔乘积 返回需要的List<JavaBean>
需求分析: 有两个Long类型的集合 : List<Long> tagsIds; List<Long> attributesIds; 现在需要将这两个Long类型的集合进行组合 ...
- java stream byte_乐字节-Java8新特性之Stream流(上)
上一篇文章,小乐给大家介绍了<Java8新特性之方法引用>,下面接下来小乐将会给大家介绍Java8新特性之Stream,称之为流,本篇文章为上半部分. 1.什么是流? Java Se中对于 ...
- Java8新特性-使用Stream流来实现递归遍历树形结构(案例)
Java8新特性-Stream流 可能平常会遇到一些需求,比如构建菜单,构建树形结构,数据库一般就使用父id来表示,为了降低数据库的查询压力,我们可以使用Java8中的Stream流一次性把数据查出来 ...
- Java8新特性之Stream流式编程
特地感谢鲁班大叔的分享,原学习地址:Java8 Stream流式编程爱 撸码就是快,流式编程好 代码传家宝 以下是学习过程整理的笔记 1.简介 Stream 流处理,首先要澄清的是 java8 中的 ...
- java8新特性之Stream流
一.什么是Stream流 Stream是java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找.过滤.映射数据等操作,使用Stream API对集合数据进行操作就 ...
- JAVA8新特性之Stream流分组
Apple apple01 = new Apple(1, "red", 100, "成都");Apple apple02 = new Apple(2, &quo ...
- 跟我学 Java 8 新特性之 Stream 流(七)流与迭代器,流系列大结局
转载自 跟我学 Java 8 新特性之 Stream 流(七)流与迭代器,流系列大结局 恭喜你们,马上就要学完Java8 Stream流的一整系列了,其实我相信Stream流对很多使用Java的同 ...
- 跟我学 Java 8 新特性之 Stream 流基础体验
转载自 跟我学 Java 8 新特性之 Stream 流基础体验 Java8新增的功能中,要数lambda表达式和流API最为重要了.这篇文章主要介绍流API的基础,也是流API系列的第一篇文章, ...
- 【java8新特性】——Stream API详解(二)
一.简介 java8新添加了一个特性:流Stream.Stream让开发者能够以一种声明的方式处理数据源(集合.数组等),它专注于对数据源进行各种高效的聚合操作(aggregate operation ...
最新文章
- 【ubuntu perf安装】The program 'perf' is currently not installed.
- POJ 2152	 Fire
- go get 的不再src目录中_GO语言基础进阶教程:包的使用
- Nginx的启动阶段讲解
- 大数据分析工程师证书_CDA数据分析就业班、大数据就业班就业情况怎么样?
- android一格一格向上的进度条,如何 使用 ProgressBar 进度条
- Python引力波火了 你该了解的开源框架
- 中国营养与健康调查(CHNS)2018年最新数据
- 实现安卓中TextView,EditText中数字的数码管字体显示
- ios 微信逆向部分
- rtl8812驱动分析(二)
- android加密、签名相关
- tail命令 – 查看文件尾部内容
- 在使用npm install时遇到的问题 npm ERR! code ERESOLVE
- Anemometer让慢查询可视化
- python pptx库中文文档_基于python-pptx库中文文档及使用详解
- 强! 看了这几个公众号让我拿到蚂蚁金服、美团的 Offer
- 电源学习-DCDC电源分类
- 如何计算cuboid的数量
- 笔记本电脑html电视,笔记本电脑变电视怎么设置
热门文章
- TB6612FNG电机驱动模块的简单使用
- 【ABAP系列】SAP ABAP smartforms设备类型CNSAPWIN不支持页格式ZXXX
- 一文读懂iOS如何使用TestFlight进行测试
- 脚本语言【JavaScript基础】JavaScript函数:声明+调用
- js中RGB与十六进制颜色转换
- Linux内核内存管理(2):固定映射地址(fixmap)和输入输出重映射(ioremap)
- Java系统插件开发原理与实例
- super 和 this
- 通达信公式:如何表示5个数据中的前三大数值?
- UEFI开发探索82- YIE002USB开发板(05 制作HID设备)