jdk8函数式编程

Lambda表达式

Lambda表达式允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理。这一特性在许多语言都有支持,如pyhton, js等。Jdk1.8开始,Java也支持Lambda表达式。

最简单的Lambda表达式可由逗号分隔的参数列表、->符号和语句块组成,例如:

1
Arrays.asList("a", "b", "d").forEach(e -> System.out.println(e));

上面的参数e类型由编译器推导得出,也可显式指定:

1
Arrays.asList("a", "b", "d").forEach((String e) -> System.out.println(e));

对于复杂语句块,可以使用花括号扩起来:

1
2
3
4
Arrays.asList("a", "b", "d").forEach(e -> {
System.out.println(e);
System.out.println(e.contains("a"));
});

Lambda可以引用类成员和局部变量,会将这些变量隐式得转换成final,如以下代码则会报错:

1
2
3
4
String t = "a";
Arrays.asList("a", "b", "d").forEach(e ->
System.out.println(e + t)); // Variable used in lambda expression should be final or effectively final
t = "b";

去掉 t=”b”; 则可正常运行。

Lambda表达式有返回值,返回值的类型也由编译器推理得出。如果Lambda表达式中的语句块只有一行,则可以不用使用return语句,下列两个代码片段效果相同:

1
2
3
4
5
Arrays.asList("a", "b", "d").sort((e1, e2) -> e1.compareTo(e2));

Arrays.asList("a", "b", "d").sort((e1, e2) -> {
return e1.compareTo(e2);
});

函数式接口

在Java中,Lambda表达式则是一种折中的实现方式。Java的Lambda表达式依赖与函数接口,函数接口指的是只有一个抽象方法的接口,
这样的接口可以隐式转换为Lambda表达式。

还是从最简单的Lambda表达式开始:

1
Arrays.asList("a", "b", "d").forEach(e -> System.out.println(e));

跳转至 Iterable 接口看看是怎么实现的:

1
2
3
4
5
6
7
8
9
10
public interface Iterable<T> {
...
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
...
}

这里forEach方法接收了一个Consumer的参数,Consumer 则是一个函数接口:

1
2
3
4
5
6
7
8
9
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);

default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}

@FunctionalInterface 注解显式的声明了 Consumer 是个函数式接口,它仅有一个抽象方法accept();
需要注意的是,默认方法和静态方法不会破坏函数式接口的定义,因此上面的代码是合法的;
这使得其可以被转换为Lamda表达式,正如上面的示例。

JDK 1.8新增的函数接口在java.util.function包下:

  • Consumer< T> 代表了接受一个输入参数并且无返回的操作。 函数: void accept(T t);
1
2
3
4
5
6
7
8
9
10
11
12
public interface Iterable<T> {
...
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
...
}

Arrays.asList("a", "b", "d").forEach(e -> System.out.println(e));
  • Function< T, R> 接受一个输入参数,返回一个结果。 函数: R apply(T t);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
...
/**
*
* 如果给定的key不存在(或者key对应的value为null),就去计算mappingFunction的值;(存在则返回已存入的值)
*
* 如果mappingFunction的值不为null,就把key=value放进去;
* 如果mappingFunction的值为null,就不会记录该映射关系,返回值为null;
* 如果计算mappingFunction的值的过程出现异常,再次抛出异常,不记录映射关系,返回null;
*/
@Override
public V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
if (mappingFunction == null)
throw new NullPointerException();
...
V v = mappingFunction.apply(key);
...
return v;
}
...
}

HashMap<String, String> hashMap = new HashMap<>();
hashMap.computeIfAbsent("key", k -> k.toUpperCase()); // putIfAbsent("key", "KEY")
  • Predicate< T> 接受一个输入参数,返回一个布尔值结果。 函数: boolean test(T t);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
static class Person {
public enum Sex {
MALE, FEMALE
}

String name;
LocalDate birthday;
Sex gender;
String emailAddress;
int age;

...
}

public static void printPersonsWithPredicate(List<Person> roster, Predicate<Person> tester) {
for (Person p : roster) {
if (tester.test(p)) {
p.printPerson();
}
}
}

printPersonsWithPredicate(roster,
p -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25);
  • Supplier< T> 无参数,返回一个结果。 函数: T get();
1
2
3
4
5
6
7
8
9
10

public final class Optional< T> {
...
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
...
}

System.out.println(Optional.ofNullable(null).orElseGet(() -> "B"));
  • UnaryOperator< T> extends Function< T, T> 接受一个参数为类型T,返回值类型也为T。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class AtomicReference<V> implements java.io.Serializable {
...
public final V updateAndGet(UnaryOperator<V> updateFunction) {
V prev, next;
do {
prev = get();
next = updateFunction.apply(prev);
} while (!compareAndSet(prev, next));
return next;
}
...
}

static Person fake(String name){
Person person = new Person();
person.name = name;
...
return person;
}

AtomicReference<Person> person = new AtomicReference<>(roster.get(0));
person.updateAndGet(p -> fake(p.name));
  • BiConsumer< T, U> 代表了一个接受两个输入参数的操作,并且不返回任何结果。 函数: void accept(T t, U u);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable {
...
public void forEach(BiConsumer<? super K, ? super V> action) {
if (action == null) throw new NullPointerException();
Node<K,V>[] t;
if ((t = table) != null) {
Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
for (Node<K,V> p; (p = it.advance()) != null; ) {
action.accept(p.key, p.val);
}
}
}
...
}

concurrentHashMap.forEach((k, v) -> System.out.println(k + " " + v));
  • BiFunction< T, U, R> 代表了一个接受两个输入参数的方法,并且返回一个结果。 函数: R apply(T t, U u);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
...
public V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
if (remappingFunction == null)
throw new NullPointerException();
Node<K,V> e; V oldValue;
int hash = hash(key);
if ((e = getNode(hash, key)) != null &&
(oldValue = e.value) != null) {
V v = remappingFunction.apply(key, oldValue);
if (v != null) {
e.value = v;
afterNodeAccess(e);
return v;
}
else
removeNode(hash, key, null, false, true);
}
return null;
}
...
}


HashMap<String, String> hashMap = new HashMap<>();
hashMap.computeIfAbsent("key", k -> k.toUpperCase()); // putIfAbsent("key", "KEY")
hashMap.computeIfPresent("key", (k, v) -> k + v); // put("key", "keyKey")
  • BinaryOperator< T> extends BiFunction< T,T,T> 代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class AtomicReference<V> implements java.io.Serializable {
...
public final V accumulateAndGet(V x,
BinaryOperator<V> accumulatorFunction) {
V prev, next;
do {
prev = get();
next = accumulatorFunction.apply(prev, x);
} while (!compareAndSet(prev, next));
return next;
}
...
}

AtomicReference<Integer> integerAtomicReference = new AtomicReference<>(Integer.valueOf(1));
integerAtomicReference.accumulateAndGet(5, (oldValue, newValue) -> oldValue + newValue);
  • BiPredicate< T, U> 代表了一个两个参数的boolean值方法。 函数: boolean test(T t, U u);
1
2
BiPredicate<Integer, Integer> largeThan = (x, y) -> x > y;
System.out.println(largeThan.test(2, 3));

基础接口为以上,其他接口都是带类型的,如IntConsumer,其接收参数为int;ObjDoubleConsumer,接收一个obj和一个double。

除开 java.util.function 包下的接口,其它常见函数接口如下:

  • java.lang.Runnable

  • java.util.concurrent.Callable

  • java.util.Comparator

方法引用

方法引用通过方法的名字来指向一个方法。使用符号 :: 。 这可以使得代码更为紧凑。

如:

1
Arrays.asList("a", "b", "d").forEach(System.out::println);

再如:
有一个 Car 类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static class Car {
public static Car create(Supplier<Car> supplier) {
return supplier.get();
}

public static void collide(Car car) {
System.out.println("Collided " + car.toString());
}

public void follow(Car another) {
System.out.println("Following the " + another.toString());
}

public void repair() {
System.out.println("Repaired " + this.toString());
}
}
  • 构造器引用:它的语法是Class::new,或者更一般的Class< T >::new
1
Car car = Car.create(Car::new);
  • 静态方法引用 Class::static_method
1
2
List<Car> cars = Arrays.asList(car);
cars.forEach(Car::collide);
  • 特定类的任意方法引用 Class::method
1
cars.forEach(Car::repair);
  • 特定对象的方法引用 instance::method
1
2
Car lead = Car.create(Car::new);
cars.forEach(lead::follow);

Stream

Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的。它更像一个高级版本的 Iterator,不可以重复遍历里面的数据,像水一样,流过了就一去不复返。它和普通的 Iterator 不同的是,它可以并行遍历,普通的 Iterator 只能是串行,在一个线程中执行。

当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架来拆分任务和加速处理过程。

Stream 的另外一大特点是,数据源本身可以是无限的。

流的构成

流的元素类型: Stream< T>, IntStream, LongStream, DoubleStream。

流计算由以下三部分构成: 流来源,0或多个中间操作,终止操作。

流的来源(stream source)
  • Colloection.stream() or parallelStream() 使用一个集合的元素创建一个流。
    1
    2
    List list = Arrays.asList("a", "b", "d");
    Stream stream = list.stream();
  • Arrays.stream(T[] array) 使用数组创建流。
    1
    2
    String[] array = {"a", "b", "d"};
    Stream stream = Arrays.stream(array);
  • Stream.of(T t) 使用单个元素创建一个流。
    1
    Stream stream = Stream.of(Integer.valueOf("123"));
  • Stream.of(T… values) 使用多个元素创建一个流。
    1
    Stream stream = Stream.of(Integer.valueOf("123"), Double.valueOf("233.0"));
  • Stream.empty() 创建一个空流。
  • Stream.iterate(final T seed, final UnaryOperator< T> f) 创建一个包含序列 first, f(first), f(f(first)), … 的无限流
    1
    Stream stream = Stream.iterate(1, e -> e * 2); // 2^N
  • Stream.generate(Supplier s) 使用一个生成器函数创建一个无限流。
    1
    Stream stream = Stream.generate(Math::random);
  • IntStream.range(int startInclusive, int endExclusive) 创建一个由下限到上限之间的元素组成的 IntStream。
    1
    IntStream intStream = IntStream.range(1,10); // 1-9
  • Random.ints() 创建由随机数构成的无限流。
    1
    IntStream intStream = new Random().ints();
  • 其他: BufferedReader.lines(); BitSet.stream(); Stream.chars(); Files.list(Path dir);
    Pattern.splitAsStream(CharSequence input); JarFile.stream(); etc..
中间操作(intermediate operation)

中间操作负责将一个流转换为另一个流。一个流可以后面跟随零个或多个中间操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是 lazy 的,就是说,仅仅调用到这类方法,并没有真正开始流的遍历。

在对于一个 Stream 进行多次中间操作,每次都对 Stream 的每个元素进行转换,而且是执行多次,这样时间复杂度就是 N(转换次数)个 for 循环里把所有操作都做掉的总和吗?其实不是这样的,转换操作都是 lazy 的,多个中间操作只会在终止操作的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream 里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在终结操作的时候循环 Stream 对应的集合,然后对每个元素执行所有的函数。

中间操作包括 filter()(选择与条件匹配的元素)、map()(根据函数来转换元素)、distinct()(删除重复)、limit()(在特定大小处截断流)和 sorted()。

中间操作可进一步划分为无状态和有状态操作。
无状态操作(比如 filter() 或 map())可独立处理每个元素,而有状态操作(比如 sorted() 或 distinct())可合并以前看到的影响其他元素处理的元素状态。

  • filter(Predicate< T>) 与预期匹配的流的元素

    1
    2
    Person.createRoster().stream().filter(person -> person.getGender() == Person.Sex.MALE
    && person.getAge() >= 18).collect(Collectors.toList()); // 查找18岁以上的男性
  • map(Function< T, U>) 将提供的函数应用于流的元素的结果

    1
    Person.createRoster().stream().map(person -> person.getAge()).collect(Collectors.toSet()); // 获取所有人的年龄集合
  • flatMap(Function< T, Stream< U>> 将提供的流处理函数应用于流元素后获得的流元素

    1
    2
    3
    4
    5
    6
    String[] words = new String[]{"abc","abc","abc"};
    Arrays.stream(words)
    .map(word -> word.split(""))
    .flatMap(Arrays::stream) // 将三个String[]流元素使用Arrays.stream(T..)处理获得String流
    .distinct()
    .forEach(System.out::print);
  • distinct() 去除重复元素,实际使用了ConcurrentHashMap< T, Boolean>进行操作,所以是根据hashcode进行去重的。(参见DistinctOps类)

    1
    2
    3
    4
    5
    6
    String[] words = new String[]{"abc","abc","abc"};
    Arrays.stream(words)
    .map(word -> word.split(""))
    .flatMap(Arrays::stream) // 将三个String[]流元素使用Arrays.stream(T..)处理获得String流
    .distinct() //去重
    .forEach(System.out::print); //输出abc
  • sorted() OR sorted(Comparator<? super T>) 对流元素进行排序。

    1
    2
    3
    4
    5
    6
    7
    String[] words = new String[]{"cbad","def"};
    Arrays.stream(words)
    .map(word -> word.split(""))
    .flatMap(Arrays::stream)
    .distinct()
    .sorted()
    .forEach(System.out::print); // abcdef
  • limit(long) 截断至所提供长度的流元素

    1
    new Random().ints().limit(10).forEach(System.out::println); //输出10个随机数
  • skip(long) 丢弃了前 N 个元素的流元素

    1
    Stream.iterate(1, e -> e * 2).limit(10).skip(5).forEach(System.out::println); // 2^0 - 2^9 然后丢弃前5,即2^5 - 2^9
  • peek() 主要为debug使用,给出流操作结果。

    1
    2
    3
    4
    5
    6
    Stream.of("one", "two", "three", "four")
    .filter(e -> e.length() > 3)
    .peek(e -> System.out.println("Filtered value: " + e))
    .map(String::toUpperCase)
    .peek(e -> System.out.println("Mapped value: " + e))
    .collect(Collectors.toList());
终结操作(terminal operation)

一个流只能有一个终结操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。终结操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个side effect。

  • forEach(Consumer<? extends T> action) / forEachOrdered(Consumer<? super T> action) 将提供的操作应用于流的每个元素。

    1
    new Random().ints().limit(10).forEach(System.out::println); //输出10个随机数
  • toArray() 使用流的元素创建一个数组。

    1
    new Random().ints().limit(10).toArray();
  • reduce(…) 将流的元素聚合为一个汇总值。

    • Optional< T> reduce(BinaryOperator< T> accumulator); 未定义初始值,从而第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素。
    • T reduce( T identity, BinaryOperator< T> accumulator); 定义了初始值,从而第一次执行的时候第一个参数的值是初始值,第二个参数是Stream的第一个元素。
    • < U> U reduce(U identity,BiFunction< U, ? super T, U> accumulator,BinaryOperator< U> combiner); combiner的作用在于合并每个线程的result得到最终结果。
1
2
3
4
5
System.out.println("10个随机数之和:"
+ new Random().ints()
.limit(10)
.reduce((acc, item) -> acc + item)
.getAsInt());
  • collect(…) 将流的元素聚合到一个汇总结果容器中。

    • < R> R collect(Supplier< R> supplier,BiConsumer< R, ? super T> accumulator,BiConsumer< R, R> combiner);

    • < R, A> R collect(Collector<? super T, A, R> collector);

1
2
3
4
List<String> stringList = Stream.of("one", "two", "three", "four")
.filter(e -> e.length() > 3)
.map(String::toUpperCase)
.collect(ArrayList::new, List::add, (left, right) -> left.addAll(right)); //同collect(Collectors.toList())
  • min(Comparator<? super T>) 通过比较符返回流的最小元素。

    1
    2
    3
    4
    5
    6
    String[] words = new String[]{"cbad","def"};
    System.out.println(Arrays.stream(words)
    .map(word -> word.split(""))
    .flatMap(Arrays::stream)
    .distinct()
    .min((e1, e2) -> e2.compareTo(e1)).get()); // 这里逆序,返回f
  • max(Comparator<? super T>) 通过比较符返回流的最大元素。

    1
    2
    3
    4
    5
    6
    String[] words = new String[]{"cbad","def"};
    System.out.println(Arrays.stream(words)
    .map(word -> word.split(""))
    .flatMap(Arrays::stream)
    .distinct()
    .max((e1, e2) -> e2.compareTo(e1)).get()); // 这里逆序,返回a
  • count() 返回流的大小。

    1
    2
    3
    4
    5
    6
    String[] words = new String[]{"cbad","def"};
    System.out.println(Arrays.stream(words)
    .map(word -> word.split(""))
    .flatMap(Arrays::stream)
    .distinct()
    .count()); // 输出6
  • anyMatch(Predicate<? super T>) / allMatch(Predicate<? super T>) / noneMatch(Predicate<? super T>) 返回流的任何/所有元素是否与提供的预期相匹配。

    1
    2
    String[] words = new String[]{"cbad","def"};
    System.out.println(Arrays.stream(words).allMatch(string -> string.contains("d"))); // true
  • findFirst() 返回流的第一个元素(如果有)。保证是第一个元素。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Test
    public void createStream_whenFindFirstResultIsPresent_thenCorrect() {

    List<String> list = Arrays.asList("A", "B", "C", "D");

    Optional<String> result = list.stream().findFirst();

    assertTrue(result.isPresent());
    assertThat(result.get(), is("A"));
    }
  • findAny() 返回流的任何元素(如果有)。不保证是第一个元素。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Test
    public void createStream_whenFindAnyResultIsPresent_thenCorrect() {
        List<String> list = Arrays.asList("A","B","C","D");
     
        Optional<String> result = list.stream().findAny();
     
        assertTrue(result.isPresent());
        assertThat(result.get(), anyOf(is("A"), is("B"), is("C"), is("D")));
    }
Collectors

终结操作中 collect 方法有两种入参,一是接收三个方法参数,二是接收一个Collector方法。而Collectors类中则内置了常用Collector。

  • toCollection(Supplier< C> collectionFactory) 自定义集合类收集元素
1
List<String> linkedListResult = Arrays.asList("cbad","def").stream().collect(Collectors.toCollection(LinkedList::new));
  • toList() 转ArrayList
1
List<String> arrayListResult = Arrays.asList("cbad","def").stream().collect(Collectors.toList());
  • toSet() 转hashSet
1
2
3
4
Person.createRoster()
.stream()
.map(person -> person.getAge())
.collect(Collectors.toSet());
  • joining() / joining(CharSequence delimiter) / joining(CharSequence delimiter,CharSequence prefix,CharSequence suffix) 拼接
1
2
3
4
String[] words = new String[]{"cbad","def"};
System.out.println(Arrays.stream(words).collect(Collectors.joining())); // cbaddef
System.out.println(Arrays.stream(words).collect(Collectors.joining("-"))); // cbad-def
System.out.println(Arrays.stream(words).collect(Collectors.joining("-", "START[", "]END"))); // START[cbad-def]END
  • mapping(Function<? super T, ? extends U> mapper, Collector<? super U, A, R> downstream) 在聚合前先对元素进行操作
1
Stream.of("cbad","def").collect(Collectors.mapping(x -> x.toUpperCase(), Collectors.joining(","))); //CBAD,DEF
  • collectingAndThen(Collector< T,A,R> downstream, Function< R,RR> finisher) 对聚合后的数据进行处理
1
2
3
4
5
6
7
8
Map<Person.Sex, Person> oldestPeople =  Person.createRoster().stream()
.collect(
Collectors.groupingBy(
Person::getGender, // 根据性别分类
Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparingInt(Person::getAge)), // 分别获取最大年龄
Optional::get) // 对聚合结果(最大年龄)进行get
));
  • counting() 统计输入元素数量

  • minBy(Comparator<? super T> comparator) maxBy(Comparator<? super T> comparator) 获取最小/大元素

  • summingInt(ToIntFunction<? super T> mapper) / summingLong / summingDouble 求和

1
Person.createRoster().stream().collect(Collectors.summingInt(Person::getAge));
  • averagingInt(ToIntFunction<? super T> mapper) / averagingLong / averagingDouble 求平均
1
Person.createRoster().stream().collect(Collectors.averagingInt(Person::getAge));
  • reducing(…) 将流的元素聚合为一个汇总值。
    • Collector< T, ?, Optional< T>> reducing(BinaryOperator< T> op)
    • Collector< T, ?, T> reducing(T identity, BinaryOperator< T> op)
    • Collector< T, ?, U> reducing(U identity,Function<? super T, ? extends U> mapper,BinaryOperator< U> op)
1
2
3
System.out.println(
Stream.of(1, 2, 3, 4).collect(
Collectors.reducing(0, (acc, item) -> acc + item)));
  • groupingBy(…) / groupingByConcurrent(…) 分组聚合

    • Collector< T, ?, Map<K, List< T>>> groupingBy(Function<? super T, ? extends K> classifier)

    • Collector< T, ?, Map< K, D>> groupingBy(Function<? super T, ? extends K> classifier,Collector<? super T, A, D> downstream)

    • < T, K, D, A, M extends Map< K, D>> Collector< T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,Supplier< M> mapFactory,Collector<? super T, A, D> downstream)

    • Collector< T, ?, ConcurrentMap< K, List< T>>> groupingByConcurrent(Function<? super T, ? extends K> classifier)

    • Collector< T, ?, ConcurrentMap< K, D>> groupingByConcurrent(Function<? super T, ? extends K> classifier,Collector<? super T, A, D> downstream)

    • < T, K, A, D, M extends ConcurrentMap< K, D>>
      Collector< T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier,Supplier< M> mapFactory,Collector<? super T, A, D> downstream)

1
2
Map<Person.Sex, List<Person>> peopleGroupBySex =  Person.createRoster().stream()
.collect(Collectors.groupingBy(Person::getGender));
  • partitioningBy(…) 分类为是否符合给定条件的两类
    • Collector< T, ?, Map< Boolean, List< T>>> partitioningBy(Predicate<? super T> predicate)
    • Collector< T, ?, Map< Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream)
1
2
3
4
5
6
Map<Boolean, List<Person>> peopleGroupBySex =  Person.createRoster().stream()
.collect(
Collectors.partitioningBy(
person -> person.getAge() >= 18
&& person.getGender() == Person.Sex.MALE)
);
  • toMap(…) / toConcurrentMap(…)

    • Collector< T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper)

    • Collector< T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper,BinaryOperator< U> mergeFunction)

    • Collector< T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper,BinaryOperator< U> mergeFunction,Supplier< M> mapSupplier)

1
2
3
4
5
Map<Integer, Person> people =  Person.createRoster().stream()
.collect(
Collectors.toMap(Person::getAge,
Function.identity(), (oldValue, item) -> item) // 这里使用了hashmap.merge,默认两参数会抛出异常,这里定义了冲突时的操作
);
  • Collector< T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) / summarizingLong / summarizingDouble
    获得统计信息 最大值,最小值,平均数,总数,总和
    1
    2
    3
    4
    Optional.ofNullable(
    roster.stream().
    collect(Collectors.summarizingInt(Person::getAge)))
    .ifPresent(System.out::println); //IntSummaryStatistics{count=20, sum=107, min=0, average=5.350000, max=9}

参考