文章目录
Java8的两个重大改变,一个是Lambda表达式,另一个就是本节要讲的Stream API表达式。
一、Stream 流对象的作用
Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找、过滤、筛选等操作。
Stream(流) 类用于来简化集合类的使用,Stream 本质上是个接口,接口中定义了很多对 Stream 对象的操作;
二、Stream的操作步骤
1、创建Stream
从一个数据源,如集合、数组中获取流。
2、中间操作
一个操作的中间链,对数据源的数据进行操作。
3、终止操作
一个终止操作,执行中间操作链,并产生结果。
要注意的是,对流的操作完成后需要进行关闭操作(或者用JAVA7的try-with-resources)。(流的关闭就是在操作体外执行的操作)
三、特征
- 单次处理,一次处理结束后,当前stream就关闭了
- 支持并行操作
四、举个简单的例子
假设有一个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()是终止操作。
五、stream流中方法精简总结
方法名 | 简介 |
---|---|
allMatch | 检查 Stream 中的所有元素,全部都通过检测则返回 true |
anyMatch | 检查 Stream 中的所有元素,全部都通过检测则返回 true |
noneMatch | 当流中每个元素都不符合该断言时才返回true |
count | 返回流中元素的总个数 |
max | 返回stream中的最大值 |
min | 返回stream中的最小值 |
sort | 对stream中的元素排序 |
filter | 过滤 Stream中的元素 |
map | 将流中的一个值转换成一个新的值 |
collect | 接收一个Collector实例,将流中元素收集成另外一个数据结构 |
collect(toList()) | 通过 Stream 生成一个列表 |
flatMap | 将多个 Stream 连接成一个 Stream |
reduce | 从一组值中生成一个新的值 |
of | 返回包含参数中单个指定元素的顺序Stream |
distinct | 去重 |
findFirst | 返回流中第一个元素 |
findAny | 返回流中的任意元素 |
六、操作方法的使用详解
stream流结合lambda表达式使用起来非常方便。
可以学习一下lambda表达式的使用,有空我会在CSDN上总结
1. allMatch和anyMatch
allMatch:检查 Stream 中的所有元素,全部都通过检测则返回 true,否则 false
anyMatch:检查 Stream 中的所有元素,至少有一个通过检测则返回 true,否则 false
//allMatch
System.out.println("----->"+list.stream().allMatch(n->n.getClass() == Integer.class));
//anyMatch
System.out.println("----->"+list.stream().anyMatch(n->n>1));
2. max,min和sort
max:返回stream中的最大值
min:返回stream中的最小值
sort:对stream中的元素排序
//遍历
list.stream().forEach(a -> System.out.println(a));
//max
System.out.println("----->"+list.stream().max((a,b)->a-b).get());
//min
System.out.println("----->"+list.stream().min((a,b)->a-b).get());
//sort
list.stream().sorted((a,b)->a-b).forEach(a->System.out.println(a));
3. filter和map
filter:筛选 Stream 元素,符合条件的留下并组成一个新的 Stream 。
map:依次对 Stream 中的元素进行指定的函数操作,并将按顺序将函数操作的返回值组合到一个新的 Stream 中。
//筛选filter
list.stream().filter(n->n>6).forEach(n->System.out.println(n));
//map
list.stream().map(n->n+1).forEach(n->System.out.println(n));
4. of
用法: static Stream of(T t)
参数: 此方法接受强制参数t,该参数是Stream中的单个元素。
返回值: Stream of(T t)返回包含单个指定元素的顺序Stream。
// Java code for Stream of(T t)
// to get a sequential Stream
// containing a single element.
import java.util.*;
import java.util.stream.Stream;
class GFG {
// Driver code
public static void main(String[] args)
{
// Creating an Stream having single element only
Stream stream = Stream.of("Geeks");
// Displaying the Stream having single element
stream.forEach(System.out::println);
}
}
输出:Geeks
5. distinct和collect
distinct:去重
collect:可以做collectors中的一些操作,如:连接,转list,分组等
//collect
Stream.of("1","2","3").collect(Collectors.toList()).forEach(n->System.out.println(n));
//去重distinct
Stream.of("2","2","2").distinct().forEach(n->System.out.println(n));
其中,.collect(Collectors.toList()) 方法将操作后返回的 Stream 生成一个 List。
6. collect(toList()) & filter
collect(toList()) 的作用是通过一个 Stream 对象生成 List 对象,案例:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = list.stream().filter((value) -> value > 2).collect(toList());
result.forEach((value) -> System.out.print(value));
解析:创建了一个 List 对象并初始化,然后筛选出大于 2 的值,输出。
filter 方法的作用是过滤 Stream 中的元素,filter 方法是一个高阶函数,
接收一个函数接口作为参数,此高阶函数返回一个 boolean 值,返回 true 的元素会保留下来;
collect(toList()) 方法将 filter 操作返回的 Stream 生成一个 List。
高阶函数:接收或返回一个函数接口的函数称为高阶函数。
函数接口:只包含一个函数的接口成为函数接口。
7. map
map 函数的作用是将流中的一个值转换成一个新的值,举个例子,我们要将一个 List 转换成 List ,那么就可以使用 map 方法,案例:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<String> result = list.stream().map(value -> String.format("String:%s", value)).collect(toList());
result.forEach(System.out::print);
解析:map 方法将 Integer 元素转换成 String 并使用 collect(toList()) 方法生成一个新的 List。
System.out::print 是 (value) -> System.out.print(value) 的简化版写法。
8. flatMap
将多个 Stream 连接成一个 Stream。案例:
List<String> list = Arrays.asList("abc", "def", "ghi");
List<Character> result = list.stream().flatMap(value -> {
char[] chars = value.toCharArray();
Character[] characters = new Character[chars.length];
for(int i = 0; i < characters.length; i++){
characters[i] = chars[i];
}
return Stream.of(characters);
}).collect(toList());
result.forEach(System.out::println);
解析:首先定义一个 List 对象,将这个对象中的每一个 String 都分割成一个字母并生成一个新的 List 对象。
上面代码先遍历 list ,通过 flatMap 函数将每个 String 元素都生成一个新的 Stream 并将这些 Stream 连接成一个新的 Stream。
9. reduce
从一组值中生成一个新的值
List<Integer> list = Arrays.asList(0, 1, 2, 3);
int count = list.stream().reduce(0, (acc, item) -> acc + item).intValue();
System.out.println(count);
reduce 函数的一个参数为循环的初始值,这里计算累加时初始值为 0,acc 代表已经计算的结果,item 表示循环的每个元素。
10. 收集操作
collect:接收一个Collector实例,将流中元素收集成另外一个数据结构。