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

輸出

 

 

 

 

隨時補充

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM