Stream API的使用
前言
个人笔记,仅供参考。
一、Stream API说明
1.1、引入说明
- Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API。
- Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
- Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执非常复杂的查找、过滤和映射数据等操作。 使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
1.1.1、为什么要使用Stream API
- 实际开发中,项目中多数数据源都来自于Mysql,Oracle等。但现在数据源可以更多了,有MongDB,Radis等,而这些NoSQL的数据就需要Java层面去处理。
- Stream 和 Collection 集合的区别:Collection 是一种静态的内存数据结构,而 Stream 是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向 CPU,通过 CPU 实现计算。
1.1.2、什么是 Stream
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,Stream讲的是计算!”
注意:
- ①Stream 自己不会存储元素。
- ②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
- ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
1.2、使用说明
1.2.1、Stream 的操作三个步骤
- 1- 创建 Stream
一个数据源(如:集合、数组),获取一个流 - 2- 中间操作
一个中间操作链,对数据源的数据进行处理 - 3- 终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
二、Stream流的使用
数据准备
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));
return list;
}
}
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() {
}
public Employee(int id) {
this.id = 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;
}
}
2.1、四种创建方式
/*1、通过集合*/
@Test
public void test1(){
List<Employee> employeeList = new ArrayList<>();
/* 创建顺序流:default Stream<E> stream; */
Stream<Employee> stream = employeeList.stream();
/* 创建并行流:default Stream<E> parallelStream(); */
Stream<Employee> parallelStream = employeeList.parallelStream();
}
/*2、通过数组*/
@Test
public void test2(){
/*static <T> Stream<T> stream(T[] array): 返回一个流*/
Integer[] arr = {1,2,1,2,3,5};
Stream<Integer> stream = Arrays.stream(arr);
int[] intArr = {1,2,5,8,5,2};
IntStream stream1 = Arrays.stream(intArr);
}
/*3、通过Stream的of()*/
@Test
public void tes3(){
/*public static<T> Stream<T> of(T... values) : 返回一个流*/
Stream<String> stream = Stream.of("AA", "BB", "CC");
}
/*4、创建无限流*/
@Test
public void test4(){
/* 迭代
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)*/
/* 生成
public static<T> Stream<T> generate(Supplier<T> s)*/
}
2.2、常用中间操作
/* 一、筛选与切片*/
@Test
public void test1(){
List<Employee> employeeList = EmployeeData.getEmployees();
Stream<Employee> stream = employeeList.stream();
/* 1、filter(Predicate P),接收lambda,从流中过滤出符合条件的数据。
filter查询出员工中工资大于7000的员工
*/
stream.filter(employee -> employee.getSalary() > 7000 ).forEach(System.out::println);
System.out.println();
/* 2、limit(n)-截断流,使其元素不超过给定数量
查询工资大于7000的前两条数据
*/
employeeList.stream().filter(employee -> employee.getSalary() > 7000 ).limit(2).forEach(System.out::println);
System.out.println();
/* 3、skip(n)-截断流,跳过前n个数据
查询工资大于7000的前两条数据之外的数据
*/
employeeList.stream().filter(employee -> employee.getSalary() > 7000 ).skip(2).forEach(System.out::println);
/*
* 4、distinct()-筛选,通过流生成的hashcode和equals()
根据姓名去重
*/
employeeList.add(new Employee(1006, "比尔盖茨", 42, 9500.43));
employeeList.add(new Employee(1007, "任正非", 26, 4333.32));
employeeList.add(new Employee(1008, "扎克伯格", 35, 2500.32));
employeeList.stream().distinct().forEach(System.out::println);
}
/* 二、映射*/
@Test
public void test(){
List<String> list = Arrays.asList("A", "BB", "CCC");
/* 1、map(Function f):接受一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每一个元素上
将集合中的全部元素转换成小写
*/
list.stream().map(String::toLowerCase).forEach(System.out::println);
list.stream().map(str -> str.toLowerCase()).forEach(System.out::println);
System.out.println();
/*
* 获取员工中的员工名称长度大于三的员工
*/
List<Employee> employeeList = EmployeeData.getEmployees();
employeeList.stream().filter(emp -> emp.getName().length() > 3).forEach(System.out::println);
/*
* 获取员工中的员工名称长度大于三的员工姓名
*/
employeeList.stream().filter(emp -> emp.getName().length() > 3).map(emp -> emp.getName()).forEach(System.out::println);
System.out.println();
employeeList.stream().map(emp -> emp.getName()).filter(emp -> emp.length() > 3).forEach(System.out::println);
System.out.println();
employeeList.stream().map(Employee::getName).filter(emp -> emp.length() > 3).forEach(System.out::println);
}
/* 三、排序*/
@Test
public void test3(){
Integer[] intArr = {22,5,6,8,52,54,63};
String[] strArr = {"AA","JJ","BB","GG"};
/* sorted()--自然排序*/
Arrays.stream(intArr).sorted().forEach(System.out::println);
Arrays.stream(strArr).sorted().forEach(System.out::println);
/* sorted(Comparator com)--定制排序*/
List<Employee> employeeList = EmployeeData.getEmployees();
employeeList.stream().sorted((e1,e2) -> (int) (e1.getSalary() - e2.getSalary())).forEach(System.out::println);
Arrays.stream(intArr).sorted((s1, s2) -> -s1.compareTo(s2)).forEach(System.out::println);
}
2.3、终止操作
/*一、匹配与查找*/
@Test
public void test1(){
List<Employee> employeeList = EmployeeData.getEmployees();
// allMatch(Predicate p) 是否所有员工的年龄都大于30
System.out.println(employeeList.stream().allMatch(e -> e.getAge() > 30));
// anyMatch(Predicate p) 是否存在员工年龄大于40的员工
System.out.println(employeeList.stream().anyMatch(emp -> emp.getAge() > 40));
// 是否有员工工资大于一万的数据
System.out.println(employeeList.stream().anyMatch(emp -> emp.getSalary() > 10000));
// findFirst(Predicate p) 返回符合条件的第一个元素
System.out.println(employeeList.stream().filter(emp -> emp.getName().length() > 3).findFirst().get());
}
@Test
public void test2(){
List<Employee> employeeList = EmployeeData.getEmployees();
// count() 返回流中元素的总个数
// 统计工资大于7000的员工的个数
System.out.println(employeeList.stream().filter(emp -> emp.getSalary() > 7000).count());
// max(Comparator com) 返回流中元素最大值
// 返回流中最高的工资
System.out.println(employeeList.stream().map(employee -> employee.getSalary()).max(Double::compare).get());
// min(Comparator com) 返回流中元素最小值
// 返回流中最低的工资的员工信息
System.out.println(employeeList.stream().min(Comparator.comparingDouble(Employee::getSalary)).get());
//forEach(Consumer c) 内部迭代
// employeeList.stream().forEach(System.out::println);
// 针对于集合java 8 增加了forEach()方法
employeeList.forEach(System.out::println);
}
/* 二、归约 */
@Test
public void test3(){
List<Employee> employeeList = EmployeeData.getEmployees();
// reduce(T identity,BinaryOperator) - 将流中的元素反复结合起来得到一个新值,返回T
// 计算1-10的自然数之和
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.println(list.stream().reduce(0, (x, y) -> x + y));
System.out.println(list.stream().reduce(0, (x, y) -> Integer.sum(x, y)));
System.out.println(list.stream().reduce(0, Integer::sum));
// reduce(BinaryOperator) - 将流中的元素反复结合起来得到一个新值,返回Optional<T>
// 计算所有员工的工资之和
System.out.println(employeeList.stream().map(Employee::getSalary).reduce(0.0, (x, y) -> x + y));
System.out.println(employeeList.stream().map(Employee::getSalary).reduce(0.0, (x, y) -> Double.sum(x, y)));
System.out.println(employeeList.stream().map(Employee::getSalary).reduce(0.0, Double::sum));
}
/* 三、收集 */
@Test
public void test4(){
List<Employee> employeeList = EmployeeData.getEmployees();
// collect(Collect c) 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream流中元素做汇总的方法
// 查找工资大于6000的员工,并返回一个新的list或者set
System.out.println(employeeList.stream().filter(emp -> emp.getSalary() > 70000).collect(Collectors.toList()));
Set<Employee> set = employeeList.stream().filter(emp -> emp.getSalary() > 7000).collect(Collectors.toSet());
set.stream().forEach(System.out::println);
// 按照员工的年龄进行排序,返回到一个新的list中
System.out.println(employeeList.stream().sorted((e1, e2) -> (int) (e1.getSalary() - e2.getSalary())).collect(Collectors.toList()));
}