学习java8这篇文章就够了 目录 基础 Java8-进阶

目录

本文分3部分

java8-基础

主要讲述java8的一些基础概念及用法。包括:Optional类,Lambda表达式,Stream接口。

java8-进阶

主要讲述java8的一些进阶用法。包括:Function接口,自定义Stream接口。

java8-实践

主要讲述java8的用法的一些比较特别的实践用法。

点一点链接,支持一波吃饭,http://aliyun.guan2ye.com/

基础

(一)optional类

  • 创建一个空Optional对象

输出的是一个空的optional对象

1
2
3
复制代码Optional<String> optional = Optional.empty();
System.out.println(optional);
##:Optional.empty
  • 创建一个非空Optional对象

如果personnull,将会立即抛出,而不是访问person的属性时获得一个潜在的错误

1
2
3
4
5
6
7
8
复制代码Person person = new Person("xu","hua");
Optional<Person> optional2 = Optional.of(person);
System.out.println(optional2);
System.out.println(optional2.get());
System.out.println(optional2.get().firstName);
##:Optional[xuhua]
xuhua
xu
  • 判断对象是否存在
1
2
3
4
复制代码System.out.println(optional.isPresent());
System.out.println(optional2.isPresent());
##:false
true
  • 如果Optional为空返回默认值
1
2
3
4
复制代码System.out.println(optional.orElse("fallback"));
optional.ifPresent(System.out::println);
##:fallback
xuhua

(二)Lambda表达式

  • Lambda表达式的使用

java8以前的字符串排列,创建一个匿名的比较器对象Comparator然后将其传递给sort方法

1
2
3
4
5
6
7
复制代码List<String> names= Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});

java8使用lambda表达式就不需要匿名对象了

1
复制代码Collections.sort(names,(String a,String b)->{return b.compareTo(a);});

简化一下:对于函数体只有一行代码的,你可以去掉大括号{}以及return关键字

1
复制代码Collections.sort(names,(String a,String b)->b.compareTo(a));

Java编译器可以自动推导出参数类型,所以你可以不用再写一次类型

1
复制代码Collections.sort(names, (a, b) -> b.compareTo(a));
1
复制代码##:[xenia, peter, mike, anna]

对于null的处理

1
2
3
4
复制代码List<String> names2 = Arrays.asList("peter", null, "anna", "mike", "xenia");
names2.sort(Comparator.nullsLast(String::compareTo));
System.out.println(names2);
##:[anna, mike, peter, xenia, null]
  • 函数式接口,方法,构造器

每一个lambda表达式都对应一个类型,通常是接口类型。

而“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。

因为默认方法不算抽象方法,所以你也可以给你的函数式接口添加默认方法。

我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,

你只需要给你的接口添加 @FunctionalInterface 注解,

编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。

+ 函数式接口



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
复制代码@FunctionalInterface
public static interface Converter<F, T> {
T convert(F from);
}
/**原始的接口实现*/
Converter<String, Integer> integerConverter1 = new Converter<String, Integer>() {
@Override
public Integer convert(String from) {
return Integer.valueOf(from);
}
};

/**使用lambda表达式实现接口*/
Converter<String, Integer> integerConverter2 = (from) -> Integer.valueOf(from);

Integer converted1 = integerConverter1.convert("123");
Integer converted2 = integerConverter2.convert("123");
System.out.println(converted1);
System.out.println(converted2);
##:123
123
/**简写的lambda表达式*/
Converter<String, Integer> integerConverter3 = Integer::valueOf;
Integer converted3 = integerConverter3.convert("123");
System.out.println(converted3);
##:123
+ 函数式方法
1
2
3
4
5
6
7
8
9
10
复制代码static class Something {
String startsWith(String s) {
return String.valueOf(s.charAt(0));
}
}
Something something = new Something();
Converter<String, String> stringConverter = something::startsWith;
String converted4 = stringConverter.convert("Java");
System.out.println(converted4);
##:j
+ 函数式构造器 Java编译器会自动根据PersonFactory.create方法的签名来选择合适的构造函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
复制代码public class Person {
public String firstName;
public String lastName;

public Person() {
}

public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

public String toString(){
return firstName+lastName;
}
}
1
2
3
4
5
6
7
复制代码interface PersonFactory<P extends Person> {
P create(String firstName, String lastName);
}
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("xu", "hua");
System.out.println(person.toString());
##:xuhua

在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。

你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。

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
30
31
32
33
34
35
36
37
38
39
40
41
42
复制代码static int outerStaticNum = 10;

int outerNum;

void testScopes() {

/**变量num可以不用声明为final*/
int num = 1;

/**可以直接在lambda表达式中访问外层的局部变量*/
Lambda2.Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + outerStaticNum+num);
String convert = stringConverter.convert(2);
System.out.println(convert);
##:13
/**但是num必须不可被后面的代码修改(即隐性的具有final的语义),否则编译出错*/
//num=3;

/**lambda内部对于实例的字段以及静态变量是即可读又可写*/
Lambda2.Converter<Integer, String> stringConverter2 = (from) -> {
outerNum = 13;
return String.valueOf(from + outerNum);
};
System.out.println(stringConverter2.convert(2));
System.out.println("\nBefore:outerNum-->" + outerNum);
outerNum = 15;
System.out.println("After:outerNum-->" + outerNum);
##:Before:outerNum-->13
After:outerNum-->15

String[] array = new String[1];
Lambda2.Converter<Integer, String> stringConverter3 = (from) -> {
array[0] = "Hi here";
return String.valueOf(from);
};
stringConverter3.convert(23);
System.out.println("\nBefore:array[0]-->" + array[0]);
array[0] = "Hi there";
System.out.println("After:array[0]-->" + array[0]);
##:Before:array[0]-->Hi here
After:array[0]-->Hi there
}

(三)Stream类

点一点链接,支持一波吃饭,http://aliyun.guan2ye.com/

java.util.Stream 表示能应用在一组元素上一次执行的操作序列。

Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,这样你就可以将多个操作依次串起来。

Stream 的创建需要指定一个数据源,比如 java.util.Collection的子类,List或者SetMap不支持。

Stream的操作可以串行执行或者并行执行。

  • Stream的基本接口
1
2
3
4
5
6
7
8
9
复制代码List<String> stringCollection = new ArrayList<>();
stringCollection.add("ddd2");
stringCollection.add("aaa2");
stringCollection.add("bbb1");
stringCollection.add("aaa1");
stringCollection.add("bbb3");
stringCollection.add("ccc");
stringCollection.add("bbb2");
stringCollection.add("ddd1");
+ Filter 过滤.


`Filter`通过一个`predicate`接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以我们可以在过滤后的结果来应用其他`Stream`操作(比如`forEach`)。


`forEach`需要一个函数来对过滤后的元素依次执行。


`forEac`h是一个最终操作,所以我们不能在`forEach`之后来执行其他`Stream`操作。



1
2
3
4
复制代码stringCollection
.stream()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);
+ Sorted 排序. `Sorted`是一个中间操作,返回的是排序好后的`Stream`。 如果你不指定一个自定义的`Comparator`则会使用默认排序.
1
2
3
4
5
复制代码stringCollection
.stream()
.sorted()
.forEach(System.out::println);
System.out.println(stringCollection);//原数据源不会被改变
+ Map. 中间操作`ma`p会将元素根据指定的`Function`接口来依次将元素转成另外的对象.
1
2
3
4
5
6
复制代码stringCollection
.stream()
.map(String::toUpperCase)
.map((s)->s+" space")
.sorted((a, b) -> b.compareTo(a))
.forEach(System.out::println);
+ Match `Stream`提供了多种匹配操作,允许检测指定的`Predicate`是否匹配整个`Stream`。 所有的匹配操作都是最终操作,并返回一个boolean类型的值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
复制代码boolean anyStartsWithA = stringCollection
.stream()
.anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA); // true

boolean allStartsWithA = stringCollection
.stream()
.allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA); // false

boolean noneStartsWithZ = stringCollection
.stream()
.noneMatch((s) -> s.startsWith("z"));
System.out.println(noneStartsWithZ); // true
+ Count 计数是一个最终操作,返回`Stream`中元素的个数,返回值类型是`long`。
1
2
3
4
5
复制代码long startsWithB = stringCollection
.stream()
.filter((s) -> s.startsWith("b"))
.count();
System.out.println(startsWithB); // 3
+ Reduce `Reduce`是一个最终操作,允许通过指定的函数来讲`stream`中的多个元素规约为一个元素,规约后的结果是通过`Optional`接口表示的。
1
2
3
4
5
6
7
8
复制代码Optional<String> reduced =
stringCollection
.stream()
.sorted()
.reduce((s1, s2) -> s1 + "#" + s2);

reduced.ifPresent(System.out::println);
##:aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2
  • 并行stream和串行stream
+ 串行stream



1
2
3
4
5
6
7
8
9
10
11
12
13
复制代码List<String> values = new ArrayList<>(MAX);
for (int i = 0; i < MAX; i++) {
UUID uuid = UUID.randomUUID();
values.add(uuid.toString());
}

long t0 = System.nanoTime();
long count = values.stream().sorted().count();
System.out.println(count);

long t1 = System.nanoTime();
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("sequential sort took: %d ms", millis));
+ 并行stream 并行`stream`是在运行时将数据划分成了多个块,然后将数据块分配给合适的处理器去处理。 只有当所有块都处理完成了,才会执行之后的代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
复制代码List<String> values = new ArrayList<>(MAX);
for (int i = 0; i < MAX; i++) {
UUID uuid = UUID.randomUUID();
values.add(uuid.toString());
}

long t0 = System.nanoTime();
long count = values.parallelStream().sorted().count();
System.out.println(count);

long t1 = System.nanoTime();
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("parallel sort took: %d ms", millis));
时间结果比较:
1
2
3
4
复制代码1000000
sequential sort took: 717 ms
1000000
parallel sort took: 303 ms
  • IntStream接口

IntStream接口是stream的一种,继承了BaseStream接口。

+ range
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
复制代码IntStream.range(0, 10)
.forEach(i -> {
if (i % 2 == 1) System.out.print(i+" ");
});
##:1 3 5 7 9

OptionalInt reduced1 =
IntStream.range(0, 10)
.reduce((a, b) -> a + b);
System.out.println(reduced1.getAsInt());

int reduced2 =
IntStream.range(0, 10)
.reduce(7, (a, b) -> a + b);
System.out.println(reduced2);
##:45
52
+ sum
1
复制代码System.out.println(IntStream.range(0, 10).sum());
  • Stream的应用
1
2
3
4
5
6
7
8
9
10
11
12
复制代码Map<String, Integer> unsortMap = new HashMap<>();
unsortMap.put("z", 10);
unsortMap.put("b", 5);
unsortMap.put("a", 6);
unsortMap.put("c", 20);
unsortMap.put("d", 1);
unsortMap.put("e", 7);
unsortMap.put("y", 8);
unsortMap.put("n", 99);
unsortMap.put("j", 50);
unsortMap.put("m", 2);
unsortMap.put("f", 9);

使用stream类来对mapvalue排序

1
2
3
4
5
6
7
8
9
复制代码public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
Map<K, V> result = new LinkedHashMap<>();
map.entrySet().parallelStream()
.sorted((o1, o2) -> (o2.getValue()).compareTo(o1.getValue()))
.forEachOrdered(x -> result.put(x.getKey(), x.getValue()));
return result;
}
System.out.println(sortByValue(unsortMap));
##:{n=99, j=50, c=20, z=10, f=9, y=8, e=7, a=6, b=5, m=2, d=1}
1
2
3
4
5
6
7
8
9
10
11
12
13
复制代码List<Object> list = new ArrayList<>();
JSONObject data1 = new JSONObject();
data1.put("type", "支出");
data1.put("money", 500);
JSONObject data2 = new JSONObject();
data2.put("type", "收入");
data2.put("money", 1000);
JSONObject data3 = new JSONObject();
data3.put("type", "借贷");
data3.put("money", 100);
list.add(data1);
list.add(data2);
list.add(data3);

使用stream类来处理list``里面的json`数据

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
30
31
32
33
34
35
36
复制代码    /**
* 按money的值来排列json
*/
list.stream()
.filter(x -> JSONObject.fromObject(x).containsKey("money"))
.sorted((b, a) -> Integer.valueOf(JSONObject.fromObject(a).getInt("money")).compareTo(JSONObject.fromObject(b)
.getInt("money")))
.forEach(System.out::println);
/**
* 找到最小的money
*/
Integer min = list.stream()
.filter(x -> JSONObject.fromObject(x).containsKey("money"))
.map(x -> JSONObject.fromObject(x).getInt("money"))
.sorted()
.findFirst()
.get();
System.out.println(min);
/**
* 计算type的数目
*/
Map<String, Integer> type_count = new HashMap<>();
list.stream()
.filter(x -> JSONObject.fromObject(x).containsKey("type"))
.map(x -> JSONObject.fromObject(x).getString("type"))
.forEach(x -> {
if (type_count.containsKey(x)) type_count.put(x, type_count.get(x) + 1);
else type_count.put(x, 1);
});
System.out.println(type_count.toString());
##:
{"type":"收入","money":1000}
{"type":"支出","money":500}
{"type":"借贷","money":100}
100
{借贷=1, 收入=1, 支出=1}

Java8-进阶

点一点链接,支持一波吃饭,http://aliyun.guan2ye.com/

函数式接口

只包含一个抽象方法的接口

  • Function<T, R>

接受一个输入参数,返回一个结果。

Function接口包含以下方法:

定义两个比较简单的函数:times2squared

1
2
复制代码Function<Integer, Integer> times2 = e -> e * 2;
Function<Integer, Integer> squared = e -> e * e;
+ `R apply(T t)`


执行函数



1
2
3
复制代码//return 8 - > 4 * 2
Integer a = times2.apply(4);
System.out.println(a);
+ `compose` 先执行参数里面的操作,然后执行调用者
1
2
3
复制代码//return 32 - > 4 ^ 2 * 2
Integer b = times2.compose(squared).apply(4);
System.out.println(b);
+ `andThen` 先执行调用者操作,再执行参数操作
1
2
3
复制代码//return 64 - > (4 * 2) ^ 2
Integer c = times2.andThen(squared).apply(4);
System.out.println(c);
+ `identity` 总是返回传入的参数本身
1
2
3
复制代码//return 4
Integer d = identity.apply(4);
System.out.println(d);
  • BiFunction<T, U, R>

接受输入两个参数,返回一个结果

+ `R apply(T t, U u)`



1
2
3
复制代码BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
//return 30
System.out.println(add.apply(10,20));
  • Supplier<T>

无参数,返回一个结果。

+ `T get()`



1
2
3
复制代码Supplier<Integer> get= () -> 10;
//return 10
Integer a=get.get();
  • Consumer<T>

代表了接受一个输入参数并且无返回的操作

+ `void accept(T t)`



1
2
复制代码//return void
Consumer<Integer> accept=x->{};
  • BiConsumer<T, U>

代表了一个接受两个输入参数的操作,并且不返回任何结果

+ `void accept(T t, U u)`



1
2
复制代码//return void
BiConsumer<Integer,Integer> accept=(x,y)->{};
  • BinaryOperator<T> extends BiFunction<T,T,T>

一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果

定义了两个静态方法:minBy,maxBy

  • Predicate<T>

接受一个输入参数,返回一个布尔值结果。

+ `test`



1
2
3
复制代码Predicate<String> predicate=x->x.startsWith("a");
//return ture
System.out.println(predicate.test("abc"));

Stream接口

  • Collector接口

Collector是Stream的可变减少操作接口

Collector<T, A, R>接受三个泛型参数,对可变减少操作的数据类型作相应限制:

T:输入元素类型

A:缩减操作的可变累积类型(通常隐藏为实现细节)

R:可变减少操作的结果类型

Collector接口声明了4个函数,这四个函数一起协调执行以将元素目累积到可变结果容器中,并且可以选择地对结果进行最终的变换:

+ `Supplier<A> supplier()`: 创建新的结果结
+ `BiConsumer<A, T> accumulator()`: 将元素添加到结果容器
+ `BinaryOperator<A> combiner()`: 将两个结果容器合并为一个结果容器
+ `Function<A, R> finisher()`: 对结果容器作相应的变换在Collector接口的characteristics方法内,可以对Collector声明相关约束:


+ `Set<Characteristics> characteristics()`:


Characteristics是Collector内的一个枚举类,声明了CONCURRENT、UNORDERED、IDENTITY\_FINISH等三个属性,用来约束Collector的属性:


    - CONCURRENT:表示此收集器支持并发,意味着允许在多个线程中,累加器可以调用结果容器
    - UNORDERED:表示收集器并不按照Stream中的元素输入顺序执行
    - IDENTITY\_FINISH:表示finisher实现的是识别功能,可忽略。
> 如果一个容器仅声明CONCURRENT属性,而不是UNORDERED属性,那么该容器仅仅支持无序的Stream在多线程中执行。

定义自己的Stream

  • collect

collect有两个接口:

1
2
3
4
复制代码<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> <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner)`



> Supplier supplier是一个工厂函数,用来生成一个新的容器;



> BiConsumer accumulator也是一个函数,用来把Stream中的元素添加到结果容器中;



> BiConsumer combiner还是一个函数,用来把中间状态的多个结果容器合并成为一个(并发的时候会用到)



1
2
3
4
5
6
7
8
复制代码Supplier<List<String>> supplier = ArrayList::new;
BiConsumer<List<String>, String> accumulator = List::add;
BiConsumer<List<String>, List<String>> combiner = List::addAll;

//return [aaa1, aaa1],实现了Collectors.toCollection
List<String> list1 = stringCollection.stream()
.filter(x -> x.startsWith("a"))
.collect(supplier, accumulator, combiner);
+ `<2> <R, A> R collect(Collector<? super T, A, R> collector)` `Collectors`是Java已经提供好的一些工具方法:
1
2
3
4
5
复制代码List<String> stringCollection = new ArrayList<>();
stringCollection.add("ddd2");
stringCollection.add("aaa1");
stringCollection.add("bbb1");
stringCollection.add("aaa1");
转换成其他集合: - `toList`
1
2
3
复制代码//return [aaa1, aaa1]
stringCollection.stream()
.filter(x -> x.startsWith("a")).collect(Collectors.toList())
- `toSet`
1
2
3
复制代码//return [aaa1]
stringCollection.stream()
.filter(x -> x.startsWith("a")).collect(Collectors.toSet())
- `toCollection` 接口:
1
复制代码public static <T, C extends Collection<T>> Collector<T, ?, C> toCollection(Supplier<C> collectionFactory)
实现:
1
2
3
4
复制代码//return [aaa1, aaa1]
List<String> list = stringCollection.stream()
.filter(x -> x.startsWith("a"))
.collect(Collectors.toCollection(ArrayList::new));
- `toMap` 接口:
1
2
3
复制代码public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper)
实现:
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
复制代码//return {aaa1=aaa1_xu}
Function<String, String> xu = x -> x + "_xu";
Map<String, String> map = stringCollection.stream()
.filter(x -> x.startsWith("a"))
.distinct()
.collect(Collectors.toMap(Function.identity(), xu));

```转成值:


- `averagingDouble`:求平均值,Stream的元素类型为double
- `averagingInt`:求平均值,Stream的元素类型为int
- `averagingLong`:求平均值,Stream的元素类型为long
- `counting`:Stream的元素个数
- `maxBy`:在指定条件下的,Stream的最大元素
- `minBy`:在指定条件下的,Stream的最小元素
- `reducing`: reduce操作
- `summarizingDouble`:统计Stream的数据(double)状态,其中包括count,min,max,sum和平均。
- `summarizingInt`:统计Stream的数据(int)状态,其中包括count,min,max,sum和平均。
- `summarizingLong`:统计Stream的数据(long)状态,其中包括count,min,max,sum和平均。
- `summingDouble`:求和,Stream的元素类型为double
- `summingInt`:求和,Stream的元素类型为int
- `summingLong`:求和,Stream的元素类型为long数据分区:


- `partitioningBy`


接口:
复制代码public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream)
1
实现:
复制代码Predicate<String> startA = x -> x.startsWith("a"); //return {false=[ddd2, bbb1], true=[aaa1, aaa1]} Map<Boolean, List<String>> map2 = stringCollection.stream() .collect(Collectors.partitioningBy(startA)); //return {false={false=[ddd2], true=[bbb1]}, true={false=[], true=[aaa1, aaa1]}} Predicate<String> end1 = x -> x.endsWith("1"); Map<Boolean, Map<Boolean, List<String>>> map3 = stringCollection.stream() .collect(Collectors.partitioningBy(startA, Collectors.partitioningBy(end1)));
1
2
3
4
5
6
	

- `groupingBy`


接口:
复制代码public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier) public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream) public static <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)
1
实现:
复制代码//rerurn {a=[aaa1, aaa1], b=[bbb1], d=[ddd2]} Function<String, String> stringStart = x -> String.valueOf(x.charAt(0)); Map<String, List<String>> map4 = stringCollection.stream() .collect(Collectors.groupingBy(stringStart)); //rerurn {ddd2=1, bbb1=1, aaa1=2} Map<String, Long> map5 = stringCollection.stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); //rerurn {d=1, a=2, b=1} Map<String, Long> map6 = stringCollection.stream() .collect(Collectors.groupingBy(stringStart, LinkedHashMap::new, Collectors.counting()));
1
2
3
4
* `reduce`


`reduce`有三个接口:

复制代码Optional reduce(BinaryOperator accumulator);

U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator combiner);

T reduce(T identity, BinaryOperator accumulator);

1
2

+ `<1> Optional<T> reduce(BinaryOperator<T> accumulator)`
复制代码BinaryOperator<String> binaryOperator = (x, y) -> x + y;
//rerurn ddd2aaa1bbb1aaa1
String reduceStr1 = stringCollection.stream().reduce(binaryOperator).orElse("");

1
+ `<2> T reduce(T identity, BinaryOperator<T> accumulator)`
复制代码//return start:ddd2aaa1bbb1aaa1 String reduceStr2=stringCollection.stream().reduce("start:",binaryOperator);
1
2
3
4
5
6
7
8
9
10
11
12
13
+ `<3> <U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner)`



> 第一个参数返回实例u,传递你要返回的U类型对象的初始化实例u



> BiFunction accumulator,负责数据的累加



> BinaryOperator combiner,负责在并行情况下最后合并每个reduce线程的结果
复制代码List<Person> personList = new ArrayList<>(); personList.add(new Person(10, 20)); personList.add(new Person(20, 30)); personList.add(new Person(30, 50)); BiFunction<Person, Person, Person> biFunction = (x, y) -> new Person(x.getAge() + y.getAge(), x.getRate() + y.getRate()); BinaryOperator<Person> binaryOperator1 = (x, y) -> new Person(x.getAge() + y.getAge(), x.getRate() + y.getRate()); Person total = personList.stream().reduce(new Person(0, 0), biFunction, binaryOperator1); System.out.println("total:"+total);
1
2
========
* Map的双重循环

复制代码 //对map的entry对象来做stream操作,使用两次forEach
Map<String, Long> map = new HashMap<>();
crowdMap.entrySet().stream()
.map(Map.Entry::getValue)
.forEach(x -> x.entrySet().forEach(y -> {
if (map.containsKey(y.getKey()))
map.put(y.getKey(), map.get(y.getKey()) + y.getValue());
else map.put(y.getKey(), y.getValue());
}));

//对map的entry对象来做stream操作,使用flatMap将stream合并
Map<String, Long> map = new HashMap<>();
crowdMap.entrySet().stream()
        .map(Map.Entry::getValue)
        .flatMap(x -> x.entrySet().stream())
        .forEach(y -> {
            if (map.containsKey(y.getKey()))
                map.put(y.getKey(), map.get(y.getKey()) + y.getValue());
            else map.put(y.getKey(), y.getValue());
        });

//使用map本身的foreach语句            
Map<String, Long> map = new HashMap<>();
crowdMap.forEach((key, value) -> value.forEach((x, y) -> {
    if (map.containsKey(x))
        map.put(x, map.get(x) + y);
    map.put(x, y);
}));
1
* List的多次分组

复制代码 //使用groupingBy将ApproveRuleDetail对象分别按照item和detail分组,并计次
Map<String, Map<String, Long>> detailMap = approveRuleDetailList.stream()
.collect(Collectors
.groupingBy(ApproveRuleDetail::getItem, Collectors.
groupingBy(ApproveRuleDetail::getDetail, Collectors.counting())));

1
* List按照自定义条件分组

复制代码 //使用自定义的Function函数,将年龄按照每10岁分组
Function<Integer, Integer> ageGroup = x -> x / 10;
Map<Integer, List> ageMap = statisticsPipelineList
.stream()
.collect(Collectors.groupingBy(y -> ageGroup.apply(y.getAge())));

1
2


复制代码 //将年龄按不同方式分组
Function<Integer, Integer> ageCredit = x -> {
if (x <= 18)
return 18;
else if (x >= 40)
return 40;
else return x;
};

//将StatisticsPipeline转化为suggestion
ToDoubleFunction<StatisticsPipeline> mapper = StatisticsPipeline::getSuggestion;

//将人群按照不同年龄分组,并计算每个年龄段的suggestion的平均值
Map<Integer, Double> ageCreditMap = statisticsPipelineList
        .stream()
        .collect(Collectors.groupingBy(y -> ageCredit.apply(y.getAge()), Collectors.averagingDouble(mapper)));
1
* 多个数据求集合

复制代码 //合并数据
private BiFunction<Integer[], ApprovePipeline, Integer[]> accumulator = (x, y) -> new Integer[]{
x[0] + y.getAuth(), x[1] + y.getAntiFraud(), x[2] + y.getCreditRule(), x[3] + y.getModelReject(), x[4] + y.getSuggestion()
};

//合并集合
private BinaryOperator<Integer[]> combiner = (x, y) -> new Integer[]{x[0] + y[0], x[1] + y[1], x[2] + y[2], x[3] + y[3], x[4] + y[4]};

//将ApprovePipeline对象的不同数据相加
Integer[] detail = approvePipelineList.stream().reduce(new Integer[]{0, 0, 0, 0, 0}, accumulator, combiner);
1
* 多个数据求集合-多重合并

复制代码 private BiFunction<Integer[], ApprovePipeline, Integer[]> accumulator = (x, y) -> new Integer[]{
x[0] += y.getAuth(), x[1] += y.getAntiFraud(), x[2] += y.getCreditRule(), x[3] += y.getModelReject(), x[4] += y.getSuggestion()
};
//合并数据
BiFunction<Integer[], Map.Entry<String, List>, Integer[]> newAccumulator = (x, y) -> {
List pipelineList = y.getValue();
Integer[] data = pipelineList.stream().reduce(new Integer[]{0, 0, 0, 0, 0}, accumulator, combiner);
return new Integer[]{
x[0] += data[0], x[1] += data[1], x[2] += data[2], x[3] += data[3], x[4] += data[4]
};
};
//最终reduce
Integer[] total = channelMap.entrySet().stream().reduce(new Integer[]{0, 0, 0, 0, 0}, newAccumulator, combiner);

1
* map最大多项和

复制代码Long hourC3 = hourMap.entrySet().stream().mapToLong(Map.Entry::getValue).sorted().limit(3).sum();



![在这里插入图片描述](https://gitee.com/songjianzaina/juejin_p8/raw/master/img/863c3cf19f6defef9144fce9c1ecd234e318d2f0cd109038d8d96cacb083d20d)






**本文转载自:** [掘金](https://juejin.cn/post/6844904049125359623)

*[开发者博客 – 和开发相关的 这里全都有](https://dev.newban.cn/)*
0%