java8新特性--高级集合类和收集器

1.方法引用

什么是方法引用:
对于一个对象,我们调用其方法,通常是
对象引用.方法。
比如:

package domain;

import java.io.Serializable;

public class User implements Serializable{

/**
*
*/
private static final long serialVersionUID = -8794064868071396333L;

/**
* id-id
*/
protected Long id;

/**
* name-姓名
*/
protected String name;

/**
* getter
* @return
*/
public Long getId() {
return id;
}

/**
* setter
* @param id
*/
public void setId(Long id) {
this.id = id;
}

/**
* getter
* @return
*/
public String getName() {
return name;
}

/**
* setter
* @param name
*/
public void setName(String name) {
this.name = name;
}

@Override
/**
* toString
*/
public String toString() {
return "\n{id="+this.id+",name="+this.name+"}";
}

}
public static List<User> getUsers(){
Supplier<User> userSupplier = () -> {
User user = new User();
user.setId((long)(Math.random()*100));
user.setName("name:"+Math.random());
return user;
};
Supplier<List<User>> userListSupplier = () -> {
List<User> userList = new ArrayList<>();
for(int i = 0;i < 10;i++){
userList.add(userSupplier.get());
}
return userList;
};
return userListSupplier.get();
}

如果需要调用user的名字方法
u.getName()
但是在java8中,可以使用方法引用调用:
User::getName
静态方法也可以使用方法引用:

@Test
public void testStaticMethod(){
Operator operator = StaticMethodUse::message;
System.out.println(operator.getMessage());
}

因为java8具有自动推断的功能,所以对于多个参数的方法也可以这样使用。
但是需要注意,当jvm无法通过推断去获得具体的参数以及类型时,会编译不通过。
在方法重载中可能遇见。
对于new方法同样可以使用

@Test
public void method2(){
List<User> users = getUsers();
System.out.println(users.stream().map(User::getId).collect(Collectors.toList()));
TreeSet<Long> integers = (TreeSet<Long>) users.stream()
.map(User::getId)
.collect(Collectors.toCollection(TreeSet::new));
System.out.println(integers);
}
[97, 71, 14, 81, 35, 48, 83, 87, 30, 9]
[9, 14, 30, 35, 48, 71, 81, 83, 87, 97]

2.元素顺序

流中的顺序依赖于数据源与对流的操作。
如果流的数据源于有序的集合,那么流在未进行操作处理前也是有序的,如果流的数据源于无序的集合,那么流在未进行操作处理前也是无序的。
流的某些操作会使流产生顺序:

@Test
public void method(){
Stream.of(8,7,6,5,4,3,2,1).forEach(System.out::print);
Stream.of(8,7,6,5,4,3,2,1).sorted().forEach(System.out::print);
}
8765432112345678
@Test
public void method1(){
List<Integer> nuIntegers = Stream.of(1,2,3,43,4).collect(Collectors.toList());
System.out.println(nuIntegers);
System.out.println(nuIntegers.stream().collect(Collectors.toList()));
HashSet<Integer> nuHashSet = new HashSet<>(Stream.of(1, 2, 3, 4, 5, 6,
7).collect(Collectors.toList()));
System.out.println(nuHashSet);
System.out.println(new HashSet<>(Stream.of(1, 2, 3, 4, 5, 6,
7).collect(Collectors.toList())));
}
[1, 2, 3, 43, 4]
[1, 2, 3, 43, 4]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]

但是有些操作在有序的流上开销更大,调用unordered方法可以消除顺序(理论消除)

3.收集器得到集合

流的一系列操作完成后,我们的目标是得到结果,对于处理过程的关心有时远远不如结果。
所以,对流进行操作后,需要得到各种需求的结果。

@Test
public void method2(){
List<User> users = getUsers();
System.out.println(users.stream().map(User::getId).collect(Collectors.toList()));
TreeSet<Long> integers = (TreeSet<Long>) users.stream()
.map(User::getId)
.collect(Collectors.toCollection(TreeSet::new));
System.out.println(integers);
}
[28, 27, 19, 91, 18, 24, 56, 10, 33, 20]
[10, 18, 19, 20, 24, 27, 28, 33, 56, 91]

4.收集器得到值

@Test
public void methodd() {
System.out.println(Stream.of(1, 2, 3, 4, 5, 6).count());
System.out.println(Stream.of(1, 2, 3, 4, 5, 6)
.reduce((t1, t2) -> t1 + t2).get());
}
6
21

5.数据分块

partitioningBy
根据条件把集合分为两个块,条件为真的一个块,条件不满足的一个块

@Test
public void method3() {
Map<Boolean, List<User>> map = getUsers().stream().collect(
Collectors.partitioningBy(u -> {
User user = (User) u;
return user.getId() > 50;
}));
System.out.println("true:"+map.get(Boolean.TRUE));
System.out.println("false:"+map.get(Boolean.FALSE));
}
true:[
{id=67,name=name:0.9729720092540897},
{id=65,name=name:0.3976028732740996},
{id=99,name=name:0.11859074306005513},
{id=59,name=name:0.926818840325105},
{id=89,name=name:0.07495749655123418}]
false:[
{id=13,name=name:0.2021882102021173},
{id=47,name=name:0.9757163997464735},
{id=10,name=name:0.5198655310361624},
{id=36,name=name:0.2948607355701769},
{id=45,name=name:0.4078745241528474}]

6.数据分组

有时候情况比较复杂,可能需要分为不止两个情况:
groupingBy

@Test
public void method4() {
Map<Object, List<User>> map = getUsers().stream().collect(
Collectors.groupingBy(u -> {
User user = (User) u;
return user.getId() / 10;
}));
map.keySet()
.stream()
.forEach(
key -> System.out.println(key.toString() + map.get(key)));
}
0[
{id=1,name=name:0.23476649648638293}]
1[
{id=15,name=name:0.24427781847847663}]
2[
{id=21,name=name:0.23213067356765882}]
4[
{id=45,name=name:0.10486159882705315},
{id=49,name=name:0.18522620749528862},
{id=43,name=name:0.07330274040839779}]
5[
{id=57,name=name:0.7349992581943537}]
7[
{id=73,name=name:0.8131407702525516}]
8[
{id=84,name=name:0.3420039119709738}]
9[
{id=91,name=name:0.9667753993476034}]

7.字符串

很多时候得到的只是一个字符串

@Test
public void method5() {
System.out.println(getUsers().stream().map(User::getName)
.collect(Collectors.joining(",", "[[", "]]")));
}
[[name:0.11218904193934853,name:0.25308636811198415,name:0.3285258004094165,name:0.22669912536520198,name:0.7422811971620336,name:0.11139353769100546,name:0.9213403316147115,name:0.9115647733519233,name:0.40461386849609826,name:0.18547812106089345]]

8.组合收集器

有时候对流的结果需要进行多次处理时,一个收集器无法达到目的,那么可以使用组合收集器
其中Collectors.mapping允许在收集器的容器上进行类似Map的操作。但是需要指明使用什么集合存储结果。
所以可以无限的进行处理。

@Test
public void method6() {
Map<Object, List<String>> map = getUsers().stream().collect(
Collectors.groupingBy(u -> {
User user = (User) u;
return user.getId() / 10;
}, Collectors.mapping(u -> {
User user = (User) u;
return user.getId().toString();
}, Collectors.toList())));
map.keySet()
.stream()
.forEach(
key -> System.out.println(key.toString() + map.get(key)));
}
1[11, 18, 11]
2[25, 21, 25]
3[38]
4[47]
6[62]
7[74]

9.StringJoiner

@Test
public void method7() {
System.out.println(getUsers()
.stream()
.map(User::getName)
.reduce(new StringJoiner(",", "[", "]"), StringJoiner::add,
StringJoiner::merge));
}
[name:0.05014662378597001,name:0.14382379523465583,name:0.250085350150563,name:0.4452916378928623,name:0.4577493183388345,name:0.16732177926336944,name:0.28472786466912425,name:0.9587666951439549,name:0.8634821476314806,name:0.8086175553942864]

10.Map的迭代

@Test
public void method8(){
Map<Object, List<User>> map = getUsers().stream().collect(
Collectors.groupingBy(u -> {
User user = (User) u;
return user.getId() / 10;
}));
map.forEach((k,v) -> System.out.println(k+":"+v));
}
0:[
{id=3,name=name:0.09549433059171863},
{id=9,name=name:0.18300253357797602}]
1:[
{id=15,name=name:0.007254795912946754},
{id=17,name=name:0.9921882736367683}]
2:[
{id=24,name=name:0.29708003735108823}]
4:[
{id=49,name=name:0.06957046350989127}]
5:[
{id=58,name=name:0.005931753851733501}]
6:[
{id=68,name=name:0.30472865571794816}]
8:[
{id=81,name=name:0.5635235466394759}]
9:[
{id=98,name=name:0.8223411207651237}]