Java8 新特性之集合操作Stream

Posted dw3306

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java8 新特性之集合操作Stream相关的知识,希望对你有一定的参考价值。

Java8 新特性之集合操作Stream

 

 

Stream简介

 

  • Java 8引入了全新的Stream API。这里的Stream和I/O流不同,它更像具有Iterable的集合类,但行为和集合类又有所不同。
  • stream是对集合对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作,或者大批量数据操作。

为什么要使用Stream

  • 函数式编程带来的好处尤为明显。这种代码更多地表达了业务逻辑的意图,而不是它的实现机制。易读的代码也易于维护、更可靠、更不容易出错。
  • 高端

 

使用实例:

测试数据:

public class Data 
    private static List<PersonModel> list = null;

    static 
        PersonModel wu = new PersonModel("wu qi", 18, "男");
        PersonModel zhang = new PersonModel("zhang san", 19, "男");
        PersonModel wang = new PersonModel("wang si", 20, "女");
        PersonModel zhao = new PersonModel("zhao wu", 20, "男");
        PersonModel chen = new PersonModel("chen liu", 21, "男");
        list = Arrays.asList(wu, zhang, wang, zhao, chen);
    

    public static List<PersonModel> getData() 
        return list;
    
 

 

Filter

  • 遍历数据并检查其中的元素时使用。
  • filter接受一个函数作为参数,该函数用Lambda表达式表示。
保留年龄为 20 的 person 元素
list = list.stream()
            .filter(person -> person.getAge() == 20)
            .collect(toList());

打印输出 [Personname=‘jack‘, age=20]

 

   /**
     * 过滤所有的男性
     */
    public static void fiterSex()
        List<PersonModel> data = Data.getData();

        //old
        List<PersonModel> temp=new ArrayList<>();
        for (PersonModel person:data) 
            if ("男".equals(person.getSex()))
                temp.add(person);
            
        
        System.out.println(temp);
        //new
        List<PersonModel> collect = data
                .stream()
                .filter(person -> "男".equals(person.getSex()))
                .collect(toList());
        System.out.println(collect);
    

    /**
     * 过滤所有的男性 并且小于20岁
     */
    public static void fiterSexAndAge()
        List<PersonModel> data = Data.getData();

        //old
        List<PersonModel> temp=new ArrayList<>();
        for (PersonModel person:data) 
            if ("男".equals(person.getSex())&&person.getAge()<20)
                temp.add(person);
            
        

        //new 1
        List<PersonModel> collect = data
                .stream()
                .filter(person -> 
                    if ("男".equals(person.getSex())&&person.getAge()<20)
                        return true;
                    
                    return false;
                )
                .collect(toList());
        //new 2
        List<PersonModel> collect1 = data
                .stream()
                .filter(person -> ("男".equals(person.getSex())&&person.getAge()<20))
                .collect(toList());

    

 distinct()

去除重复元素,这个方法是通过类的 equals 方法来判断两个元素是否相等的

如例子中的 Person 类,需要先定义好 equals 方法,不然类似[Personname=‘jack‘, age=20, Personname=‘jack‘, age=20] 这样的情况是不会处理的

 参考:https://blog.csdn.net/haiyoung/article/details/80934467

 

 

limit(long n)

 

返回前 n 个元素

list = list.stream()
            .limit(2)
            .collect(toList());

打印输出 [Personname=‘jack‘, age=20, Personname=‘mike‘, age=25]

 

 

Map

  • map生成的是个一对一映射,for的作用
  • 比较常用

 

   /**
     * 取出所有的用户名字
     */
    public static void getUserNameList()
        List<PersonModel> data = Data.getData();

        //old
        List<String> list=new ArrayList<>();
        for (PersonModel persion:data) 
            list.add(persion.getName());
        
        System.out.println(list);

        //new 1
        List<String> collect = data.stream().map(person -> person.getName()).collect(toList());
        System.out.println(collect);

        //new 2
        List<String> collect1 = data.stream().map(PersonModel::getName).collect(toList());
        System.out.println(collect1);

        //new 3
        List<String> collect2 = data.stream().map(person -> 
            System.out.println(person.getName());
            return person.getName();
        ).collect(toList());
    

 

 

FlatMap

  • 顾名思义,跟map差不多,更深层次的操作

  • 但还是有区别的

  • map和flat返回值不同

  • Map 每个输入元素,都按照规则转换成为另外一个元素。
    还有一些场景,是一对多映射关系的,这时需要 flatMap。

  • Map一对一

  • Flatmap一对多

  • map和flatMap的方法声明是不一样的

    • <r> Stream<r> map(Function mapper);
    • <r> Stream<r> flatMap(Function> mapper);
  • map和flatMap的区别:我个人认为,flatMap的可以处理更深层次的数据,入参为多个list,结果可以返回为一个list,而map是一对一的,入参是多个list,结果返回必须是多个list。通俗的说,如果入参都是对象,那么flatMap可以操作对象里面的对象,而map只能操作第一层。

 
public static void flatMapString() 
        List<PersonModel> data = Data.getData();
        //返回类型不一样
        List<String> collect = data.stream()
                .flatMap(person -> Arrays.stream(person.getName().split(" "))).collect(toList());

        List<Stream<String>> collect1 = data.stream()
                .map(person -> Arrays.stream(person.getName().split(" "))).collect(toList());

        //用map实现
        List<String> collect2 = data.stream()
                .map(person -> person.getName().split(" "))
                .flatMap(Arrays::stream).collect(toList());
        //另一种方式
        List<String> collect3 = data.stream()
                .map(person -> person.getName().split(" "))
                .flatMap(str -> Arrays.asList(str).stream()).collect(toList());
    

 

 

Collect

  • collect在流中生成列表,map,等常用的数据结构
  • toList()
  • toSet()
  • toMap()

 /**
     * toList
     */
    public static void toListTest()
        List<PersonModel> data = Data.getData();
        List<String> collect = data.stream()
                .map(PersonModel::getName)
                .collect(Collectors.toList());
    

    /**
     * toSet
     */
    public static void toSetTest()
        List<PersonModel> data = Data.getData();
        Set<String> collect = data.stream()
                .map(PersonModel::getName)
                .collect(Collectors.toSet());
    

    /**
     * toMap
     */
    public static void toMapTest()
        List<PersonModel> data = Data.getData();
        Map<String, Integer> collect = data.stream()
                .collect(
                        Collectors.toMap(PersonModel::getName, PersonModel::getAge)
                );

        data.stream()
                .collect(Collectors.toMap(per->per.getName(), value->
            return value+"1";
        ));
    

    /**
     * 指定类型
     */
    public static void toTreeSetTest()
        List<PersonModel> data = Data.getData();
        TreeSet<PersonModel> collect = data.stream()
                .collect(Collectors.toCollection(TreeSet::new));
        System.out.println(collect);
    

    /**
     * 分组
     */
    public static void toGroupTest()
        List<PersonModel> data = Data.getData();
        Map<Boolean, List<PersonModel>> collect = data.stream()
                .collect(Collectors.groupingBy(per -> "男".equals(per.getSex())));
        System.out.println(collect);
    

    /**
     * 分隔
     */
    public static void toJoiningTest()
        List<PersonModel> data = Data.getData();
        String collect = data.stream()
                .map(personModel -> personModel.getName())
                .collect(Collectors.joining(",", "", ""));
        System.out.println(collect);
    

 

groupingBy 分组

groupingBy 用于将数据分组,最终返回一个 Map 类型

Map<Integer, List<Person>> map = list.stream().collect(groupingBy(Person::getAge));

 

例子中我们按照年龄 age 分组,每一个 Person 对象中年龄相同的归为一组

另外可以看出,Person::getAge 决定 Map 的键(Integer 类型),list 类型决定 Map 的值(List

多级分组

groupingBy 可以接受一个第二参数实现多级分组:

 

Map<Integer, Map<T, List<Person>>> map = list.stream().collect(groupingBy(Person::getAge, groupBy(...)));

 

partitioningBy 分区

分区与分组的区别在于,分区是按照 true 和 false 来分的,因此partitioningBy 接受的参数的 lambda 也是 T -> boolean

根据年龄是否小于等于20来分区
Map<Boolean, List<Person>> map = list.stream()
                                     .collect(partitioningBy(p -> p.getAge() <= 20));

打印输出

    false=[Personname=‘mike‘, age=25, Personname=‘tom‘, age=30], 
    true=[Personname=‘jack‘, age=20]

 

 

参考博客:

https://www.jianshu.com/p/9fe8632d0bc2

https://cloud.tencent.com/developer/article/1187833

https://www.concretepage.com/java/jdk-8/java-8-distinct-example

 

以上是关于Java8 新特性之集合操作Stream的主要内容,如果未能解决你的问题,请参考以下文章

Java8新特性--Stream流操作

7. Java8新特性_创建 Stream

Java 8新特性之Stream流

java8新特性——Stream

java8 新特性入门 stream/lambda

Java8新特性第3章(Stream API)