Stream流的使用
使用的操作类:
Employee
package useData; import java.util.Objects; public class Employee { private int id; private String name; private int age; private double salary; public Employee(int id, String name, int age, double salary) { this.id = id; this.name = name; this.age = age; this.salary = salary; } public Employee(int id, String name) { this.id = id; this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Employee employee = (Employee) o; return id == employee.id && age == employee.age && Double.compare(employee.salary, salary) == 0 && name.equals(employee.name); } @Override public int hashCode() { return Objects.hash(id, name, age, salary); } @Override public String toString() { return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", salary=" + salary + '}'; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void setSalary(double salary) { this.salary = salary; } public int getId() { return id; } public String getName() { return name; } public int getAge() { return age; } public double getSalary() { return salary; } }
EmployeeData
package useData; 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, "马云", 30, 6020.38)); list.add(new Employee(1003, "刘强东", 29, 6300.38)); list.add(new Employee(1004, "雷军", 35, 7000.32)); list.add(new Employee(1005, "李彦宏", 32, 6000.38)); list.add(new Employee(1006, "比尔盖茨", 34, 9000.38)); list.add(new Employee(1007, "任正非", 21, 8000.38)); list.add(new Employee(1008, "扎克伯格", 49, 7000.38)); return list; } }
一、进行筛选与切片
package day12; import org.junit.Test; import useData.Employee; import useData.EmployeeData; import java.util.List; import java.util.stream.Stream; /* 筛选与切片 filter limit skip distinct */ public class StreamAPITest1 { @Test public void test1(){ List<Employee> list = EmployeeData.getEmployees(); // 1. filter(Preficate p) - 接收 Lambda, 从六种排出某些元素 Stream<Employee> stream = list.stream(); // 练习查询 员工表中 大于 7000 的 stream.filter(e->e.getSalary()>7000).forEach(System.out::println); System.out.println("---------------------------------------------------"); // 2. limit(n) - 截断流 , 使其元素不能超过给定量 // 注意这样用是错的 已经执行终止操作 需要重新给定源 // stream.limit(3).forEach(); list.stream().limit(3).forEach(System.out::println); System.out.println("---------------------------------------------------"); // 3. skip(n) 跳过前 n 条数据 list.stream().skip(3).forEach(s-> System.out.println(s)); System.out.println("---------------------------------------------------"); // distincet() -筛选 通过流所生成的元素的hashcode() 和 equals() 取出重复元素 list.add(new Employee(1003, "刘强东", 29, 6300.38)); list.add(new Employee(1003, "刘强东", 29, 6300.38)); list.add(new Employee(1003, "刘强东", 29, 6300.38)); System.out.println("去重前:"); for(Employee e: list) System.out.println(e); System.out.println("去重后:"); list.stream().distinct().forEach(System.out::println); } }
二、映射操作
package day12; import org.junit.Test; import useData.Employee; import useData.EmployeeData; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; /* 映射 map flatMap */ public class StreamAPITest2 { @Test public void test2(){ // map(function f) 接收一个函数作为参数 ,将元素转换成其他形式或者提取信息, 该函数会被应用到每个元素上, 并将其映射成一个新的元素 List<String> list = Arrays.asList("aa", "bb", "cc", "dd"); list.stream().map(s->s.toUpperCase()).forEach(s-> System.out.println(s)); System.out.println("--------------------------------------------------------"); // 练习:获取员工姓名长度大于3的员工的姓名 List<Employee> employees = EmployeeData.getEmployees(); employees.stream().map(s->s.getName()).filter(s->s.length()>3).forEach(s-> System.out.println(s)); // employees.stream().map(Employee::getName).filter().forEach(s-> System.out.println(s)); // 可以看出 map 调用后 其中仍有stream中的 stream Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest2::fromStringToStream); streamStream.forEach(s->{ s.forEach(System.out::println); }); System.out.println("--------------------------------------------------------"); // flat(Mapfunction f) 接收一个函数作为参数, 将流中的 每个值 换成 另一个流, 然后把所有流 连接成 一个 流 // 注意看 test3 的类比 map 相当于 list1.add() 而 flatMap 相当于 list1.addAll() 方法 Stream<Character> characterStream = list.stream().flatMap(StreamAPITest2::fromStringToStream); characterStream.forEach(System.out::println); } @Test public void test3(){ ArrayList list1 = new ArrayList(); list1.add(1); list1.add(2); list1.add(3); ArrayList list2 = new ArrayList(); list2.add(4); list2.add(5); list2.add(6); // list1.add(list2); // [1, 2, 3, [4, 5, 6]] list1.addAll(list2); // [1, 2, 3, 4, 5, 6] System.out.println(list1); } // 把字符串 转成对于有的 stream 的集合 public static Stream<Character> fromStringToStream(String str){ ArrayList<Character> list = new ArrayList<>(); for(Character c : str.toCharArray()){ list.add(c); } return list.stream(); } }
三、排序操作
package day12; import org.junit.Test; import useData.Employee; import useData.EmployeeData; import java.util.Arrays; import java.util.List; /* 排序 sorted */ public class StreamAPITest3 { @Test public void test4(){ // 排序的用法 // sorted : 产生一个新流, 其中按自然顺序排序 List<Integer> list = Arrays.asList(4, 1, 2, 6, 3, 0, -34); list.stream().sorted().forEach(System.out::println); System.out.println("------------------------------------------------"); List<Employee> employees = EmployeeData.getEmployees(); // employees.stream().sorted().forEach(System.out::println); // 由于 Employee 没有去实现 comparable 接口 所以不能直接用 // sorted(Comparator com) 产生一个新流, 其中按比较顺序排序 employees.stream().sorted( // (e1,e2)->{ // return e1.getAge() - e2.getAge(); // } // 或者 (e1,e2)-> e1.getAge()-e2.getAge() ).forEach(System.out::println); } }
四、终止操作
package day12; import org.junit.Test; import useData.Employee; import useData.EmployeeData; import java.util.List; import java.util.Optional; import java.util.stream.Stream; /** * 终止操作 * foreach 内部迭代 * 还有 匹配与查找 * allMatch(Predicate p) : 检查是否匹配所有元素 * anyMatch(Predicate p) : 检查 * noneMatch(Predicate p) * findFirst() * findAny() */ public class StreamAPITest4 { // 1- 匹配与查找 @Test public void test1(){ // allMatch(Predicate p) : 检查是否匹配所有元素 // 练习 是否所有员工年龄都大于35 List<Employee> employees = EmployeeData.getEmployees(); // allMatch 返回值是个 boolean 类型 boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 35); System.out.println(allMatch); // 判断是否都大于 35 返回false 说明有小于35的 // anyMatch(Predicate p) :是否有大于 指定 指定元素的 boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() < 9000); System.out.println(anyMatch); // noneMatch(Predicate p) : 检查是否没有匹配的元素 // 检查是否有姓雷的 boolean noneMatch = employees.stream().noneMatch(s -> s.getName().startsWith("雷")); System.out.println("是否有没有姓雷的:"+noneMatch); // 雷军 姓雷 所有会返回 false // findFirst() : 返回匹配到的第一个元素 / 返回流中的第一个元素 Optional<Employee> first = employees.stream().findFirst(); System.out.println("返回流中的第一个元素:"+first); // findAny : 返回当前流中的任意一个元素 Optional<Employee> first1 = employees.parallelStream().findAny(); System.out.println("返回并行流中的第一个元素:"+first1); } @Test public void test2(){ List<Employee> employees = EmployeeData.getEmployees(); // count - 返回流中元素的个数 // 默认是long 防止返回的值太大 long count = employees.stream().filter(e -> e.getSalary() > 7000).count(); System.out.println(count); // max(Comparator c) - 返回流中最大值 // 对于数值型 可能好判断 不过对于 其他类型则还是需要比较器的 Optional<Employee> max = employees.stream().max((e1, e2) -> { return Double.compare(e1.getSalary(), e2.getSalary()); }); System.out.println("薪水最多的: "+ max); // 或者这样写 Stream<Double> doubleStream = employees.stream().map(e -> e.getSalary()); Optional<Double> max1 = doubleStream.max(Double::compare); System.out.println("2薪水最多的:"+max1); // min(Comparator c) - 返回流中最小值 // 使用同上 } }
五、归约操作
package day12; import org.junit.Test; import useData.Employee; import useData.EmployeeData; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; /** * 归约 * reduce(T identity, BinaryOperator) - 可以将流中的元素进行反复结合,得到一个值。 * // 练习1: 计算 1-10中的自然和 */ public class StreamAPITest5 { @Test public void test1(){ // int 数组 转换成 列表 int[] arr = {1,2,3}; List<int[]> ints = Arrays.asList(arr); System.out.println(ints); // [[I@46ee7fe8] Stream<Integer> boxed = Arrays.stream(arr).boxed(); List<Integer> collect = boxed.collect(Collectors.toList()); // Arrays.stream(arr).collect(Collectors.toList()); System.out.println(collect); // [1, 2, 3] // Arrays.stream(arr).flatMap(s->(int)s) } @Test public void test2(){ // educe(T identity, BinaryOperator) - 可以将流中的元素进行反复结合,得到一个值。 List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10); Integer reduce = list.stream().reduce(0, Integer::sum);// 0表示初始值 sum 表示累加操作 System.out.println(reduce); // 计算所有员工工资的总和 List<Employee> employees = EmployeeData.getEmployees(); Stream<Double> salaryStream = employees.stream().map(e -> e.getSalary()); Double doubleSum = salaryStream.reduce(0.0, Double::sum); // 下面一种写法也是可以的 System.out.println("薪资总和: "+doubleSum); Optional<Double> sumMoney = employees.stream().map(e -> e.getSalary()).reduce((d1, d2)-> d1+d2); // 自己求 不使用 sum System.out.println("薪资总和: "+sumMoney); Optional<Double> sumMoney2 = employees.stream().map(e -> e.getSalary()).reduce(Double::sum); // 自己求 不使用 sum System.out.println("薪资总和: "+sumMoney2); } }
六、收集操作
package day12; import org.junit.Test; import useData.Employee; import useData.EmployeeData; import java.util.List; import java.util.stream.Collectors; /** * 收集操作 : * collect(Collector c) : 将流转换为其他形式。 接收一个 Collector 接口的实现, 用于给 Stream 中的元素汇总的方法 * Collector 接口中的方法的实现决定了如何对流执行收集的操作(如 收集到 List、Set、Map) */ public class StreamAPITest6 { @Test public void test1(){ // 查找工资大于 7000的员工, 结果返回一个 List 或者 Set List<Employee> employees = EmployeeData.getEmployees(); List<Employee> list = employees.stream().filter(s -> s.getSalary() > 7000).collect(Collectors.toList()); list.forEach(System.out::println); } }