Java8 集合Stream流常见用法(一)

416 阅读3分钟

Java8 集合Stream流常见用法(一)

​ Stream是Java8新增的非常强力的集合处理类。其中包含了许多常见的集合处理操作,例如过滤,分组,统计等等。使用它的最大好处就是避免大段的for语句,可以使代码更加的高效整洁。

​ 虽说这是Java8就已经发布的特性,但是在实际项目中使用率却不高,原因我猜测主要是因为stream流中间操作的可读性以及对lambda表达式的生疏使得不了解的人对其望而却步。但是只要理解了lambda表达式的由来及用法,熟悉了stream常规操作,集合处理就会变的高效而优雅。

  • lambda表达式(匿名函数)

    当我们用以接口为参数的方法时,需要对接口的方法实现。例如集合的排序:

      Collections.sort(persons, new Comparator<Person>() {
                @Override
                public int compare(Person o1, Person o2) {
                    return o1.getAge() > o2.getAge();
                }
            });
    

    改用lambda表达式:

      Collections.sort(persons,(o1,o2) -> {
                    return o1.getAge() > o2.getAge();
                }
            });
    

    代码精简了许多,但不是所有的接口都可以,进入Comparator方法:

    @FunctionalInterface
    public interface Comparator<T> {
    
        int compare(T o1, T o2);
    

    重点就是 @FunctionalInterface

    被这个注解修饰的类表明这是一个函数式接口。即这个接口只有这一个方法需要实现,这样才能用lambda表达式,常用的还有Runable接口。Stream中很多方法的参数都是函数式接口。

  • 常见用法

     List<Person> persons = Arrays.asList(new Person("yjj",21),new Person("xm",22)); //实体类 属性为姓名,年龄
    
    • 过滤

      过滤集合中年龄大于21的实体

      persons = persons.stream().filter(person -> {return person.getAge()>21;}).collect(Collectors.toList());
      

      filter()方法的参数就是一个函数式接口,它的方法是bool返回类型,显而易见就是让我们声明过滤的条件,为true就过滤。

      filter()方法执行后返回的仍然是Stream,这是一个中间操作,最后需要执行终止操作collect()返回一个集合。

      中间操作的意思就是在终止操作之前,你仍然可以进行其他中间操作对上一个操作的结果再加工,就如同一个流水线。

    • 查询

      获取集合中姓名为'xm'的实体

      Person person = persons.stream().filter(e-> e.getName().equals("xm")).findAny().orElse(null);
      
    • 匹配

      匹配集合中实体的name属性并提取成一个列表。

      List<String> names = persons.stream().map(Person::getName).collect(Collectors.toList());
      

      冒号(::)运算符在Java 8中被用作方法引用(method reference),方法引用是与lambda表达式相关的一个重要特性。它提供了一种不执行方法的方法。为此,方法引用需要由兼容的函数接口组成的目标类型上下文。就是类名::方法名

    • 分组

      1.将集合转换成key为name属性,value为实体的Map。

      不使用Stream

      Map<String,Person> personMap = new HashMap<>();
              for (Person person : persons) {
                  personMap.put(person.getName(),person);
              }
      

      使用Stream

      Map<String,Person> personMap = persons.stream().collect(Collectors.toMap(Person::getName,e->e));
      

      2.将集合以年龄分组。并以年龄为key,该年龄下的list为value组成map。

      Map<String,List<Person>> personMap = persons.stream().collect(Collectors.groupingBy(Person::getName));
      
    • 计算

      1.获取年龄最大的实体

      Person person = persons.stream().max(Comparator.comparingInt(Person::getAge)).get();
      

      2.计算平均年龄

      double average = persons.stream().mapToInt(Person::getAge).average().orElse(0.0);
      

      3.年龄求和

      long totalAge = persons.stream().mapToInt(Person::getAge).summaryStatistics().getSum();
      
  • 不同类型的流

    除了常规对象流之外,Java还提供了基本类型的流,IntStream,LongStream,DoubleStream

    IntStreams.range()可以代替常见的for循环

     IntStream.range(1,4).forEach(System.out::println);