在java8之后使用stream将list转成map,以及对list中的map分组求和;Stream的常用操作;按条件分割集合;map和flatmap

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: 阿浪

要注意的是map的key必须唯一,所以有可能出现不唯一的时候,就会报错

@Test
    public void listToMapByAgeKey(){
        // value 为对象中的属性
        Map<Integer, String> map = list.stream().collect(Collectors.toMap(Student::getAge, Student::getName));
    }

会有key重复异常

java.lang.IllegalStateException: Duplicate key 小花

因为age有相同就会报错 此时stream包下Collectors.toMap方法有一个重载方法的参数,这个参数可以传一个合并的函数解决冲突

@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);

和之前的结果是一样的,但是这个更简化一步到位
在java8之后使用stream将list转成map,以及对list中的map分组求和;Stream的常用操作;按条件分割集合;map和flatmap_第1张图片

filter过滤

该操作会接受一个谓词(一个返回boolean的函数)作为参数,并返回一个包括所有符合谓词的元素的流
filter中的方法返回 boolean类型 即 true/false,当里面的表达式 = true的时候表明当前元素被过滤掉了,剩下的都是返回false的元素。

list.stream()
	.filter(TestObject::isMng)
	.collect(Collectors.toList());

distinct去重

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直接获取前几条记录

流支持limit(n)方法,该方法会返回一个不超过给定长度的流
获取前5条

list.stream()
	.filter(u->u.getSex().equals("M"))
	.limit(5).forEach(u->System.out.println(u.getName()));

skip跳过元素

流还支持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将集合中的元素通过一个闭包转成其他类型

流支持map方法,它会接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映射成一个新的元素

list.stream()
	.map(TestObject::getName)
	.collect(Collectors.toList())
	.forEach(System.out::println);

anyMatch检查集合中是否至少有一个元素满足条件

anyMatch返回boolean类型true/false

if(list.stream().anyMatch(u->u.getName().equals("Ron"))){
  System.out.println("Ron已经到了");
}

allMatch检查集合中的所有元素是否都满足条件

allMatch返回boolean类型true/false

if(list.stream().allMatch(u->u.getAge()>=10)){
  System.out.println("很棒,都大于10岁");
}else{
  System.out.println("原来都还没发育");
}

noneMatch检查集合中的元素是否都不满足条件,和allMatch相反

if(list.stream().noneMatch(u->u.getAge()<10)){
  System.out.println("很棒,都大于10岁");
}else{
  System.out.println("原来都还没发育");
}

findAny返回任意一个元素

list.stream()
  .filter(u->u.getName().equals("Ron"))
  .findAny()
  .ifPresent(u->System.out.println(u.getName()));

findFirst返回第一个元素

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列表。

map和flatmap

在stream中一般map用的比较多,不过还有一个名字很像的flatmap。用法也很简单,就是将嵌套集合打平。

直接上demo吧

在java8之后使用stream将list转成map,以及对list中的map分组求和;Stream的常用操作;按条件分割集合;map和flatmap_第2张图片

你可能感兴趣的:(JAVA,list,junit,java)