Java8-Stream API
Java8-Stream API笔记参考视频:https://www.bilibili.com/video/BV184411x7XA?p=19什么是StreamStream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。Stream关注的是对数据的运算注:Stream自己不会存储元素Stream不会改变源对象,而是返回一个持有结果的新StreamStream操作是延迟执行的,即会等到需
·
Java8-Stream API
笔记参考视频:https://www.bilibili.com/video/BV184411x7XA?p=19
什么是Stream
Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
Stream关注的是对数据的运算
注:
- Stream自己不会存储元素
- Stream不会改变源对象,而是返回一个持有结果的新Stream
- Stream操作是延迟执行的,即会等到需要结果的时候才执行
Stream操作的三个步骤
- 创建Stream(实例化)
一个数据源(如:集合、数组),获取一个流
- 中间操作(过滤、映射等)
一个中间操作链,对数据源的数据进行处理
- 终止操作
一旦执行终止操作,就执行中间操作链,并产生结果。
实体类Employee
public class Employee {
private int id;
private String name;
private int age;
private double salary;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Employee() {
System.out.println("Employee().....");
}
public Employee(int id) {
this.id = id;
System.out.println("Employee(int id).....");
}
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public Employee(int id, String name, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", salary=" + salary + '}';
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Employee employee = (Employee) o;
if (id != employee.id)
return false;
if (age != employee.age)
return false;
if (Double.compare(employee.salary, salary) != 0)
return false;
return name != null ? name.equals(employee.name) : employee.name == null;
}
@Override
public int hashCode() {
int result;
long temp;
result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + age;
temp = Double.doubleToLongBits(salary);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
}
生成数据的类
import java.util.ArrayList;
import java.util.List;
public class EmployeeData {
public static List<Employee> getEmployees(){
List<Employee> list = new ArrayList<>();
list.add(new Employee(1001, "马化腾", 34, 6000.38));
list.add(new Employee(1002, "马云", 12, 9876.12));
list.add(new Employee(1003, "刘强东", 33, 3000.82));
list.add(new Employee(1004, "雷军", 26, 7657.37));
list.add(new Employee(1005, "李彦宏", 65, 5555.32));
list.add(new Employee(1006, "比尔盖茨", 42, 9500.43));
list.add(new Employee(1007, "任正非", 26, 4333.32));
list.add(new Employee(1008, "扎克伯格", 35, 2500.32));
list.add(new Employee(1009, "张三", 26, 6666));
return list;
}
}
Stream的实例化
方法1 通过集合创建Stream
@Test
public void test1(){
List<Employee> employees = EmployeeData.getEmployees();
//返回一个顺序流
Stream<Employee> stream = employees.stream();
//返回一个并行流
Stream<Employee> parallelStream = employees.parallelStream();
}
方法2 通过数组创建Stream
@Test
public void test2(){
int[] arr = new int[]{1,2,3,4,5,6};
//调用Arrays类的static<T> Stream<T> stream(T[] array) 返回一个流
IntStream stream = Arrays.stream(arr);
Employee e1 = new Employee(1001,"Tom");
Employee e2 = new Employee(1002,"Sam");
Employee[] arr1 = new Employee[]{e1,e2};
Stream<Employee> stream1 = Arrays.stream(arr1);
}
方法3 通过Stream的of()
@Test
public void test3(){
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
}
方法4 创建无限流
@Test
public void test4(){
//迭代
//public static<T> Stream<T> iterate(final T seed,final UnaryOperator<T> f)
//遍历前十个偶数
Stream.iterate(0,t->t+2).limit(10).forEach(System.out::println);
//生成
//public static<T> Stream<T> generate(Supplier<T> s)
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
Stream的中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
1.筛选与切片
方法 | 描述 |
---|---|
filter(Predicate p) | 接收Lambda,从流中排除某些元素 |
distinct() | 筛选,通过流所生成元素的hashCode()和equals()去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量 |
skip(long n) | 跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补 |
@Test
public void test1(){
/**
* 筛选与切片
* */
// * | filter(Predicate p) | 接收Lambda,从流中排除某些元素 |
System.out.println("-------------------------------------filter-------------------------------------");
List<Employee> list = EmployeeData.getEmployees();
Stream<Employee> stream = list.stream();
stream.filter(e->e.getSalary()>7000).forEach(System.out::println);
// * | limit(long maxSize) | 截断流,使其元素不超过给定数量 |
System.out.println("-------------------------------------limit-------------------------------------");
list.stream().limit(3).forEach(System.out::println);
// * | skip(long n) | 跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补 |
System.out.println("-------------------------------------skip-------------------------------------");
list.stream().skip(3).forEach(System.out::println);
// * | distinct() | 筛选,通过流所生成元素的hashCode()和equals()去除重复元素 |
System.out.println("-------------------------------------distinct-------------------------------------");
list.add(new Employee(1003,"刘强东",33,3000.82));
list.add(new Employee(1003,"刘强东",33,3000.82));
list.add(new Employee(1003,"刘强东",33,3000.82));
list.add(new Employee(1003,"刘强东",33,3000.82));
list.add(new Employee(1003,"刘强东",33,3000.82));
System.out.println("筛选前:");
System.out.println(list);
System.out.println("筛选后:");
list.stream().distinct().forEach(System.out::println);
}
2.映射
方法 | 描述 |
---|---|
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的DoubleStream |
mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的IntStream |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的LongStream |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 |
@Test
public void test2(){
/**
* 映射
* */
// map(Function f)接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
System.out.println("-------------------------------------map-------------------------------------");
List<String> list = Arrays.asList("a1", "b2", "c3", "d4", "e5");
list.stream().map(str->str.toUpperCase()).forEach(System.out::println);
System.out.println("练习1:获取员工姓名长度大于3的员工的姓名。");
List<Employee> list0 = EmployeeData.getEmployees();
// map
list0.stream().map(Employee::getName).filter(str->str.length() > 3).forEach(System.out::println);
System.out.println("练习2");
System.out.println("-------------------------------------map-------------------------------------");
Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest1::fromStringToStream);
streamStream.forEach(s->{
s.forEach(System.out::println);
});
System.out.println("-------------------------------------flatmap-------------------------------------");
list.stream().flatMap(StreamAPITest1::fromStringToStream).forEach(System.out::println);
}
// 将字符串中的多个字符构成的集合转换为对应的Stream的实例
public static Stream<Character> fromStringToStream(String str){
ArrayList<Character> list = new ArrayList<>();
for (Character c : str.toCharArray()){
list.add(c);
}
return list.stream();
}
3.排序
方法 | 描述 |
---|---|
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator com) | 产生一个新流,其中按比较器顺序排序 |
@Test
public void test3(){
//| sorted() | 产生一个新流,其中按自然顺序排序 |
System.out.println("-------------------------------------sorted()自然排序-------------------------------------");
List<Integer> list = Arrays.asList(11, 22, 33, 44, 88, 21, 2, 53, 6);
list.stream().sorted().forEach(System.out::println);
//| sorted(Comparator com) | 产生一个新流,其中按比较器顺序排序 |
System.out.println("-------------------------------------sorted(Comparator com)定制排序-------------------------------------");
System.out.println("按年龄排序");
List<Employee> employeeList = EmployeeData.getEmployees();
employeeList.stream().sorted((e1,e2)-> Integer.compare(e1.getAge(), e2.getAge())).forEach(System.out::println);
//年龄相同时按工资排序
System.out.println("年龄相同时按工资排序");
employeeList.stream().sorted(
(e1,e2)->{
int temp = Integer.compare(e1.getAge(), e2.getAge());
// System.out.println(temp);
// System.out.println("000000");
if (temp!=0){
return temp;
}else {
return Double.compare(e1.getSalary(),e2.getSalary());
}
}
).forEach(System.out::println);
}
Stream的终止操作
1.匹配与查找
方法 | 描述 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否匹配至少一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中的任意元素 |
count() | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代(使用Collection接口需要用户做迭代,称为外部迭代。相反,Stream API使用内部迭代) |
import org.junit.Test;
import java.util.List;
import java.util.Optional;
public class StreamAPITest2 {
@Test
public void test1(){
/**
* 匹配与查找
* */
//| allMatch(Predicate p) | 检查是否匹配所有元素 |
System.out.println("-------------------------------------allMatch-------------------------------------");
System.out.println("练习1:是否所有的员工年龄都大于18");
List<Employee> list = EmployeeData.getEmployees();
boolean result1 = list.stream().allMatch(e -> e.getAge() > 18);
System.out.println(result1);
//| anyMatch(Predicate p) | 检查是否匹配至少一个元素 |
System.out.println("-------------------------------------anyMatch-------------------------------------");
System.out.println("练习2:是否存在员工的工资大于4000");
boolean result2 = list.stream().anyMatch(e -> e.getSalary() > 4000);
System.out.println(result2);
//| noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
System.out.println("-------------------------------------noneMatch-------------------------------------");
System.out.println("练习3:是否没有员工姓“雷”");
boolean result3 = list.stream().noneMatch(e -> e.getName().startsWith("雷") );
System.out.println(result3);
//| findFirst() | 返回第一个元素 |
System.out.println("-------------------------------------findFirst-------------------------------------");
System.out.println("练习4:按年龄从小到大排序并返回第一个结果(返回年龄最小的)");
Optional<Employee> result4 = list.stream().sorted((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())).findFirst();
System.out.println(result4);
//| findAny() | 返回当前流中的任意元素 |
System.out.println("-------------------------------------findAny-------------------------------------");
System.out.println("练习5:随机返回一个流中的结果");
System.out.println("串行流:每次返回的结果都是list中的第一个数据");
Optional<Employee> result5 = list.stream().findAny();
System.out.println(result5);
System.out.println("并行流:每次返回的结果都不同,但对同一个源的多次调用可能不会返回相同的结果。");
Optional<Employee> result6 = list.parallelStream().findAny();
System.out.println(result6);
System.out.println("-------------------------------------count-------------------------------------");
long count = list.stream().filter(employee -> employee.getSalary() > 5000).count();
System.out.println("工资大于5000的人数:"+count);
System.out.println("-------------------------------------max-------------------------------------");
Optional<Employee> max = list.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println("工资最多的员工:"+max);
System.out.println("-------------------------------------min-------------------------------------");
Optional<Employee> min = list.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println("工资最少的员工:"+min);
System.out.println("-------------------------------------forEach-------------------------------------");
list.stream().forEach(System.out::println);
}
}
2.归约
方法 | 描述 |
---|---|
reduce(T iden,BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回T |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回Optional |
@Test
public void test2(){
/**
* 归约
* */
//| reduce(T iden,BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回T |
//练习1:计算1-10的自然数的和
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer re = list.stream().reduce(0, Integer::sum);//identity:初始值
System.out.println(re);
//| reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回Optional<T> |
//练习2:计算所有员工工资总和
List<Employee> employeeList = EmployeeData.getEmployees();
Optional<Double> reduce = employeeList.stream().map(e -> e.getSalary()).reduce(Double::sum);
System.out.println(reduce);
Optional<Double> reduce1 = employeeList.stream().map(e -> e.getSalary()).reduce((s1,s2)->s1+s2);
System.out.println(reduce1);
}
3.收集
方法 | 描述 |
---|---|
collect(Collector c) | 将流转换为其他形式。接收以一个Collector接口的实现,用于给Stream中元素做汇总的方法 |
Collector接口中方法的实现决定了如何对流执行收集的操作(如收集到List、Set、Map),且Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例,常用方法如下表:
方法 | 描述 |
---|---|
toList | 把流中的元素收集到List |
toSet | 把流中的元素收集到Set |
toCollection | 把流中的元素收集到自定义的集合中 |
joining | 连接流中的每个字符串 |
counting | 计算流中元素个数 |
averagingDouble | 计算流中Double属性元素的平均值 |
summingDouble | 计算流中Double属性元素的和 |
summarizingDouble | 收集流中Double属性的统计值 |
groupingBy | 根据属性的值对流进行分组 |
partitioningBy | 根据true或false对数据进行分区 |
将流转换为其他形式
@Test
public void test3(){
/**
* 收集
* */
//collect(Collector c)将流转换为其他形式。接收以一个Collector接口的实现,用于给Stream中元素做汇总的方法
//练习1:查找工资大于6000的员工,结果返回为一个List或Set
List<Employee> employeeList = EmployeeData.getEmployees();
System.out.println("-------------------------------------toList-------------------------------------");
List<Employee> collect = employeeList.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
collect.forEach(System.out::println);
System.out.println("-------------------------------------toSet-------------------------------------");
Set<Employee> collect1 = employeeList.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
collect1.forEach(System.out::println);
System.out.println("-------------------------------------toCollection自定义实现-------------------------------------");
System.out.println("LinkedList:");
LinkedList<Employee> collect2 = employeeList.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toCollection(LinkedList::new));
collect2.forEach(System.out::println);
System.out.println("Vector:");
Collection<Employee> collect3 = employeeList.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toCollection(Vector::new));
collect3.forEach(System.out::println);
}
字符串连接
@Test
public void test4(){
System.out.println("-------------------------------------joining-------------------------------------");
List<String> list = Arrays.asList("AAA","BBB","CCC","ddd","eee","fff","GGG","hhh");
System.out.println("不指定连接符");
String collect4 = list.stream().collect(Collectors.joining(""));
System.out.println(collect4);
System.out.println("指定连接符");
String collect5 = list.stream().collect(Collectors.joining("---"));
System.out.println(collect5);
System.out.println("指定连接符以及前后缀");
String collect6 = list.stream().collect(Collectors.joining("---","前缀","后缀"));
System.out.println(collect6);
}
统计
@Test
public void test5(){
List<Employee> list = EmployeeData.getEmployees();
System.out.println("-------------------------------------count-------------------------------------");
Long count = list.stream().collect(Collectors.counting());
System.out.println(count);
System.out.println("-------------------------------------average(以averagingDouble为例)-------------------------------------");
Double averageSalary = list.stream().collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println("平均工资:"+averageSalary);
System.out.println("-------------------------------------summing(以summingDouble为例)-------------------------------------");
Double totalSalary = list.stream().collect(Collectors.summingDouble(Employee::getSalary));
System.out.println("总工资:"+totalSalary);
System.out.println("-------------------------------------summarizing(以summarizingDouble为例)-------------------------------------");
DoubleSummaryStatistics summarizingResult = list.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println("统计结果:"+summarizingResult);
System.out.println("-------------------------------------groupingBy-------------------------------------");
Map<Integer, List<Employee>> groupByResult = list.stream().collect(Collectors.groupingBy(Employee::getAge));
System.out.println("分组结果:");
for (Integer s : groupByResult.keySet()) {
System.out.println("key:" + s);
System.out.println("values:" + groupByResult.get(s));
}
System.out.println("-------------------------------------partitioningBy-------------------------------------");
Map<Boolean, List<Employee>> partitioningByResult = list.stream().collect(Collectors.partitioningBy(e -> e.getAge() > 35));
System.out.println("分区结果:");
for (Boolean s : partitioningByResult.keySet()) {
System.out.println("key:" + s);
System.out.println("values:" + partitioningByResult.get(s));
}
}
更多推荐
已为社区贡献2条内容
所有评论(0)