• Java8 List<对象> 转 Set、Map(高级)、排序、分组、统计


     

    实体类

    import lombok.Getter;
    import lombok.Setter;
    
    @Getter
    @Setter
    public class Student {
    
        private int id;
        private String name;
        private String score;
        private int classNo;
    
        public Student(int id, String name, String score, int classNo) {
            this.id = id;
            this.name = name;
            this.score = score;
            this.classNo = classNo;
        }
    }

    Main

    import com.demo.entity.Student;
    
    import java.util.*;
    import java.util.stream.Collectors;
    
    
    public class Main {
    
        private static List<String> simpleList = new ArrayList<>();
        private static List<Student> normalList = new ArrayList<>();
        static {
            simpleList.add("apple");
            simpleList.add("apple");
            simpleList.add("banana");
            simpleList.add("orange");
    
            normalList.add(new Student(1, "Emma", "A", 701));
            normalList.add(new Student(2, "Larissa", "S", 701));
            normalList.add(new Student(3, "Sophia", "B", 701));
            normalList.add(new Student(4, "Ashley", "B", 702));
            normalList.add(new Student(5, "May", "C", 702));
            normalList.add(new Student(6, "Hailey", "D", 702));
            normalList.add(new Student(7, "Kelly", "S", 703));
            normalList.add(new Student(8, "Amy", "A", 703));
            normalList.add(new Student(9, "Wesley", "C", 703));
        }
        public static void main(String[] args){
            // TODO
        }
    
    }

    List<String> 转 Set<String>

    System.out.println("----------------简单List---------------");
    simpleList.forEach(System.out::println);
    System.out.println("----------------简单List转Set---------------");
    Set<String> simpleSet = new HashSet<>(simpleList);
    simpleSet.forEach(System.out::println);

    输出:

    ----------------简单List---------------
    apple
    apple
    banana
    orange
    ----------------简单List转Set---------------
    banana
    orange
    apple

    List<Student> 转 Set<Integer>

    System.out.println("----------------普通List---------------");
    normalList.forEach(System.out::println);
    System.out.println("----------------普通List转Set---------------");
    Set<Integer> normalSet = normalList.stream().map(Student::getClassNo).collect(Collectors.toSet());
    normalSet.forEach(System.out::println);

    输出:

    ----------------普通List---------------
    Student{id=1, name='Emma', score='A', classNo=701}
    Student{id=2, name='Larissa', score='S', classNo=701}
    Student{id=3, name='Sophia', score='B', classNo=701}
    Student{id=4, name='Ashley', score='B', classNo=702}
    Student{id=5, name='May', score='C', classNo=702}
    Student{id=6, name='Hailey', score='D', classNo=702}
    Student{id=7, name='Kelly', score='S', classNo=703}
    Student{id=8, name='Amy', score='A', classNo=703}
    Student{id=9, name='Wesley', score='C', classNo=703}
    ----------------普通List转Set---------------
    701
    702
    703

    List<Student> 转 List<String>

    System.out.println("----------------普通List转List---------------");
    List<String> list = normalList.stream().map(Student::getName).collect(Collectors.toList());
    list.forEach(System.out::println);

    输出:

    ----------------普通List转List---------------
    Emma
    Larissa
    Sophia
    Ashley
    May
    Hailey
    Kelly
    Amy
    Wesley

    List<Student> 转 Map<Integer,Student>

    System.out.println("----------------普通List转Map---------------");
    Map<Integer,Student> normalMap = normalList.stream().collect(Collectors.toMap(Student::getId,(b)->b));
    normalMap.forEach((id, student) -> {
        System.out.println(id + "::" + student);
    });

    输出:

    ----------------普通List转Map---------------
    1::Student{id=1, name='Emma', score='A', classNo=701}
    2::Student{id=2, name='Larissa', score='S', classNo=701}
    3::Student{id=3, name='Sophia', score='B', classNo=701}
    4::Student{id=4, name='Ashley', score='B', classNo=702}
    5::Student{id=5, name='May', score='C', classNo=702}
    6::Student{id=6, name='Hailey', score='D', classNo=702}
    7::Student{id=7, name='Kelly', score='S', classNo=703}
    8::Student{id=8, name='Amy', score='A', classNo=703}
    9::Student{id=9, name='Wesley', score='C', classNo=703}

    复杂一点的转换:(List转Map处理重复key)

    List<Student> students = new ArrayList<>(normalList);
    System.out.println("----------------原数据---------------");
    students.forEach(System.out::println);
    System.out.println("----------------List<Student>转Map<String, Student>重复key只保留前者---------------");
    // 重复key处理 (s1, s2) -> s1)
    Map<Integer, Student> classStudentMap = students.stream().collect(Collectors.toMap(Student::getClassNo, s -> s, (s1, s2) -> s1));
    classStudentMap.forEach((classNo, student) -> System.out.println(classNo + "::" + student));
    
    System.out.println("----------------List<Student>转Map<String, List<Student>>---------------");
    // 重复key处理成一个集合
    Map<Integer, List<Student>> listMap = students.stream().collect(Collectors.toMap(Student::getClassNo, s -> {
        List<Student> l = new ArrayList<>();
        l.add(s);
        return l;
    }, (List<Student> s1, List<Student> s2) -> {
        s1.addAll(s2);
        return s1;
    }));
    listMap.forEach((learn, student) -> System.out.println(learn + "::" + student));

    输出:

    ----------------原数据---------------
    Student{id=1, name='Emma', score='A', classNo=701}
    Student{id=2, name='Larissa', score='S', classNo=701}
    Student{id=3, name='Sophia', score='B', classNo=701}
    Student{id=4, name='Ashley', score='B', classNo=702}
    Student{id=5, name='May', score='C', classNo=702}
    Student{id=6, name='Hailey', score='D', classNo=702}
    Student{id=7, name='Kelly', score='S', classNo=703}
    Student{id=8, name='Amy', score='A', classNo=703}
    Student{id=9, name='Wesley', score='C', classNo=703}
    ----------------List<Student>转Map<String, Student>重复key只保留前者---------------
    701::Student{id=1, name='Emma', score='A', classNo=701}
    702::Student{id=4, name='Ashley', score='B', classNo=702}
    703::Student{id=7, name='Kelly', score='S', classNo=703}
    ----------------List<Student>转Map<String, List<Student>>---------------
    701::[Student{id=1, name='Emma', score='A', classNo=701}, Student{id=2, name='Larissa', score='S', classNo=701}, Student{id=3, name='Sophia', score='B', classNo=701}]
    702::[Student{id=4, name='Ashley', score='B', classNo=702}, Student{id=5, name='May', score='C', classNo=702}, Student{id=6, name='Hailey', score='D', classNo=702}]
    703::[Student{id=7, name='Kelly', score='S', classNo=703}, Student{id=8, name='Amy', score='A', classNo=703}, Student{id=9, name='Wesley', score='C', classNo=703}]

    Map<String, List<Student>>转List<Student> 和 Map<String, List<Student>>转List<List<Student>>

    List<Student> students = new ArrayList<>(normalList);
    // 先分组,准备好数据
    Map<String, List<Student>> grouping = students.stream().collect(Collectors.groupingBy(Student::getScore));
    System.out.println("----------------Map<String, List<Student>>转List<Student>---------------");
    // 把map的values全部拆出来
    List<Student> collect = grouping.entrySet().stream()
            .flatMap(map -> map.getValue().stream())
            .collect(Collectors.toList());
    collect.forEach(System.out::println);
    
    System.out.println("----------------Map<String, List<Student>>转List<List<Student>>---------------");
    // 只要map的value,但是不改变格式
    grouping.values().forEach(System.out::println);

    输出:

    ----------------Map<String, List<Student>>转List<Student>---------------
    Student{id=1, name='Emma', score='A', classNo=701}
    Student{id=8, name='Amy', score='A', classNo=703}
    Student{id=3, name='Sophia', score='B', classNo=701}
    Student{id=4, name='Ashley', score='B', classNo=702}
    Student{id=5, name='May', score='C', classNo=702}
    Student{id=9, name='Wesley', score='C', classNo=703}
    Student{id=2, name='Larissa', score='S', classNo=701}
    Student{id=7, name='Kelly', score='S', classNo=703}
    Student{id=6, name='Hailey', score='D', classNo=702}
    ----------------Map<String, List<Student>>转List<List<Student>>---------------
    [Student{id=1, name='Emma', score='A', classNo=701}, Student{id=8, name='Amy', score='A', classNo=703}]
    [Student{id=3, name='Sophia', score='B', classNo=701}, Student{id=4, name='Ashley', score='B', classNo=702}]
    [Student{id=5, name='May', score='C', classNo=702}, Student{id=9, name='Wesley', score='C', classNo=703}]
    [Student{id=2, name='Larissa', score='S', classNo=701}, Student{id=7, name='Kelly', score='S', classNo=703}]
    [Student{id=6, name='Hailey', score='D', classNo=702}]

    分组

    List<Student> students = new ArrayList<>(normalList);
    System.out.println("----------------分组---------------");
    // 根据key分组
    Map<String, List<Student>> grouping = students.stream().collect(Collectors.groupingBy(Student::getScore));
    grouping.forEach((score, student) -> System.out.println(score + "::" + student));
    System.out.println("----------------按照多个属性分组---------------");
    // 根据多个key的组合分组
    grouping = students.stream().collect(Collectors.groupingBy( e -> e.getClassNo() + "_" + e.getScore()));
    grouping.forEach((learn, student) -> System.out.println(learn + "::" + student));

    输出:

    ----------------分组---------------
    A::[Student{id=1, name='Emma', score='A', classNo=701}, Student{id=8, name='Amy', score='A', classNo=703}]
    B::[Student{id=3, name='Sophia', score='B', classNo=701}, Student{id=4, name='Ashley', score='B', classNo=702}]
    C::[Student{id=5, name='May', score='C', classNo=702}, Student{id=9, name='Wesley', score='C', classNo=703}]
    S::[Student{id=2, name='Larissa', score='S', classNo=701}, Student{id=7, name='Kelly', score='S', classNo=703}]
    D::[Student{id=6, name='Hailey', score='D', classNo=702}]
    ----------------按照多个属性分组---------------
    702_C::[Student{id=5, name='May', score='C', classNo=702}]
    703_A::[Student{id=8, name='Amy', score='A', classNo=703}]
    702_B::[Student{id=4, name='Ashley', score='B', classNo=702}]
    701_S::[Student{id=2, name='Larissa', score='S', classNo=701}]
    703_C::[Student{id=9, name='Wesley', score='C', classNo=703}]
    703_S::[Student{id=7, name='Kelly', score='S', classNo=703}]
    702_D::[Student{id=6, name='Hailey', score='D', classNo=702}]
    701_B::[Student{id=3, name='Sophia', score='B', classNo=701}]
    701_A::[Student{id=1, name='Emma', score='A', classNo=701}]

    排序

    List<Student>根据名字排序

    System.out.println("----------------List排序---------------");
    // 虽然这里是浅拷贝,但是只影响修改而不影响排序
    List<Student> students = new ArrayList<>(normalList);
    Collections.sort(students, Comparator.comparing(Student::getName));
    // 比上面更简洁
    // students.sort(Comparator.comparing(Student::getName));
    students.forEach(System.out::println);

    输出:

    ----------------List排序---------------
    Student{id=8, name='Amy', score='A', classNo=703}
    Student{id=4, name='Ashley', score='B', classNo=702}
    Student{id=1, name='Emma', score='A', classNo=701}
    Student{id=6, name='Hailey', score='D', classNo=702}
    Student{id=7, name='Kelly', score='S', classNo=703}
    Student{id=2, name='Larissa', score='S', classNo=701}
    Student{id=5, name='May', score='C', classNo=702}
    Student{id=3, name='Sophia', score='B', classNo=701}
    Student{id=9, name='Wesley', score='C', classNo=703}

    List<String>排序

    System.out.println("----------------简单List排序---------------");
    List<String> list = new ArrayList<>(simpleList);
    System.out.println("----------------正序---------------");
    list.sort((a,b) -> a.compareTo(b));
    // 更简洁的方式
    // list.sort(Comparator.naturalOrder());
    list.forEach(System.out::println);
    System.out.println("----------------倒序---------------");
    list.sort(Comparator.reverseOrder());
    list.forEach(System.out::println);

    输出:

    ----------------简单List排序---------------
    ----------------正序---------------
    apple
    apple
    banana
    orange
    ----------------倒序---------------
    orange
    banana
    apple
    apple

    Map排序

    List<Student> students = new ArrayList<>(normalList);
    // 先按照成绩分组,准备好数据
    Map<String, List<Student>> grouping = students.stream().collect(Collectors.groupingBy(Student::getScore));
    System.out.println("----------------Map<String, List<Student>>排序---------------");
    Map<String, List<Student>> result = new LinkedHashMap<>();
    // Map的key有特殊处理
    grouping.entrySet().stream()
            .sorted((o1,o2) -> {
                Integer k1 = getWeight(o1.getKey());
                Integer k2 = getWeight(o2.getKey());
                return k1.compareTo(k2);
            })
            .forEachOrdered(x -> result.put(x.getKey(), x.getValue()));
    result.forEach((learn, student) -> System.out.println(learn + "::" + student));
    System.out.println("----------------");
    Map<String, List<Student>> result2 = new LinkedHashMap<>();
    // 仅仅按照key排序
    grouping.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .forEachOrdered(x -> result2.put(x.getKey(), x.getValue()));
    result2.forEach((learn, student) -> System.out.println(learn + "::" + student));
    System.out.println("----------------");
    Map<String, List<Student>> result3 = new LinkedHashMap<>();
    // 等价第一个,只是省去了getKey方法
    grouping.entrySet().stream()
            .sorted(Map.Entry.comparingByKey((o1,o2) -> {
                Integer k1 = getWeight(o1);
                Integer k2 = getWeight(o2);
                return k1.compareTo(k2);
            }))
            .forEachOrdered(x -> result3.put(x.getKey(), x.getValue()));
    result3.forEach((learn, student) -> System.out.println(learn + "::" + student));

    权重方法:

    /**
     * 不同成绩有不同的排序权重
     * @param score
     * @return
     */
    public static Integer getWeight(String score){
        switch (score){
            case "S": return 1;
            case "A": return 2;
            case "B": return 3;
            case "C": return 2;
            case "D": return 2;
            default:return 0;
        }
    }

    输出:

    ----------------Map<String, List<Student>>排序---------------
    S::[Student{id=2, name='Larissa', score='S', classNo=701}, Student{id=7, name='Kelly', score='S', classNo=703}]
    A::[Student{id=1, name='Emma', score='A', classNo=701}, Student{id=8, name='Amy', score='A', classNo=703}]
    C::[Student{id=5, name='May', score='C', classNo=702}, Student{id=9, name='Wesley', score='C', classNo=703}]
    D::[Student{id=6, name='Hailey', score='D', classNo=702}]
    B::[Student{id=3, name='Sophia', score='B', classNo=701}, Student{id=4, name='Ashley', score='B', classNo=702}]
    ----------------
    A::[Student{id=1, name='Emma', score='A', classNo=701}, Student{id=8, name='Amy', score='A', classNo=703}]
    B::[Student{id=3, name='Sophia', score='B', classNo=701}, Student{id=4, name='Ashley', score='B', classNo=702}]
    C::[Student{id=5, name='May', score='C', classNo=702}, Student{id=9, name='Wesley', score='C', classNo=703}]
    D::[Student{id=6, name='Hailey', score='D', classNo=702}]
    S::[Student{id=2, name='Larissa', score='S', classNo=701}, Student{id=7, name='Kelly', score='S', classNo=703}]
    ----------------
    S::[Student{id=2, name='Larissa', score='S', classNo=701}, Student{id=7, name='Kelly', score='S', classNo=703}]
    A::[Student{id=1, name='Emma', score='A', classNo=701}, Student{id=8, name='Amy', score='A', classNo=703}]
    C::[Student{id=5, name='May', score='C', classNo=702}, Student{id=9, name='Wesley', score='C', classNo=703}]
    D::[Student{id=6, name='Hailey', score='D', classNo=702}]
    B::[Student{id=3, name='Sophia', score='B', classNo=701}, Student{id=4, name='Ashley', score='B', classNo=702}]

    如果你要倒序的话

    System.out.println("----------------倒序----------------");
    Map<String, List<Student>> result4 = new LinkedHashMap<>();
    // 仅仅按照key排序
    grouping.entrySet().stream()
            .sorted(Map.Entry.<String, List<Student>>comparingByKey().reversed())
            .forEachOrdered(x -> result4.put(x.getKey(), x.getValue()));
    result4.forEach((learn, student) -> System.out.println(learn + "::" + student));
    System.out.println("----------------");
    Map<String, List<Student>> result5 = new LinkedHashMap<>();
    // 等价第一个,只是省去了getKey方法
    grouping.entrySet().stream()
            .sorted(Map.Entry.<String, List<Student>>comparingByKey((o1,o2) -> {
                Integer k1 = getWeight(o1);
                Integer k2 = getWeight(o2);
                return k1.compareTo(k2);
            }).reversed())
            .forEachOrdered(x -> result5.put(x.getKey(), x.getValue()));
    result5.forEach((learn, student) -> System.out.println(learn + "::" + student));

    输出:

    ----------------倒序----------------
    S::[Student{id=2, name='Larissa', score='S', classNo=701}, Student{id=7, name='Kelly', score='S', classNo=703}]
    D::[Student{id=6, name='Hailey', score='D', classNo=702}]
    C::[Student{id=5, name='May', score='C', classNo=702}, Student{id=9, name='Wesley', score='C', classNo=703}]
    B::[Student{id=3, name='Sophia', score='B', classNo=701}, Student{id=4, name='Ashley', score='B', classNo=702}]
    A::[Student{id=1, name='Emma', score='A', classNo=701}, Student{id=8, name='Amy', score='A', classNo=703}]
    ----------------
    B::[Student{id=3, name='Sophia', score='B', classNo=701}, Student{id=4, name='Ashley', score='B', classNo=702}]
    A::[Student{id=1, name='Emma', score='A', classNo=701}, Student{id=8, name='Amy', score='A', classNo=703}]
    C::[Student{id=5, name='May', score='C', classNo=702}, Student{id=9, name='Wesley', score='C', classNo=703}]
    D::[Student{id=6, name='Hailey', score='D', classNo=702}]
    S::[Student{id=2, name='Larissa', score='S', classNo=701}, Student{id=7, name='Kelly', score='S', classNo=703}]

    统计

    String s = "15, 11, 01, 03, 07, 12, 15, 12, 15, 02, 07, 14, 01, 03, 04, 05, 09, 04, 06, 12, 04, 07, 13, 10, 04, 14, 13, 11, 10, 16, 16, 04, 15, 03, 16, 08, 10, 05, 08, 11, 16, 04, 13, 07, 14, 06, 14, 10, 15, 02, 09, 16, 08, 11, 10, 01, 16, 12, 06, 01, 12, 01, 16, 12, 10, 04";
    List<Integer> list = new ArrayList<>();
    for(String i : s.split(", ")){
        list.add(Integer.valueOf(i));
    }
    // 平均值
    System.out.println(list.stream().mapToDouble(value -> value).average());
    // 总值
    System.out.println(list.stream().mapToDouble(value -> value).sum());
    // 数据数量
    System.out.println(list.stream().mapToDouble(value -> value).count());
    // 最大
    System.out.println(list.stream().mapToDouble(value -> value).max());
    // 最小
    System.out.println(list.stream().mapToDouble(value -> value).min());
    // 去重后计算总值
    System.out.println(list.stream().mapToDouble(value -> value).distinct().sum());

     也有其他数据类型的方法

    结果:

    OptionalDouble[9.121212121212121]
    602.0
    66
    OptionalDouble[16.0]
    OptionalDouble[1.0]
    136.0

    =========================================分割线=================================================

    Lambda表达式

    格式:(params) -> {expression}

    比如我们实现一个Runnable接口

    Runnable run = new Runnable() {
        @Override
        public void run() {
            // TODO
        }
    };

    使用Lambda表达式

    Runnable run = () -> {
        // TODO
    };

    而可以使用Lambda的接口也是有限制的,即只能有一个方法。

    函数式接口

    规范:

    1. 接口中只能有一个抽象方法

    2. (可选)在接口上添加 @FunctionalInterface 注解,这样可以检测它是否是一个函数式接口。

    比如:

    @FunctionalInterface
    public interface Fun{
        void fun();
    }
    
    // 也可以使用泛型
    @FunctionalInterface
    public interface Fun<T>{
        void fun(T t);
    }

    使用的时候

    Fun fun = () -> {};

    为什么Lambda引用外部变量需要final修饰?

    1. 每个方法执行的时候都会在栈上创建一个栈帧,局部变量存放在栈帧中的局部变量表中,栈上的内容是线程私有的。

    2. Lambda表达式是个匿名函数,准确来说是个匿名内部类接口的实现方法。而执行此代码的线程会在执行的时候单独创建一个栈帧,局部变量依然是私有的。

    3. 由此可见,表达式里的current变量只是外部current变量的一个副本。而为了保证程序的正确性则强制要求这个被引用的局部变量被定义成final。

    也就是说,人家也可以不加入这个检查,允许你改变外部局部变量的值,但是,程序运行的结果并不会如你所愿,所以,人家索性就打消你这个念头。

    其它Java8新特性

    1. computeIfAbsent

    Map<String, String> map = new HashMap<>();
    String key = "A";
    String v = map.get(key);
    if (v == null){
        System.out.println("处理key不存在的情况");
    }

    Java8可以这样处理

    Map<String, String> map = new HashMap<>();
    String key = "A";
    String computeIfAbsent = map.computeIfAbsent(key, s -> {
        return "如果key不存在,则返回这个";
    });
    System.out.println(computeIfAbsent);

    2. filter

    过滤出特定数据,并取出特定字段

    import lombok.Getter;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.stream.Collectors;
    
    public class Main {
        public static void main(String[] args) throws Exception {
            List<People> list = new ArrayList<>();
            list.add(new People(1, "男"));
            list.add(new People(2, "女"));
            list.add(new People(3, "女"));
    
            List<Integer> collect = list.stream().filter(i -> "女".equals(i.getSex())).map(People::getId).collect(Collectors.toList());
            System.out.println(collect);
        }
    
    }
    
    @Getter
    class People{
        private int id;
        private String sex;
    
        public People(int id, String sex) {
            this.id = id;
            this.sex = sex;
        }
    }

    输出

    随时补充

  • 相关阅读:
    Linux基础(一)
    计算机基础之网络基础
    计算机基础之操作系统
    计算机基础之计算机硬件基础
    .NET Reflector 8.2支持VS2013高亮显示和代码地图视图
    jQuery图表开源软件
    8个实用的页面布局和用户界面jQuery插件
    关于mvc3.0RadioButtonFor的使用
    链式调用-python
    给实数用千分位方法输出结果
  • 原文地址:https://www.cnblogs.com/LUA123/p/9367657.html
Copyright © 2020-2023  润新知