JAVA8新特性之Stream API

1 前言
1.1 对Stream流的个人理解:

  1. 它和IO流是不一样的;
  2. 它是对数据源(集合,数组等)进行一系列的中间操作,产生一个新的流或者说我们想要的结果,并且对数据源不产生影响。
  3. 集合讲的是数据,流讲的是计算。
    个人理解

1.2Stream流操作的三个步骤

  1. 创建Stream
  2. 中间操作:对数据源数据进行处理
  3. 终端操作:执行中间操作,并产生结果

注意: 从终端操作可以看出stream流是延迟执行的,只有执行终端操作(想要需要的结果)的时候才执行中间操作

2 下面我们对Stream的三个步骤一一说明

2.1创建Stream

/**
* 创建流
*/
@Test
public void test01(){
    /**
    * 集合流
    *  - Collection.stream() 穿行流
    *  - Collection.parallelStream() 并行流
    */
    List<String> list = new ArrayList<>();
    Stream<String> stream1 = list.stream();

    //数组流
    //Arrays.stream(array)
    String[] strings = new String[10];
    Stream<String> stream2 = Arrays.stream(strings);

    //Stream 静态方法
    //Stream.of(...)
    Stream<Integer> stream3 = Stream.of(1, 2, 3);

    //无限流
    //迭代
    Stream<Integer> stream4 = Stream.iterate(0, (i) -> ++i+i++);
    stream4.forEach(System.out::println);

    //生成
    Stream.generate(() -> Math.random())
        .limit(5)
        .forEach(System.out::println);
}

2.2中间操作

创建一个list集合,这个集合只是下面例子中用,方便区别各API的用途,可不要误会

 List<Employee> emps = Arrays.asList(
            new Employee(101, "Z3", 19, 9999.99),
            new Employee(102, "L4", 20, 7777.77),
            new Employee(103, "W5", 35, 6666.66),
            new Employee(104, "Tom", 44, 1111.11),
            new Employee(105, "Jerry", 60, 4444.44)
            new Employee(105, "Jerry", 60, 4444.44)
    );
  • filter:接收 Lambda ,从流中排除某些元素
 @Test
    public void test2() {
        emps.stream()
                .filter((emp)->emp.getAge()>20)
                .forEach(System.out::println);
    }
    
    //输出
    Employee(id=103, name=W5, age=35, salary=6666.66)
    Employee(id=104, name=Tom, age=44, salary=1111.11)
    Employee(id=105, name=Jerry, age=60, salary=4444.44)
    Employee(id=105, name=Jerry, age=60, salary=4444.44)
  • limit:截断流,使其元素不超过给定数量
  @Test
    public void test2() {
        emps.stream()
                .filter((emp)->emp.getAge()>20)
                .limit(2)
                .forEach(System.out::println);
    }
     //输出
   Employee(id=103, name=W5, age=35, salary=6666.66)
   Employee(id=104, name=Tom, age=44, salary=1111.11)
  • skip(n):跳过元素,返回一个舍弃了前n个元素的流;若流中元素不足n个,则返回一个空流;与 limit(n) 互补
  @Test
    public void test2() {
        emps.stream()
                .filter((emp)->emp.getAge()>20)
                .limit(2)
                .skip(1)
                .forEach(System.out::println);

    }
    //输出
    Employee(id=104, name=Tom, age=44, salary=1111.11)
  • distinct:筛选,通过流所生成的 hashCode() 与 equals() 取除重复元素

     @Test
    public void test2() {
        emps.stream()
                .filter((emp)->emp.getAge()>20)
                .distinct()
                .forEach(System.out::println);

    }
//输出
Employee(id=103, name=W5, age=35, salary=6666.66)
Employee(id=104, name=Tom, age=44, salary=1111.11)
Employee(id=105, name=Jerry, age=60, salary=4444.44)
  • map:接收 Lambda ,将元素转换为其他形式或提取信息;接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
 @Test
    public void test2() {
        emps.stream()
               .map((emp)->emp.getAge())
                .forEach(System.out::println);
    }
    //输出   19 20 35 44 60 60

  • flatMap难点):接收一个函数作为参数,将流中每一个值都换成另一个流,然后把所有流重新连接成一个流,可以看做是两层for循环

    • 个人理解:与map()可以看做是一层for循环,flatMap()可以看做是两层for循环

    • 例如下面例子(将两个集合合并为一个集合)

flatMap()操作的一个作用就是将两个集合合并为一个集合,相当于join操作,若没有filter操作,会产生笛卡尔积现象。

//例子中boys和stus分别是boy对象集合和stu对象集合
 List<String> collect = boys.stream().flatMap(b -> stus.stream().
                        //第二层for循环中处理数据
                                filter(s -> b.getName().equals(s.getName())).
                        //将数据放入到一个新的集合中
                                map(Student::getName)
                //结束第二层循环
        ).collect(Collectors.toList());

       //等效于
        List<String> data=new ArrayList<>();
        //双层for循环处理数据
        for (Boy boy : boys) {
            for (Student student : stus) {
                //filter条件
                if(boy.getName().equals(student.getName())){
                    //map子句,将元素放入到新集合中
                    data.add(student.getName());
                }
            }
        }
//参考网址https://www.jianshu.com/p/279967ceb45f
  • sorted():自然排序
SortList.java

package com.concretepage;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class SortList {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<Student>();
        list.add(new Student(1, "Mahesh", 12));
        list.add(new Student(2, "Suresh", 15));
        list.add(new Student(3, "Nilesh", 10));

        System.out.println("---Natural Sorting by Name---");
        List<Student> slist = list.stream().sorted().collect(Collectors.toList());
        slist.forEach(e -> System.out.println("Id:"+ e.getId()+", Name: "+e.getName()+", Age:"+e.getAge()));

        System.out.println("---Natural Sorting by Name in reverse order---");
        slist = list.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
        slist.forEach(e -> System.out.println("Id:"+ e.getId()+", Name: "+e.getName()+", Age:"+e.getAge()));        

        System.out.println("---Sorting using Comparator by Age---");
        slist = list.stream().sorted(Comparator.comparing(Student::getAge)).collect(Collectors.toList());
        slist.forEach(e -> System.out.println("Id:"+ e.getId()+", Name: "+e.getName()+", Age:"+e.getAge()));

        System.out.println("---Sorting using Comparator by Age with reverse order---");
        slist = list.stream().sorted(Comparator.comparing(Student::getAge).reversed()).collect(Collectors.toList());
        slist.forEach(e -> System.out.println("Id:"+ e.getId()+", Name: "+e.getName()+", Age:"+e.getAge()));
    }
} 

Output *

—Natural Sorting by Name—
Id:1, Name: Mahesh, Age:12
Id:3, Name: Nilesh, Age:10
Id:2, Name: Suresh, Age:15
—Natural Sorting by Name in reverse order—
Id:2, Name: Suresh, Age:15
Id:3, Name: Nilesh, Age:10
Id:1, Name: Mahesh, Age:12
—Sorting using Comparator by Age—
Id:3, Name: Nilesh, Age:10
Id:1, Name: Mahesh, Age:12
Id:2, Name: Suresh, Age:15
—Sorting using Comparator by Age with reverse order—
Id:2, Name: Suresh, Age:15
Id:1, Name: Mahesh, Age:12
Id:3, Name: Nilesh, Age:10

  • sorted(Comparator c):定制排序
 @Test
    public void test2() {
        emps.stream()
              .sorted((e1,e2)->{
                  if (e1.getAge().equals(e2.getAge())){
                      return e1.getName().compareTo(e2.getName());
                  } else {
                      return e1.getAge().compareTo(e2.getAge());
                  }
              })
                .limit(2)
                .forEach(System.out::println);
    }
//输出
Employee(id=101, name=Z3, age=19, salary=9999.99)
Employee(id=102, name=L4, age=20, salary=7777.77)

2.3 终端操作(中间操作可以几个中间操作API连用,而终端操作不能几个终端操作API连用,只能用一个)

  • forEach(): 遍历输出
 @Test
    public void test2() {
        emps.stream()
               .map((emp)->emp.getAge())
                .forEach(System.out::println);
    }
    //输出   19 20 35 44 60 60
  • allMatch:检查是否匹配所有元素
 @Test
    public void test2() {
        boolean b = emps.stream()
                .allMatch(e -> e.getAge() == 19);
        System.out.println(b);//不可以使用forEach(System.out::println);,因为allMatch(e -> e.getAge() == 19);属于终端操作
        
        //输出flase
    }
  • allMatch:检查是否匹配所有元素
  • anyMatch:检查是否至少匹配一个元素
  • noneMatch:检查是否没有匹配所有元素
  • findFirst:返回第一个元素
  • findAny:返回当前流中的任意元素
  • count:返回流中元素的总个数
  • max:返回流中最大值
  • min:返回流中最小值
  • reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以将流中的数据反复结合起来,得到一个值
/**
* Java:
*  - reduce:需提供默认值(初始值)
*/
@Test
public void test01(){
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
    Integer integer = list.stream()
        .reduce(0, (x, y) -> x + y);
    System.out.println(integer);
}
  • collect:将流转换成其他形式(如利用Collectors转化为list,set,map等好多常用API)
 @Test
    public void test2() {
        //转list集合
        List<String> collect = emps.stream()
                .map(employee -> employee.getName())
                .collect(Collectors.toList());
        System.out.println(collect);
  //输出 [Z3, L4, W5, Tom, Jerry, Jerry]
    }
//转map集合
  @Test
    public void test2() {
      
        Map<Integer, List<Employee>> collect = emps.stream()
                .collect(Collectors.groupingBy(Employee::getId));
        System.out.println(collect);

    }
    //输出(从输出可以看出,应该先去重,再转换)
    {101=[Employee(id=101, name=Z3, age=19, salary=9999.99)],
     102=[Employee(id=102, name=L4, age=20, salary=7777.77)], 
     103=[Employee(id=103, name=W5, age=35, salary=6666.66)], 
     104=[Employee(id=104, name=Tom, age=44, salary=1111.11)], 
     105=[Employee(id=105, name=Jerry, age=60, salary=4444.44), Employee(id=105, name=Jerry, age=60, salary=4444.44)]}

//总结
       @Test
    public void test2() {
        //总结
        DoubleSummaryStatistics dss = emps.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println( dss);
        System.out.println(dss.getMax());
        System.out.println(dss.getMin());
        System.out.println(dss.getSum());
        System.out.println(dss.getCount());
        System.out.println(dss.getAverage());

    }
//输出
DoubleSummaryStatistics{count=6, sum=34444.410000, min=1111.110000, average=5740.735000, max=9999.990000}
9999.99
1111.11
34444.409999999996
6
5740.735
//其他API
@Test
public void test02(){
	//放入Set
    Set<String> set = emps.stream()
        .map(Employee::getName)
        .collect(Collectors.toSet());
    set.forEach(System.out::println);

    //放入LinkedHashSet
    LinkedHashSet<String> linkedHashSet = emps.stream()
        .map(Employee::getName)
        .collect(Collectors.toCollection(LinkedHashSet::new));
    linkedHashSet.forEach(System.out::println);
}

@Test
public void test03(){
    //总数
    Long count = emps.stream()
        .collect(Collectors.counting());
    System.out.println(count);

    //平均值
    Double avg = emps.stream()
        .collect(Collectors.averagingDouble(Employee::getSalary));
    System.out.println(avg);

    //总和
    Double sum = emps.stream()
        .collect(Collectors.summingDouble(Employee::getSalary));
    System.out.println(sum);

    //最大值
    Optional<Employee> max = emps.stream()
        .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
    System.out.println(max.get());

    //最小值
    Optional<Double> min = emps.stream()
        .map(Employee::getSalary)
        .collect(Collectors.minBy(Double::compare));
    System.out.println(min.get());
}

@Test
public void test04(){
    //分组
    Map<Integer, List<Employee>> map = emps.stream()
        .collect(Collectors.groupingBy(Employee::getId));
    System.out.println(map);

    //多级分组
    Map<Integer, Map<String, List<Employee>>> mapMap = emps.stream()
        .collect(Collectors.groupingBy(Employee::getId, Collectors.groupingBy((e) -> {
            if (e.getAge() > 35) {
                return "开除";
            } else {
                return "继续加班";
            }
        })));
    System.out.println(mapMap);
    
    //分区
    Map<Boolean, List<Employee>> listMap = emps.stream()
        .collect(Collectors.partitioningBy((e) -> e.getSalary() > 4321));
    System.out.println(listMap);
}

@Test
public void test05(){
    //总结
    DoubleSummaryStatistics dss = emps.stream()
        .collect(Collectors.summarizingDouble(Employee::getSalary));
    System.out.println(dss.getMax());
    System.out.println(dss.getMin());
    System.out.println(dss.getSum());
    System.out.println(dss.getCount());
    System.out.println(dss.getAverage());
    
    //连接
    String str = emps.stream()
        .map(Employee::getName)
        .collect(Collectors.joining("-")); //可传入分隔符
    System.out.println(str);
}
  • 完结
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值