將流的元素收集到集合中
集合 toList()
和 toSet()
通過使用 Stream.collect
操作,可以很容易地將 Stream
中的元素收集到容器中 :
System.out.println(Arrays
.asList("apple", "banana", "pear", "kiwi", "orange")
.stream()
.filter(s -> s.contains("a"))
.collect(Collectors.toList())
);
// prints: [apple, banana, pear, orange]
其他集合例項,例如 Set
,可以使用其他 Collectors
內建方法制作。例如, Collectors.toSet()
將 Stream
的元素收集到 Set
中 。
明確控制 List
或 Set
的實施
根據 Collectors#toList()
和 Collectors#toSet()
的文件,對於返回的 List
或 Set
的型別,可變性,可序列性或執行緒安全性沒有任何保證。
為了顯式控制要返回的實現,可以使用 Collectors#toCollection(Supplier)
,而給定的供應商返回一個新的空集合。
// syntax with method reference
System.out.println(strings
.stream()
.filter(s -> s != null && s.length() <= 3)
.collect(Collectors.toCollection(ArrayList::new))
);
// syntax with lambda
System.out.println(strings
.stream()
.filter(s -> s != null && s.length() <= 3)
.collect(Collectors.toCollection(() -> new LinkedHashSet<>()))
);
使用 toMap 收集元素
收集器將元素累積到 Map 中,其中 key 是 Student Id,Value 是 Student Value。
List<Student> students = new ArrayList<Student>();
students.add(new Student(1,"test1"));
students.add(new Student(2,"test2"));
students.add(new Student(3,"test3"));
Map<Integer, String> IdToName = students.stream()
.collect(Collectors.toMap(Student::getId, Student::getName));
System.out.println(IdToName);
輸出:
{1=test1, 2=test2, 3=test3}
Collectors.toMap 有另一個實現方式。如果在列表中新增 Map 中的新成員時重複鍵,mergeFunction 主要用於選擇新值或保留舊值。
mergeFunction 通常看起來像:(s1, s2) -> s1
保留對應於重複鍵的值,或者 (s1, s2) -> s2
為重複鍵設定新值。
將元素收集到集合的對映
示例:從 ArrayList 到 Map <String,List <>>
通常需要從主列表中製作列表地圖。示例:從列表中的學生,我們需要為每個學生製作一個主題列表的地圖。
List<Student> list = new ArrayList<>();
list.add(new Student("Davis", SUBJECT.MATH, 35.0));
list.add(new Student("Davis", SUBJECT.SCIENCE, 12.9));
list.add(new Student("Davis", SUBJECT.GEOGRAPHY, 37.0));
list.add(new Student("Sascha", SUBJECT.ENGLISH, 85.0));
list.add(new Student("Sascha", SUBJECT.MATH, 80.0));
list.add(new Student("Sascha", SUBJECT.SCIENCE, 12.0));
list.add(new Student("Sascha", SUBJECT.LITERATURE, 50.0));
list.add(new Student("Robert", SUBJECT.LITERATURE, 12.0));
Map<String, List<SUBJECT>> map = new HashMap<>();
list.stream().forEach(s -> {
map.computeIfAbsent(s.getName(), x -> new ArrayList<>()).add(s.getSubject());
});
System.out.println(map);
輸出:
{ Robert=[LITERATURE],
Sascha=[ENGLISH, MATH, SCIENCE, LITERATURE],
Davis=[MATH, SCIENCE, GEOGRAPHY] }
示例:從 ArrayList 到 Map <String,Map <>>
List<Student> list = new ArrayList<>();
list.add(new Student("Davis", SUBJECT.MATH, 1, 35.0));
list.add(new Student("Davis", SUBJECT.SCIENCE, 2, 12.9));
list.add(new Student("Davis", SUBJECT.MATH, 3, 37.0));
list.add(new Student("Davis", SUBJECT.SCIENCE, 4, 37.0));
list.add(new Student("Sascha", SUBJECT.ENGLISH, 5, 85.0));
list.add(new Student("Sascha", SUBJECT.MATH, 1, 80.0));
list.add(new Student("Sascha", SUBJECT.ENGLISH, 6, 12.0));
list.add(new Student("Sascha", SUBJECT.MATH, 3, 50.0));
list.add(new Student("Robert", SUBJECT.ENGLISH, 5, 12.0));
Map<String, Map<SUBJECT, List<Double>>> map = new HashMap<>();
list.stream().forEach(student -> {
map.computeIfAbsent(student.getName(), s -> new HashMap<>())
.computeIfAbsent(student.getSubject(), s -> new ArrayList<>())
.add(student.getMarks());
});
System.out.println(map);
輸出:
{ Robert={ENGLISH=[12.0]},
Sascha={MATH=[80.0, 50.0], ENGLISH=[85.0, 12.0]},
Davis={MATH=[35.0, 37.0], SCIENCE=[12.9, 37.0]} }
備忘單
目標 | 碼 |
---|---|
集合到 List |
Collectors.toList() |
集合預先分配的 ArrayList |
Collectors.toCollection(() -> new ArrayList<>(size)) |
集合到 Set |
Collectors.toSet() |
集合到具有更好迭代效能的 Set |
Collectors.toCollection(() -> new LinkedHashSet<>()) |
集合一個不區分大小寫的 Set<String> |
Collectors.toCollection(() -> new TreeSet<>(String.CASE_INSENSITIVE_ORDER)) |
集合到 EnumSet<AnEnum> (列舉的最佳表現) |
Collectors.toCollection(() -> EnumSet.noneOf(AnEnum.class)) |
使用獨特的鍵集合到 Map<K,V> |
Collectors.toMap(keyFunc,valFunc) |
將 MyObject.getter() 對映到唯一的 MyObject |
Collectors.toMap(MyObject::getter, Function.identity()) |
將 MyObject.getter() 對映到多個 MyObjects |
Collectors.groupingBy(MyObject::getter) |