Stream API

java8有两个重大的改变,一个是之前看到的Lambda表达式,另外一个就是Stream API(java.util.stream.*)。

Stream是java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似与使用sql执行数据库查询。

Stream API提供了一种高效且易于使用的处理数据的方式。

Stream(流)到底是什么?

是数据渠道,用于操作数据源(集合、数组)所生成的元素序列。   (集合讲的是数据,流讲的是计算

注意 : Stream自己不会存储元素

             Stream不会改变源对象。相反,会返回一个持有结果的新Stream

             Stream操作是延迟执行的。意味着他们会等到需要结果的时候才执行

Stream的操作的三个步骤

  • 创建Stream

      一个数据源(集合、数组),获取一个流

   

    //创建stream
    public void Test1(){
        List<String> list = new ArrayList<>();
        //1 可以通过Collection系列集合提供的Stream()串行流 或者parallelStream() 并行流
        Stream<String> stream = list.stream();
        //2 可以通过Arrays中静态方法stream()获取数组流
        Employee[] emps = new Employee[10];
        Stream<Employee> stream1 = Arrays.stream(emps);
        //3 通过Stream类中的静态方法 of()
        Stream<String> aa = Stream.of("aa");
        //4 创建无限流   迭代
        Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 2);
          //生成
        Stream.generate(() -> Math.random());
    }
  • 中间操作

      一个中间操作链,对数据源的数据进行处理

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

      筛选与切片

          

方法描述
filter(Predicate p)接受Lambda,从流中排除某些元素
distinct()筛选,通过流所生成元素的hashCode()和equals()去除重复元素
limit(long maxSize)截断流,使其元素不能超过给定数量
skip(long n)跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补

 

 

 

 

 

 

首先定义一个集合对象

 static List<Employee> lists = Arrays.asList(new Employee("张三",22,5000),
                                            new Employee("李四",32,8000),
                                            new Employee("王五",11,9999),
                                            new Employee("前六",50,2000),
                                            new Employee("李伟",19,10000),
                                            new Employee("丁一",27,15000),
                                            new Employee("秦王",37,4000));

测试 filter 方法

 //内部迭代,由Stream API完成
 public static void test1(){

        Stream<Employee> employeeStream = lists.stream()
                .filter((e) -> e.getAge() > 35); //中间操作
        //终止操作  惰性求值
        employeeStream.forEach(System.out::println);
    }

测试limit  如果limit和filter一起使用 limit必须在filtet的后面

    public static void test2(){
     lists.stream()
                .filter(e -> {
                    System.out.println("短路");
                    return e.getAge() > 10;
                })
                .limit(2)
                .forEach(System.out::println);

    }

 

 上述的limit有一种类似与短路操作 &&  ||   一旦发现满足条件的数据之后就不会执行剩余的迭代操作。如果没有发现满足条件的数据,便会进行多次迭代。

测试distinct: 在数据集合再多添加一条秦王对象

  public static void test3(){

        Stream<Employee> employeeStream = lists.stream()
                .filter(e -> {     //中间操作
                    return e.getAge() > 30;
                })
                .distinct();
        //终止操作
        employeeStream.forEach(System.out::println);
    }

 

测试skip : 

  public static void test4(){

        Stream<Employee> employeeStream = lists.stream()
                .filter(e -> {     //中间操作
                    return e.getAge() > 30;
                })
                .skip(2);
        //终止操作
        employeeStream.forEach(System.out::println);
    }

未添加skip(2) 打印的结果

添加了skip(2)结果

结果显而易见和limit相反,是去除前多少个

映射   

方法描述
map(Function f) 
mapToDouble(ToDoubleFunction f) 
maptoInt(ToIntFunction f) 
mapToLong(ToLongFunction f) 
flatMap(Function f) 

 

 

 

 

 

 

 

map---接收Lambda,讲元素转换成其他形式或提取元素。接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

 public static void test5(){
     List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
     list.stream()
                 .map((str) -> str.toUpperCase())
                .forEach(System.out::println);
     System.out.println("-------------------------------------");
     lists.stream()
             .map(Employee::getName)
             .forEach(System.out::println);
 }

flatMap---接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连接成一个流。

 public static void test5(){
     List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
     list.stream().flatMap(TestStreamAPI2::filterCharacter).forEach(System.out::println);
  
 }

 public static Stream<Character> filterCharacter(String str){
     List<Character> list = new ArrayList<>();
     for (Character c: str.toCharArray()
          ) {
         list.add(c);
     }
     return list.stream();
 }

上面代码实现这样一个需求: 将集合中的元素的字符分配单独打印出来,下面一个filterCharacter方法用来将字符串拆成单独的字符集合的流。

map是将一个个的流加入到当前的流中({{aaa},{bbb}}  类比与集合的 add方法),flatMap是将一个个流中的元素添加到当前的流中({a,a,a,b,b,b}  类比与集合的addAll方法)

方法描述
sorted()产生一个新流,其中按自然顺序排序
sorted(Comparator com)产生一个新流,其中按比较器顺序排序

 

 

 

 

sorted()---自然排序(Comparable)

sorted(Comparator com)----定制排序(Comparator)

 public static void testSorted(){
     List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
     list.stream()
             .sorted()
             .forEach(System.out::println);
     System.out.println("----------------定制排序-----------------------");
     lists.stream()
             .sorted((x,y) -> {
                 if(x.getAge() == y.getAge()){
                     return x.getName().compareTo(y.getName());
                 }else {
                     return Integer.compare(x.getAge(),y.getAge());
                 }
             }).forEach(System.out::println);
 }
  • 终止操作

     一个终止操作,执行中间操作链,并产生结果。

会从流的流水线生成结果,其结果可以不是任何值,例如 List、Integer 甚至是void

首先修改一下Employee2类


public class Employee2 {

    private int id;
    private String name;
    private int age;
    private double salary;
    private Status status;

    public Employee2() {
    }

    public Employee2(String name) {
        this.name = name;
    }

    public Employee2(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Employee2(int id, String name, int age, double salary) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public Employee2(int id, String name, int age, double salary, Status status) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.status = status;
    }

    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

    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 String show() {
        return "测试方法引用!";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + id;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        long temp;
        temp = Double.doubleToLongBits(salary);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee2 other = (Employee2) obj;
        if (age != other.age)
            return false;
        if (id != other.id)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Employee2 [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + ", status=" + status
                + "]";
    }

    public enum Status {
        FREE, BUSY, VOCATION;
    }

}

查找与匹配

方法描述
allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate p)检查是否至少匹配一个元素
noneMatch(Predicate p) 检查是否没有匹配所有元素
findFirst() 返回第一个元素
 findAny() 返回当前流中的任意元素

 

 

 

 

 

 

 方法 描述
 count() 返回流中元素总数
 max(Comparator c) 返回流中最大值
 min(Comparator c) 返回流中最小值
forEach(Consumer c) 内部迭代(使用Collection接口需要用户去做迭代称为外部迭代,Stream API 使用内部迭代)

 

 

 

 

 

 

allMatch——检查是否匹配所有元素

public class TestShutDown {
   static List<Employee2> emps = Arrays.asList(
            new Employee2(102, "李四", 59, 6666.66, Employee2.Status.BUSY),
            new Employee2(101, "张三", 18, 9999.99, Employee2.Status.FREE),
            new Employee2(103, "王五", 28, 3333.33, Employee2.Status.VOCATION),
            new Employee2(104, "赵六", 8, 7777.77, Employee2.Status.BUSY),
            new Employee2(104, "赵六", 8, 7777.77, Employee2.Status.FREE),
            new Employee2(104, "赵六", 8, 7777.77, Employee2.Status.FREE),
            new Employee2(105, "田七", 38, 5555.55, Employee2.Status.BUSY)
    );

    public static void test1(){
        boolean match = emps.stream()
                .allMatch((e) -> e.getStatus().equals(Employee2.Status.BUSY));
        System.out.println(match);
    }

    public static void main(String[] args) {
        test1();
    }
}

anyMatch——检查是否至少匹配一个元素

  boolean anyMatch = emps.stream()
                .anyMatch((e) -> e.getStatus().equals(Employee2.Status.BUSY));
        System.out.println(anyMatch);

noneMatch——检查是否没有匹配的元素

 boolean noneMatch = emps.stream()
                .noneMatch((e) -> e.getStatus().equals(Employee2.Status.BUSY));
        System.out.println(noneMatch);

findFirst——返回第一个元素

Optional<Employee2> first = emps.stream()
                .findFirst();
        System.out.println(first);

findAny——返回当前流中的任意元素

Optional<Employee2> any = emps.stream()
                .findAny();
        System.out.println(any);

count——返回流中元素的总个数

long count = emps.stream()
                .count();
        System.out.println(count);

max——返回流中最大值

Optional<Double> max = emps.stream()
                .map(Employee2::getSalary)
                .max(Double::compare);
        System.out.println(String.valueOf(max));

min——返回流中最小值

 Optional<Employee2> min = emps.stream()
                .min((x,y) -> Double.compare(x.getSalary(),y.getSalary()));
        System.out.println(min);

总的测试代码:

public class TestShutDown {
   static List<Employee2> emps = Arrays.asList(
            new Employee2(102, "李四", 59, 6666.66, Employee2.Status.BUSY),
            new Employee2(101, "张三", 18, 9999.99, Employee2.Status.FREE),
            new Employee2(103, "王五", 28, 3333.33, Employee2.Status.VOCATION),
            new Employee2(104, "赵六", 8, 7777.77, Employee2.Status.BUSY),
            new Employee2(104, "赵六", 8, 7777.77, Employee2.Status.FREE),
            new Employee2(104, "赵六", 8, 7777.77, Employee2.Status.FREE),
            new Employee2(105, "田七", 38, 5555.55, Employee2.Status.BUSY)
    );

    public static void test1(){
        boolean match = emps.stream()
                .allMatch((e) -> e.getStatus().equals(Employee2.Status.BUSY));
        System.out.println(match);
        System.out.println("--------------------------------------");
        boolean anyMatch = emps.stream()
                .anyMatch((e) -> e.getStatus().equals(Employee2.Status.BUSY));
        System.out.println(anyMatch);
        System.out.println("--------------------------------------");
        boolean noneMatch = emps.stream()
                .noneMatch((e) -> e.getStatus().equals(Employee2.Status.BUSY));
        System.out.println(noneMatch);
        System.out.println("--------------------------------------");
        Optional<Employee2> first = emps.stream()
                .findFirst();
        System.out.println(first);
        System.out.println("--------------------------------------");
        Optional<Employee2> any = emps.stream()
                .findAny();
        System.out.println(any);
        System.out.println("--------------------------------------");
        long count = emps.stream()
                .count();
        System.out.println(count);
        System.out.println("--------------------------------------");
        Optional<Double> max = emps.stream()
                .map(Employee2::getSalary)
                .max(Double::compare);
        System.out.println(String.valueOf(max));
        System.out.println("--------------------------------------");
        Optional<Employee2> min = emps.stream()
                .min((x,y) -> Double.compare(x.getSalary(),y.getSalary()));
        System.out.println(min);
    }

    public static void main(String[] args) {
        test1();
    }
}

归约

reduce(T iden, BinaryOperator b)  可以将流中元素反复结合起来,得到一个值。返回T
reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回Optional<T>

 

 

 

备注: map和reduce的连接通常称为map-reduce模式,因google用它来进行网络搜索而出名

  public static void test2(){
      List<Integer>list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
      Integer sum = list.stream()
              .reduce(0, (x, y) -> x + y);
      System.out.println(sum);

      Optional<Double> reduce = emps.stream()
              .map(Employee2::getSalary)
              .reduce(Double::sum);
      System.out.println(reduce.get());
  }

收集

方法 描述
collect(Collector c) 将流转化成其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法

 

 

 

Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但是Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

方法 返回类型 作用
toListList<T> 把流元素收集到List
List<Employee> emps = list.stream().collect(Collectors.toList());
toSetset<T>把流元素收集到set
Set<Employee> emps = list.stream().collect(Collectors.toSet());
toCollectionCollection<T>把流元素收集到创建的集合
Collection<Employee> emps = list.stream().collect(Collectors.toCollection(ArrayList::new));
countingLong 计算流中元素个数
long count = list.stream().collect(Collectors.counting());
summingIntInteger 对流中元素的整数属性求和
int total= list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingIntDouble 计算流中元素Integer属性的平均值
double avg= list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingIntIntSummaryStatistics  收集流中Integer属性的统计值。如平均值
IntSummaryStatistics iss = list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
joiningString 连接流中每个字符串
String str = list.stream().map(Employee::getName).collect(Collectors.joining());
maxByOptional<T> 根据比较器选择最大值
Optional<Employee> max= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
minByOptional<T>根据比较器选择最小值
Optional<Employee> min= list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
reducing 归约产生的类型 从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值
int total = list.stream().collect(Collectors.reducing(0, Employee::getSalary, Integer::sum));
 collectingAndThen 转换函数返回的类型 包裹另外一个收集器,对其结果转换函数
int how = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
groupingByMap<K, List<T>> 根据某属性值对流分组,属性为K,结果为V
Map<Employee.Status, List<Employee>> map = list.stream().collect(Collectors.groupingBy(Collectors.toList(), List::size));
partitioningByMap<Boolean, List<T>> 根据true或false进行分区
Map<Boolean, List<Employee>> vd= list.stream().collect(Collectors.partitioningBy(Employee::getManage));

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Collectors.toList()

List<String> collect = emps.stream()
                 .map(Employee2::getName)
                 .collect(Collectors.toList());
         collect.forEach(System.out::println);

Collectors.toSet()

 Set<String> collect1 = emps.stream()
                 .map(Employee2::getName)
                 .collect(Collectors.toSet());
         collect1.forEach(System.out::println);

Collectors.toCollection(HashSet::new)

HashSet<String> collect2 = emps.stream()
                 .map(Employee2::getName)
                 .collect(Collectors.toCollection(HashSet::new));
         collect2.forEach(System.out::println);

Collectors.maxBy()

 Optional<Double> collect3 = emps.stream()
                 .map(Employee2::getSalary)
                 .collect(Collectors.maxBy(Double::compare));
         System.out.println(collect3.get());

Optional<Employee2> collect4 = emps.stream()
                 .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
         System.out.println(collect4.get());

Collectors.minBy()

 Optional<Double> collect4 = emps.stream()
                 .map(Employee2::getSalary)
                 .collect(Collectors.minBy(Double::compare));
         System.out.println(collect4);


         Optional<Employee2> collect3 = emps.stream()
                 .collect(Collectors.minBy((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary())));
         System.out.println(collect3.get());

Collectors.summingDouble()

Double collect5 = emps.stream()
                 .collect(Collectors.summingDouble(Employee2::getSalary));
         System.out.println(collect5);

Collectors.averagingDouble()

Double collect6 = emps.stream()
    .collect(Collectors.averagingDouble((e)->e.getSalary()));
    
    Double collect7 = emps.stream()
    .collect(Collectors.averagingDouble(Employee2::getSalary));
    
    System.out.println("collect6:"+collect6);
    System.out.println("collect7:"+collect7);

Collectors.counting()

//总数
    Long collect8 = emps.stream()
                       .collect(Collectors.counting());
    System.out.println(collect8);

Collectors.summarizingDouble()

DoubleSummaryStatistics collect9 = emps.stream()
        .collect(Collectors.summarizingDouble(Employee2::getSalary));
    long count = collect9.getCount();
    double average = collect9.getAverage();
    double max = collect9.getMax();
    double min = collect9.getMin();
    double sum = collect9.getSum();
    System.out.println("count:"+count);
    System.out.println("average:"+average);
    System.out.println("max:"+max);
    System.out.println("min:"+min);
    System.out.println("sum:"+sum);

分组Collectors.groupingBy()

Map<Employee2.Status, List<Employee2>> collect = emps.stream()
                 .collect(Collectors.groupingBy((e)->e.getStatus()));
         System.out.println(collect);


         Map<Employee2.Status, List<Employee2>> collect2 = emps.stream()
                 .collect(Collectors.groupingBy(Employee2::getStatus));
         System.out.println(collect2);

多级分组Collectors.groupingBy()

Map<Employee2.Status, Map<String, List<Employee2>>> collect = emps.stream()
                 .collect(Collectors.groupingBy(Employee2::getStatus, Collectors.groupingBy((e)->{
                     if(e.getAge() >= 60)
                         return "老年";
                     else if(e.getAge() >= 35)
                         return "中年";
                     else
                         return "成年";
                 })));
         System.out.println(collect);

分区Collectors.partitioningBy()

Map<Employee2.Status, Map<String, List<Employee2>>> collect = emps.stream()
                 .collect(Collectors.groupingBy(Employee2::getStatus, Collectors.groupingBy((e)->{
                     if(e.getAge() >= 60)
                         return "老年";
                     else if(e.getAge() >= 35)
                         return "中年";
                     else
                         return "成年";
                 })));
         System.out.println(collect);

组接字符串Collectors.joining()

//组接字符串
    @Test
    public void testCollect6() {
        String collect = emps.stream()
        .map((e)->e.getName())
        .collect(Collectors.joining());
        System.out.println(collect);
        
        String collect3 = emps.stream()
        .map(Employee2::getName)
        .collect(Collectors.joining(","));
        System.out.println(collect3);
        
        
        String collect2 = emps.stream()
            .map(Employee2::getName)
            .collect(Collectors.joining(",", "prefix", "subfix"));
        System.out.println(collect2);
        
        
    }
    @Test
    public void testCollect7() {
        Optional<Double> collect = emps.stream()
        .map(Employee2::getSalary)
        .collect(Collectors.reducing(Double::sum));
        System.out.println(collect.get());
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值