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);