实现Collector
接口
为什么要实现Collector
接口
有三种方法创建Collector
接口
-
Collectors
工厂类 -
调用
collect()
-
自己实现
Collector
接口
理解Collector
接口的参数类型
查看接口参数
interface Collector<T, A, R> {
// content of the interface
}
首先检查T
和R
类型
-
T
stream流中元素类型 -
R
通过Collector
处理后结果类型
toList()
中R
为List<T>
,toSet()
中R
为Set<T>
。
groupingBy()
中R
为Map
。
A
的类型处理非常复杂,如果你使用IDE可能不会显式的提示
example
Collection<String> strings =
List.of("two", "three", "four", "five", "six", "seven", "eight", "nine",
"ten", "eleven", "twelve");
Collector<String, ?, List<String>> listCollector = Collectors.toList();
List<String> list = strings.stream().collect(listCollector);
Collector<String, ?, Set<String>> setCollector = Collectors.toSet();
Set<String> set = strings.stream().collect(setCollector);
Collector<String, ?, Map<Integer, Long>> groupingBy =
Collectors.groupingBy(String::length, Collectors.counting());
Map<Integer, Long> map = strings.stream().collect(groupingBy);
如果自己实现Collector
接口,就必须要显式的给出A
的类型。A
是中间可变的容器类型。例如toList()
是ArrayList
,toSet()
是HashSet
。
理解Collector
的特征
Collector.Characteristics
有3个特征
-
IDENTITY_FINISH
有该特征的不会调用finisher -
UNORDERED
不保证处理stream流中元素的顺序性,toSet()
有该特征,toList()
没有该特征 -
CONCURRENT
该特征对并行流特别重要。表示存储stream流中元素的容器(accumulator)支持并发访问。
实现类似toList()
和toSet()
的Collector
example1
class ToList<T> implements Collector<T, List<T>, List<T>> {
public Supplier<List<T>> supplier() {
return ArrayList::new;
}
public BiConsumer<List<T>, T> accumulator() {
return Collection::add;
}
public BinaryOperator<List<T>> combiner() {
return (list1, list2) -> {list1.addAll(list2); return list1; };
}
public Function<List<T>, List<T>> finisher() {
return Function.identity();
}
public Set<Characteristics> characteristics() {
return Set.of(Characteristics.IDENTITY_FINISH);
}
}
use case
Collection<String> strings =
List.of("one", "two", "three", "four", "five") ;
List<String> result = strings.stream().collect(new ToList<>());
System.out.println("result = " + result);
result
result = [one, two, three, four, five]
example2
class ToSet<T> implements Collector<T, List<T>, List<T>> {
public Supplier<List<T>> supplier() {
return HashSet::new;
}
public BiConsumer<List<T>, T> accumulator() {
return Collection::add;
}
public BinaryOperator<List<T>> combiner() {
return (list1, list2) -> {list1.addAll(list2); return list1; };
}
public Function<List<T>, List<T>> finisher() {
return Function.identity();
}
public Set<Characteristics> characteristics() {
return Set.of(Characteristics.UNORDERED);
}
}
实现类似joining()
的Collector
example
class Joining implements Collector<String, StringBuffer, String> {
public Supplier<StringBuffer> supplier() {
return StringBuffer::new;
}
public BiConsumer<StringBuffer, String> accumulator() {
return StringBuffer::append;
}
public BinaryOperator<StringBuffer> combiner() {
return StringBuffer::append;
}
public Function<StringBuffer, String> finisher() {
return Object::toString;
}
public Set<Characteristics> characteristics() {
return Set.of();
}
}
use case
Collection<String> strings =
List.of("one", "two", "three", "four", "five") ;
String result = strings.stream().collect(new Joining());
System.out.println("result = " + result);
result
result = onetwothreefourfive