StreamAPI的作用
- Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API(java.util.stream.*)。Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
**注意: **
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
StreamAPI 的执行过程
StreamAPI 的执行过程.png一、创建流
@Test
public void test1() {
//可以通过Collection 系列集合提供stream 或parallelStream
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//可以通过数组
Integer[] nums = new Integer[10];
Stream<Integer> stream2 = Arrays.stream(nums);
//可以通过Stream类中静态方法
Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5);
//创建无限流
//迭代
//limit取前十个
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2).limit(10);
stream4.forEach(System.out::println);
//生成随机数(两个)
Stream<Double> Stream5 = Stream.generate(Math::random).limit(2);
Stream5.forEach(System.out::println);
}
二、中间操作
筛选与切片:
filter——接收 Lambda , 从流中排除某些元素。
limit——截断流,使其元素不超过给定数量。
skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
- filter:过滤某些元素
@Test
public void test2(){
//所有的中间操作不会做任何的处理
Stream<Employee> stream = emps.stream()
.filter((e) -> {
System.out.println("测试中间操作");
return e.getAge() <= 35;
});
//只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”、“延迟加载”
stream.forEach(System.out::println);
}
结果是:只留下年龄<=35的员工
image.png
@Test
public void test2(){
//所有的中间操作不会做任何的处理
Stream<Employee> stream = emps.stream()
.filter((e) -> {
return e.getAge() <= 35;
}).limit(3);
//只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”、“延迟加载”
stream.forEach(System.out::println);
}
- 结果是:只留下前三个元素
- skip:跳过元素
@Test
public void test5(){
emps.parallelStream()
.filter((e) -> e.getSalary() >= 5000)
.skip(2)
.forEach(System.out::println);
}
结果是:跳过了前两个
image.png
- distinct:去重
@Test
public void test6(){
emps.stream()
.distinct()
.forEach(System.out::println);
}
结果是:将重复的赵六全部去除了[图片上传中...(映射中的Map.png-d90df4-1564816615552-0)]
image.png映射:
map——接收 Lambda , 将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
-
map与flatMap:
映射中的Map.png
flatMap.png
@Test
public void test21(){
List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
//map得到,的是一个新流,流中是流流里面是Character
Stream<Stream<Character>> stream2 = strList.stream()
.map(StreamAPITest::filterCharacter);
stream2.forEach((sm) -> {
sm.forEach(System.out::println);
});
System.out.println("---------------------------------------------");
//flatMap:将所有流连接成一个流
Stream<Character> stream3 = strList.stream()
.flatMap(StreamAPITest::filterCharacter);
stream3.forEach(System.out::println);
}
public static Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for (Character ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
结果是:效果相同但是,但是遍历逻辑有所不同
image.png排序:
sorted()——自然排序
sorted(Comparator com)——定制排序
@Test
public void test22(){
emps.stream()
.map(Employee::getName)
.sorted()
.distinct()
.forEach(System.out::println);
System.out.println("------------------------------------");
emps.stream()
.sorted((x, y) -> {
if(x.getAge() == y.getAge()){
return x.getName().compareTo(y.getName());
}else{
return Integer.compare(x.getAge(), y.getAge());
}
}).distinct()
.forEach(System.out::println);
}
终止操作
查找与匹配:
allMatch--检查是否匹配所有元素
anyMatch--检查是否至少匹配一个元素
noneMatch--检查是否没有匹配所有元素
findFirst--返回第一个元素
findAny--返回当前流中的任意元素
- 测试:
@Test
public void test01() {
//检查是否所有员工状态都是BUSY
boolean b1 = emps.stream()
.allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b1);
//检查是否至少有一个员工状态都是BUSY
boolean b2 = emps.stream()
.anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b2);
//检查是否没有员工状态都是BUSY
boolean b3 = emps.stream()
.noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b3);
System.out.println("---------------------------------------------");
//从大到小排序,取第一个(相当于Max)
Optional<Employee> first = emps.stream()
.sorted((e1, e2) -> -Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(first.get());
System.out.println("---------------------------------------------");
//串行流,一个一个查,顺序不变,一般是拿的第一个
Optional<Employee> any = emps.stream()
.filter((e1) -> e1.getStatus().equals(Employee.Status.FREE))
.findAny();
System.out.println(any.get());
System.out.println("---------------------------------------------");
//并行流,多线程一起查,随机拿符合条件的
Optional<Employee> any2 = emps.parallelStream()
.filter((e1) -> e1.getStatus().equals(Employee.Status.FREE))
.findAny();
System.out.println(any2.get());
}
结果是:
image.png- 这里需要注意的是,最后两个,单线程和多线程的区别,串行查出来的数据一般是按顺序的,并行就不一定了(赵六顺序再张三后面)
查找与匹配:
count--返回流中元素的总个数
max--返回流中最大值
min--返回流中最小值
@Test
public void test02() {
//计数,员工人数
long count = emps.stream()
.count();
System.out.println(count);
//按工资取出最大值员工
Optional<Employee> max = emps.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(max.get());
//用map取出工资,再用min得到最小工资
Optional<Double> min = emps.stream()
.map(Employee::getSalary)
.min(Double::compare);
System.out.println(min.get());
}
运行结果:
image.png归约:
reduce(T identity, BinaryOperator) / reduce(BinaryOperator)
——可以将流中元素反复结合起来,得到一个值。
@Test
public void test1() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
//计算和
//计算结果作为x,再从数组中取出新值作为y,进行下一步计算
Integer sum = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(sum);
System.out.println("----------------------------------------");
//计算总工资
Optional<Double> op = emps.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(op.get());
}
结果是:
image.pngcollect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
@Test
public void test3() {
//取名字,封装成list
List<String> list = emps.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("----------------------------------");
//取名字,封装成set
Set<String> set = emps.stream()
.map(Employee::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("----------------------------------");
//取名字,封装成hashset
HashSet<String> hs = emps.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(HashSet::new));
hs.forEach(System.out::println);
}
结果是:按照各种集合的规则将流封装成各种集合
image.png
collect是基于Collectors实现的,而Collectors除了上面的to....之外还有
maxBy:最大
minBy:最小
summingDouble:求和
averagingDouble:平均值
counting:计数
summarizingDouble:统计,上面5种都包括
groupingBy:分组(可以自定义分组,可以多级分组)
partitioningBy:分区,将满足条件的分成一个区,不满足的分成一个区
joining:连接字符串,delimiter:分割符,prefix:前缀,suffix:后缀
reducing:归约
网友评论