java8新特性之stream流

Stream 流是 Java 8 提供给开发者一套新的处理集合的API,他把我们将要处理的集合作为流,就像流水线一样,我们可以对其中的元素进行筛选,过滤,排序等中间操作,只不过这种操作更加简洁高效。

Stream的创建:
  • 1.可以通过Collection系列的集合提供的stream()或者parallelStream()方法,集合的stream方法创建的是串行流,parallelStream方法创建的是并行流(并行流就是多线程进行操作,这个时候就要考虑线程安全问题了)
  • 2.可以通过Arrays.stream()获取数组流
  • 3.通过Stream类中的静态方法of()可以创建流对象
  • 当创建一个无限流使用Stream.iterate()方法,是一个死循环

//Stream 的创建


    //1.通过集合的stream()方法创建串行流
    ArrayList<Object> list = new ArrayList<>();
    Stream<Object> stream = list.stream();
    //2.也可以通过集合的parallelStream创建并行流
    Stream<Object> parallelStream = list.parallelStream();
    //3.通过Arrays.stream(T[] t),将数组转换成流
    IntStream stream1 = Arrays.stream(new int[10]);
    //4.通过Stream的静态方法of创建流
    Stream<String> stringStream = Stream.of("aaa", "bbb", "ddd", "ccc");
    
    //创建无限流 迭代   
    Stream<Integer> iterate = Stream.iterate(1, (x) -> x + 2);
    iterate.limit(10).forEach(System.out::println);//生成奇数从一开始往后的10位

    //生成
    Stream.generate(()->(int)(Math.random()*100))//随机生成10个100以内的int类型数
            .limit(10)
            .forEach(System.out::println);
Stream的中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线线上触发终止操作,否则中间操作就不会执行任何处理,并不会显示处理结果。而在终止操作时一次性全部处理,称为惰性求值。

  • 筛选与切片

filter-接收Lambda,从流中排除某些元素
limit–截断流,使其元素不超过给定数量
skip(n) – 跳过元素,返回一个扔掉了前n个元素的流。若流中的元素个数小于n,则返回null,与limit()互补
distinct–筛选通过流所生成元素的hashCode(),equals()方法来去掉重复的元素

public class StreamAPITest {
    List<Employee> employees = Arrays.asList(
            new Employee("小明", 12000, 32),
            new Employee("小红", 8000, 23),
            new Employee("小刚", 5000, 19),
            new Employee("小凉", 7000, 40),
            new Employee("小凉", 7000, 40),
            new Employee("小凉", 7000, 40)
    );

    @Test
    public void test2() {
        //filter是内部迭代,
        //也就是StreamAPI内部实现的迭代不需要使用者再次手写迭代
        employees.stream()
                .filter((e) -> {
                    //System.out.println("进入过滤器");
                    return e.getSalary() > 7000.0;
                })
                .forEach((e) -> System.out.println(e.getSalary()));
        System.out.println("-----------------------");


        //测试limit(n)取前n个元素
        employees.stream()
                .limit(3)
                .forEach((e) -> System.out.println(e));

        System.out.println("-----------------------");
        //skip(n)测试  舍掉前n个元素,去剩下后面的
        employees.stream()
                .skip(3)
                .forEach((e) -> System.out.println(e));


        System.out.println("=============================");
        //distinct()去除重复,按照streamAPI中的hashCode和equals方法
        employees.stream()
                .distinct()
                .forEach((e) -> System.out.println(e));
    }
}

注意:distinct方法去除重复,需要实现pojo的hashCode()和equals().
控制台输出:

12000.0
8000.0
-----------------------
Employee{name='小明', salary=12000.0, age=32}
Employee{name='小红', salary=8000.0, age=23}
Employee{name='小刚', salary=5000.0, age=19}
-----------------------
Employee{name='小凉', salary=7000.0, age=40}
Employee{name='小凉', salary=7000.0, age=40}
Employee{name='小凉', salary=7000.0, age=40}
=============================
Employee{name='小明', salary=12000.0, age=32}
Employee{name='小红', salary=8000.0, age=23}
Employee{name='小刚', salary=5000.0, age=19}
Employee{name='小凉', salary=7000.0, age=40}

映射
map——接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap——接收一个函数作为参数,将流中的每个值都转换成另一个流,然后把所有流连接成一个流。

public static Stream<Character> getCharacter(String str) {
    List<Character> list = new ArrayList<>();


    for (Character character : str.toCharArray()) {
        list.add(character);
    }
    return list.stream();
}

@Test
public void test3() {
    /**
     * map,flapMap
     */

    List<String> list = Arrays.asList("cvt", "aer", "ktv", "dbms");

    //1.将list中的每个元素都转换成大写
    list.stream()
            .map((e) -> e.toUpperCase())
            .forEach(System.out::println);

    System.out.println("------水平分割线---------");
    //2.取出employees中的每个员工姓名输出
    employees.stream()
            .map((e) -> e.getName())
            .forEach(System.out::println);
    System.out.println("------水平分割线---------");

    Stream<Character> sm = list.stream()
            .flatMap(StreamAPITest::getCharacter);

    sm.forEach(System.out::println);

}
排序

这个默认的是从小到大,可以自定义排序

//排序
    List<Integer> list = Arrays.asList(12, 32, 2, 45, 38, 29);

    list.stream()
            .sorted()
            .forEach(System.out::println);//默认排序,从小到大

    System.out.println("-------------------------");


    //定制排序 employees 先按照月薪排序,如果月薪相等按照年龄排序


    employees.stream()
            .sorted((e1, e2) -> {
                if (e1.getSalary() == e2.getSalary()) {
                    return e1.getAge().compareTo(e2.getAge()) ;
                } else {
                    return e1.getSalary().compareTo( e2.getSalary());
                }
            })
            .forEach(System.out::println);

运行结果:

12
29
32
38
45
-------------------------
Employee{name='小刚', salary=5000.0, age=19}
Employee{name='小凉', salary=7000.0, age=40}
Employee{name='小谷', salary=7000.0, age=20}
Employee{name='小红', salary=8000.0, age=23}
Employee{name='小明', salary=12000.0, age=32}
查找与匹配

allMatch ——检查是否匹配所有元素
anyMatch——检查是否至少匹配一个元素
noneMatch——检查是否没有匹配所有元素
findFirst——返回第一个元素
findAny——返回当前流中的任意元素
count——返回流中元素的总个数
max——返回流中最大值
min——返回流中最小值


private List<Employee> employees = Arrays.asList(
        new Employee("小明", 12000.0, 32, Employee.Status.VOCATION),
        new Employee("小红", 8000.0, 23, Employee.Status.FREE),
        new Employee("小刚", 5000.0, 19, Employee.Status.BUSY),
        new Employee("小凉", 7000.0, 40, Employee.Status.BUSY),
        new Employee("小谷", 7000.0, 20, Employee.Status.FREE)
);


//匹配、查找、最大值、最小值、
@Test
public void test5() {
    //allMatch,如果所有的元素都匹配返回true,否则返回false
    boolean b1 = employees.stream()
            .allMatch((e) -> {
                return e.getStatus() == Employee.Status.BUSY;
            });
    System.out.println("b1 = " + b1);

    //anyMatch 匹配中的任意元素满足条件返回true
    boolean b2 = employees.stream()
            .anyMatch((e) -> e.getStatus() == Employee.Status.VOCATION);
    System.out.println("b2 = "+b2);

    //noneMatch 如果所有元素都满足条件返回true,否则返回false
    boolean b3 = employees.stream()
            .noneMatch((e) -> e.getStatus() == Employee.Status.FREE);
        //并不是所有的员工状态都是free所以返回false
    System.out.println("b3 = "+b3);

    //findFirst 查找第一个元素
    Optional<Employee> employee1 = employees.stream()
            .sorted((e1,e2)->-e1.getSalary().compareTo(e2.getSalary()))//salary 从高到低,返回最高工资的员工对象
            .findFirst();
    System.out.println("firstSalaryEmployee : "+employee1);

    //findAny 返回当前流中任意一个元素
    Optional<Employee> any = employees.parallelStream()//parallelStream 并行流
            .findAny();
    System.out.println("any : "+any);

    //max
    Optional<Employee> max = employees.stream()
            .max((e1, e2) -> e1.getAge().compareTo(e2.getAge()));
    System.out.println("max age employee "+max);

    //min
    Optional<Employee> min = employees.stream()
            .min((e1, e2) -> e1.getAge().compareTo(e2.getAge()));
    System.out.println("min age employee "+min);

    //count
    long count = employees.stream()
            .count();
    System.out.println("count: "+count);
}


运行结果输出:

b1 = false
b2 = true
b3 = false
firstSalaryEmployee : Optional[Employee{name='小明', salary=12000.0, age=32}]
any : Optional[Employee{name='小刚', salary=5000.0, age=19}]
max age employee Optional[Employee{name='小凉', salary=7000.0, age=40}]
min age employee Optional[Employee{name='小刚', salary=5000.0, age=19}]
count: 5
归约

reduce(T identity,BinaryOperator)
reduce(BinaryOperator)
作用:可以将流中元素反复结合起来,得到一个值。

List<Integer> list = Arrays.asList(23,12,3,45,67,29,98);
Integer sum = list.stream()
        .reduce(0, (x, y) -> x + y);
System.out.println("sum = "+sum);

//先从employees中取出salary,然后reduce做处理,将员工工资求和
Optional<Double> optionalDouble = employees.stream()
        .map(Employee::getSalary)
        .reduce(Double::sum);

System.out.println(optionalDouble.get());

收集
collect——将流转成其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。

public void test7(){
    //收集员工名字返回集合

    //返回List
    List<String> names = employees.stream()
            .map(Employee::getName)
            .collect(Collectors.toList());
    names.forEach(System.out::println);
    //返回指定集合
    HashSet<String> strings = employees.stream()
            .map(Employee::getName)
            .collect(Collectors.toCollection(HashSet::new));
    System.out.println(strings);

}
结果:
小明
小红
小刚
小凉
小谷
[小刚, 小凉, 小谷, 小明, 小红]

使用collect从employees 中获取最大工资的人,最小工资,平均工资,员工工资总和,员工人数

@Test
public void test1() {
    //count
    Long count = employees.stream()
            .collect(Collectors.counting());
    System.out.println("count = " + count);

    //max employee
    Optional<Employee> maxSalary = employees.stream()
            .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
    System.out.println(maxSalary.get());

    //min
    Optional<Employee> minSal = employees.stream()
            .collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
    System.out.println(minSal.get());

    //avg salary
    Double avgSal = employees.stream()
            .collect(Collectors.averagingDouble(Employee::getSalary));
    System.out.println("avg salary = "+avgSal);

    //sum salary
    Double sumSal = employees.stream()
            .collect(Collectors.summingDouble(Employee::getSalary));
    System.out.println("sum salary = "+sumSal);
}
输出结果:

count = 5
Employee{name=‘小明’, salary=12000.0, age=32}
Employee{name=‘小刚’, salary=5000.0, age=19}
avg salary = 7800.0
sum salary = 39000.0

分组

@Test
public void test2(){

    String collect = employees.stream()
            .map(Employee::getName)
            .collect(Collectors.joining(",","---","---"));//将取出的name连接在一起,中间用,隔开,前缀是‘---’,后缀也是'---'.

    System.out.println(collect);

    Map<Employee.Status, List<Employee>> collect1 = employees.stream()
            .collect(Collectors.groupingBy(Employee::getStatus));
    System.out.println("按状态分组:"+collect1);
}

输出结果:
—小明,小红,小刚,小凉,小谷—
按状态分组:{BUSY=[Employee{name=‘小刚’, salary=5000.0, age=19}, Employee{name=‘小凉’, salary=7000.0, age=40}], VOCATION=[Employee{name=‘小明’, salary=12000.0, age=32}], FREE=[Employee{name=‘小红’, salary=8000.0, age=23}, Employee{name=‘小谷’, salary=7000.0, age=20}]}

原文地址:https://www.cnblogs.com/dataoblogs/p/14121971.html