import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.junit.Test;
/**
* Created by Jackielee on 2017
* @author: lizhilong
* @date: 2017-11-24 10:13:57
* @Copyright: 2017 www.aliyun.com Inc. All rights reserved.
*/
public class DemoListToMap {
List<Student> list = Arrays.asList(new Student(1, 18, "阿龙", GenderColumn.BOY.getCode()),
new Student(2, 17, "小花", GenderColumn.GIRL.getCode()),
new Student(3, 17, "阿浪", GenderColumn.LADYBOY.getCode()));
@Test
public void listToMapByObjectValue(){
// value 为对象 student -> student jdk1.8返回当前对象
Map<Integer, Student> map = list.stream().collect(Collectors.toMap(Student::getId, student -> student));
// 遍历打印结果
map.forEach((key, value) -> {
System.out.println("key: " + key + " value: " + value);
});
}
@Test
public void listToMapByNameValue(){
// value 为对象中的属性
Map<Integer, String> map = list.stream().collect(Collectors.toMap(Student::getId, Student::getName));
map.forEach((key, value) -> {
System.out.println("key: " + key + " value: " + value);
});
}
}
value为对象执行结果:
key: 1 value: Student [id=1, age=18, name=阿龙, gender=0]
key: 2 value: Student [id=2, age=17, name=小花, gender=1]
key: 3 value: Student [id=3, age=17, name=阿浪, gender=2]
value为字段执行结果:
key: 1 value: 阿龙
key: 2 value: 小花
key: 3 value: 阿浪
@Test
public void listToMapByAgeKey(){
// value 为对象中的属性
Map<Integer, String> map = list.stream().collect(Collectors.toMap(Student::getAge, Student::getName));
}
会有key重复异常
java.lang.IllegalStateException: Duplicate key 小花
@Test
public void listToMapByAgeKey(){
// value 为对象中的属性
Map<Integer, String> map = list.stream().collect(
Collectors.toMap(Student::getAge, Student::getName, (key1, key2) -> key1)
);
map.forEach((key, value) -> {
System.out.println("key: " + key + " value: " + value);
});
}
执行结果:
key: 17 value: 小花
key: 18 value: 阿龙
List
分组求和 List<Map> list = new ArrayList();
Map<String,Integer> test = new HashMap(){{
put("id",1);
put("qty",1);
}};
list.add(test);
test = new HashMap(){{
put("id",1);
put("qty",2);
}};
list.add(test);
test = new HashMap(){{
put("id",2);
put("qty",2);
}};
list.add(test);
test = new HashMap(){{
put("id",2);
put("qty",2);
}};
list.add(test);
test = new HashMap(){{
put("id",3);
put("qty",2);
}};
list.add(test);
test = new HashMap(){{
put("id",4);
put("qty",2);
}};
list.add(test);
Map<Object,List<Map>> result = list.stream().collect(Collectors.groupingBy(it -> it.get("id")));
System.out.println(result);
Map tmpResult = new HashMap();
result.forEach((k,v)->{
tmpResult.put(k,v.stream().mapToInt(e -> (int) e.get("qty")).sum());
});
System.out.println(tmpResult);
理解了上面的操作后其实代码还可以简化
这里回顾下 list 的声明类型是List
在经过 collect(Collectors.groupingBy(it -> it.get("id")))
之后获得的数据类型是Map
Map tmpResult = new HashMap();
list.stream()
.collect(Collectors.groupingBy(it -> it.get("id")))
.forEach((k,v)->{
tmpResult.put(k,v.stream().mapToInt(e -> (int) e.get("qty")).sum());
});
System.out.println("tmpResult:" + tmpResult);
中间
list.stream()
.collect(Collectors.groupingBy(it -> it.get("id")))
获得的是一个Map但是这个map不是我们的要最终结果,需要的是最后的tmpResult这个map
再进一步简化
经过了上面2遍的操作后,逐渐加深对stream的理解
其实还可以更加简化
Map result = list.stream()
.collect(Collectors.groupingBy(it -> it.get("id")))
.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey(),e -> e.getValue().stream().mapToInt(a -> (int) a.get("qty")).sum(),(key1,key2)->key1));
System.out.println("result:" + result);
该操作会接受一个谓词(一个返回boolean的函数)作为参数,并返回一个包括所有符合谓词的元素的流
filter
中的方法返回 boolean
类型 即 true/false
,当里面的表达式 = true
的时候表明当前元素被过滤掉了,剩下的都是返回false的元素。
list.stream()
.filter(TestObject::isMng)
.collect(Collectors.toList());
distinct
返回一个元素各异(根据流所生成元素的hashCode和equals方法实现
)的流
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream()
.filter(i -> i % 2 == 0)
.distinct()
.forEach(System.out::println);
流支持limit(n)方法,该方法会返回一个不超过给定长度的流
获取前5条
list.stream()
.filter(u->u.getSex().equals("M"))
.limit(5).forEach(u->System.out.println(u.getName()));
流还支持skip(n)方法,返回一个扔掉了前n个元素的流
如果流中元素不足n个,则返回一个空流。
list.stream()
.filter(u->u.getSex().equals("M"))
//传入自定义比较排个序
.sorted(Comparator.comparing(TestObject::getName))
.skip(1)
.forEach(u->System.out.println(u.getName()));
流支持map方法,它会接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映射成一个新的元素
list.stream()
.map(TestObject::getName)
.collect(Collectors.toList())
.forEach(System.out::println);
anyMatch返回boolean类型true/false
if(list.stream().anyMatch(u->u.getName().equals("Ron"))){
System.out.println("Ron已经到了");
}
allMatch返回boolean类型true/false
if(list.stream().allMatch(u->u.getAge()>=10)){
System.out.println("很棒,都大于10岁");
}else{
System.out.println("原来都还没发育");
}
if(list.stream().noneMatch(u->u.getAge()<10)){
System.out.println("很棒,都大于10岁");
}else{
System.out.println("原来都还没发育");
}
list.stream()
.filter(u->u.getName().equals("Ron"))
.findAny()
.ifPresent(u->System.out.println(u.getName()));
list.stream()
.filter(u->u.isLeader())
.findFirst()
.ifPresent(u->System.out.println(u.getName()));
List<Integer> integers = [ 1,2,3,4,5,6,7,8,9]
//现在需要把集合按奇偶数分割为两个列表。这种情况下,我们可以使用Collectors.partitioningBy来分割:
Map<Boolean, List<Integer>> map =
integers.stream().collect(Collectors.partitioningBy(x -> x%2 == 0));
//partitioningBy会根据值是否为true,把集合分割为两个列表,一个true列表,一个false列表。
在stream中一般map用的比较多,不过还有一个名字很像的flatmap。用法也很简单,就是将嵌套集合打平。
直接上demo吧