Stream Api
基于尚硅谷java8教程
1. Stream说明
stream api位于java.util.stream包下。它是对集合操作功能的增强,它可以提高编程效率。
注意:
- stream可以对集合进行过滤、转换等操作,他的操作是lazy的。它会把转换处理操作汇总起来最后经过一次循环形成处理的最终结果,在数据处理转换过程中是数据时不会进行输出的
2. Stream使用方式
Stream api的处理流程包含如下三个方面:
-
- 创建Stream
-
- Stream转换处理
-
- 终止处理
( I ) 常用的创建Stream方式如下:
①通过Collection接口提供的方法创建
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();/**创建串行流**/
Stream<String> stream1 = list.parallelStream();//创建并行流
②通过Stream接口的工厂方法
/*第一种*/
Stream<Integer> stream = Stream.of(1,2,3,4,5);
/*第二种,无限流 生成方式*/
Stream<Double> stream1 = Stream.generate(()->Math.random()).limit(10);
/*第三种,无限流 迭代方式*/
Stream<Integer> stream2 = Stream.iterate(0,(x)->x+2).limit(10);
( II ) 常用的数据转换方式如下:
方法名 | 说明 |
---|---|
filter | 过滤,从指定的流程中排除某些元素 |
limit | 截断,类似于mysql的limit,限定返回的元素个数 |
skip(n) | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 |
distinct | 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 |
map | 对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。这个方法有三个对于原始类型的变种方法,分别是:mapToInt,mapToLong和mapToDouble。这三个方法也比较好理解,比如mapToInt就是把原始Stream转换成一个新的Stream,这个新生成的Stream中的元素都是int类型。之所以会有这样三个变种方法,可以免除自动装箱/拆箱的额外消耗 |
flatMap | 和map类似,不同的是其每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到父集合中 |
sorted(Comparator com) | 按照comparator指定的顺序排序,如果不写comparator方法将进行自然排序 |
注意:
- flatmap和map的区别:如果使用的是map方法,返回的是[ …[‘y’, ‘o’, ‘u’, ‘r’], [‘n’, ‘a’, ‘m’, ‘e’]…]
如果使用的是flatMap方法,返回的是[…‘y’, ‘o’, ‘u’, ‘r’, ‘n’, ‘a’, ‘m’, ‘e’…],详情可以参考范例中flatmap部分
( III ) 常用的终止处理方式如下:
方法名 | 说明 |
---|---|
allMatch | 检查是否匹配所有元素 |
anyMatch | 检查是否至少匹配一个元素 |
noneMatch | 检查是否没有匹配的元素 |
findFirst | 返回第一个元素 |
findAny | 返回当前流中的任意元素 |
count | 返回流中元素的总个数 |
max | 返回流中最大值 |
min | 返回流中最大值 |
reduce | 可以将流中元素反复结合起来,得到一个值,与Hadoop中reduce的原理一致 |
collect | 将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法 |
注意:
-
流在进行了终止操作后,不能在继续使用;
-
collect常用方法:
①获取最大值:map(Employee::getSalary).collect(Collectors.maxBy(Double::compare))
②获取最小值:collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())))
③获取总和:.collect(Collectors.summingDouble(e -> e.getSalary()))
④获取平均值:.collect(Collectors.averagingDouble(e -> e.getSalary()))
⑤获取统计值,然后可以根据统计值获取max/min/avg等值:.collect(Collectors.summarizingDouble(e -> e.getSalary())).getMax()
⑥分组:
.collect(Collectors.groupingBy(e -> {
if (e.getAge() > 50) {return “老年”;} else {return “成年”;}}))
⑦分区:collect(Collectors.partitioningBy(e -> e.getSalary() > 5000)) -
reduce和collection的区别:
Stream.reduce:常用的方法有average, sum, min, max, and count,返回单个的结果值,并且reduce操作每处理一个元素总是创建一个新值
Stream.collect与stream.reduce方法不同,Stream.collect修改现存的值,而不是每处理一个元素,创建一个新值,可以参见范例进行理解
3. 范例
package com.seven.jdk8;
import com.seven.pojo.Employee;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamTest {
List<Employee> employeeList = Arrays.asList(
new Employee(1,"张三",7753.25,30),
new Employee(2,"李四",1853.25,45),
new Employee(3,"王五",9753.25,51),
new Employee(4,"赵六",5653.25,45),
new Employee(5,"钱七",2553.25,27),
new Employee(5,"钱七",2553.25,27)
);
/** 创建 stream **/
@Test
public void test1(){
// 第一种
Stream<Integer> stream = Stream.of(1,2,3,4,5);
// 第二种,无限流 生成方式
Stream<Double> stream1 = Stream.generate(()->Math.random()).limit(10);
// 第三种,无限流 迭代方式
Stream<Integer> stream2 = Stream.iterate(0,(x)->x+2).limit(10);
stream2.forEach(System.out::println);
}
/** 通过stream进行数据转换 **/
// filter、limit、skip,distinct
@Test
public void test2(){
// filter
Stream<Employee> stream = employeeList.stream().filter( emp -> {
System.out.println("employee 正在进行过滤操作。。");
return emp.getAge()< 35;
});
//注意:只有进行终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”
stream.forEach(System.out::println);
//limit
System.out.println("----------------------limit-----------------------------");
employeeList.stream().limit(2).forEach(System.out::println);
// skip
System.out.println("------------------------skip----------------------------");
employeeList.stream().skip(2).forEach(emp -> System.out.print(emp.getName()+",,,,"));
// distinct
System.out.println();
System.out.println("-------------------------distinct-----------------------------");
employeeList.stream().distinct().forEach(emp -> System.out.print(emp.getName()+",,,,"));
}
// map、flatmap、sort
@Test
public void test3(){
System.out.println("----------------------------map----------------------------------");
List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee");
list.stream().map(str -> {
return str.toUpperCase();
}).forEach(System.out::print);
System.out.println();
System.out.println("----------------------------flatmap----------------------------------");
Stream.of(Arrays.asList(1, 2), Arrays.asList(3, 4)) // Stream of List<Integer>
.flatMap(numbers -> numbers.stream())
.map(integer -> integer + 1)
.collect(Collectors.toList())
.forEach(System.out::print);
System.out.println();
System.out.println("-------------------------------sort--------------------------------------");
employeeList.stream().map(e->e.getName()).sorted().forEach(System.out::println);
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
employeeList.stream().sorted((emp1,emp2)->{
if(emp1.getAge() == emp2.getAge()){
return emp1.getName().compareToIgnoreCase(emp2.getName());
}else{
return Integer.compare(emp1.getAge(),emp2.getAge());
}
}).forEach(System.out::println);
}
/** 终止处理 **/
@Test
public void test4() {
System.out.println("-------------------------------allMatch/anyMatch---------------------------------");
boolean flag = employeeList.stream().allMatch(e1 -> e1.getName().equals("张三"));
boolean flag2 = employeeList.stream().anyMatch(e1 -> e1.getName().equals("张三"));
System.out.println("allMatch-->" + flag + ",,,anyMatch-->" + flag2);
System.out.println("---------------------------------findfirst-----------------------------------------");
Optional<Employee> opt1 = employeeList.stream().sorted((emp1, emp2) -> Double.compare(emp1.getSalary(), emp2.getSalary())).findFirst();
System.out.println(opt1.get());
System.out.println("---------------------------------count-----------------------------------------");
long count = employeeList.stream().count();
System.out.println("employeeList.size = " + count);
System.out.println("---------------------------------max-----------------------------------------");
Optional<Employee> max = employeeList.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(max.get());
System.out.println("---------------------------------reduce-----------------------------------------");
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer reduce = list.stream().reduce(0, (x, y) -> x + y);
System.out.println("count list-->"+reduce);
Optional<Double> sumSalary = employeeList.stream().map(e -> e.getSalary()).reduce((s1, s2) -> Double.sum(s1, s2));
System.out.println("sum salary-->"+sumSalary.get());
System.out.println("---------------------------------collect-----------------------------------------");
List<String> listCollect = employeeList.stream().map(e -> e.getName()).collect(Collectors.toList());
listCollect.stream().forEach(System.out::println);
//假如要转换成hashset
HashSet<String> nameHashSet = employeeList.stream().map(e -> e.getName()).collect(Collectors.toCollection(() -> new HashSet<String>()));
nameHashSet.stream().forEach(System.out::print);
DoubleSummaryStatistics countSalary = employeeList.stream().collect(Collectors.summarizingDouble(e -> e.getSalary()));
System.out.println("count salary-->"+countSalary.getSum()+",,,"+countSalary.getMax());
Double average = employeeList.stream().collect(Collectors.averagingDouble(e -> e.getSalary()));
Double sum1 = employeeList.stream().collect(Collectors.summingDouble(e -> e.getSalary()));
System.out.println("average salary -->"+average+",,,sum salary-->"+sum1);
System.out.println("~~~~分组~~~~~");
Map<String, List<Employee>> groupMap = employeeList.stream().collect(Collectors.groupingBy(e -> {
if (e.getAge() > 50) {
return "老年";
} else if (e.getAge() > 35) {
return "中年";
} else {
return "成年";
}
}));
System.out.println(groupMap);
System.out.println("~~~~多级分组~~~~~");
Map<String, Map<String, List<Employee>>> multiMap = employeeList.stream().collect(Collectors.groupingBy((e) -> {
if (e.getAge() > 50) {
return "老年";
} else if (e.getAge() > 35) {
return "中年";
} else {
return "成年";
}
}, Collectors.groupingBy(e1 -> {
if (e1.getSalary() > 5000) {
return "高收入";
} else {
return "低收入";
}
})));
System.out.println(multiMap);
System.out.println("~~~~~分区~~~~~~~");
Map<Boolean, List<Employee>> partitionMap = employeeList.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > 5000));
System.out.println(partitionMap);
}
}
源代码地址:http://git.oschina.net/johnny/java_base