Java8 Stream使用flatMap合并List_卓立的博客-CSDN博客_stream.flatmap

之前也写过很多篇关于Java8使用的文章了,但是回顾一下,好像还没介绍过Java8 Stream的flatMap操作,昨天刚好在工作中遇到一个场景,发现flatMap简直太方便了,这里总结一下flatMap的常规使用。附带讲一下,使用Java8实现集合的并、交、差操作,其实之前也讲过一种使用Guava的实现方式,具体请参考Guava集合工具

  • flatMap

首先看一下一种场景,存在一个Map<Integer, ListContainer>,ListContainer中存在一个List<AClass>成员变量。有这样一个需求,讲Map中values中所有的List<AClass>组合成一个List<AClass>。我们也许会这样操作:

List<AClass> resultAClassList = Lists.newArrayList();for (ListContainer tmp : map.values()){    resultAClassList.addAll(tmp.getLst());}

这还是只存在一层List的情况,如果存在多层,for还需要嵌套,使用起来很不方便。后来查到,Java8 Stream的flatMap操作可以很好地适用这种场景,首先看一下flatMap方法定义:

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

参数是一个Function函数式接口,提供T到Stram的转换。其实参考方法实现,flatMap就是将Function转化后的Stram合并成一个Stream。下面看一下使用示例,完成上述相同的功能:

@Testpublic void mergeMapValuesTest(){    Map<Integer, ListContainer> map = Maps.newHashMap();    List<AClass> aClassList1 = Lists.newArrayList();    AClass aClass = new AClass(1, "zhuoli1", "haha1");    aClassList1.add(aClass);    aClassList1.add(new AClass(2, "zhuoli2", "haha2"));    aClassList1.add(new AClass(3, "zhuoli3", "haha3"));     List<AClass> aClassList2 = Lists.newArrayList();    aClassList2.add(aClass);    aClassList2.add(new AClass(5, "zhuoli5", "haha5"));    aClassList2.add(new AClass(6, "zhuoli6", "haha6"));     /*交集*/    /*[AClass(id=1, name=zhuoli1, description=haha1)]*/    List<AClass> intersectResult = aClassList1.stream().filter(aClassList2::contains).collect(Collectors.toList());    System.out.println(intersectResult);     /*并集*/    List<AClass> unionResult = Stream.of(aClassList1, aClassList2).flatMap(Collection::stream).distinct().collect(Collectors.toList());    assertEquals(unionResult.size(), 5);    System.out.println(unionResult);     /*差集*/    /*[AClass(id=2, name=zhuoli2, description=haha2), AClass(id=3, name=zhuoli3, description=haha3)]*/    List<AClass> differenceResult = aClassList1.stream().filter(x -> !aClassList2.contains(x)).collect(Collectors.toList());    System.out.println(differenceResult);     map.put(1, new ListContainer(aClassList1));    map.put(2, new ListContainer(aClassList2));     /*合并多个list*/    List<AClass> aClassListResult = map.values().stream().flatMap(listContainer -> listContainer.getLst().stream()).collect(Collectors.toList());    /*注意跟并集的区别*/    assertEquals(aClassListResult.size(), 6);    System.out.println(aClassListResult);}

分享一个flatMap的复杂操作,实现List<Data1>和List<Data2>根据Id进行连接,将连接结果输出为一个List<OutputData>:

@Data@AllArgsConstructorpublic class Data1 {    private int id;    private String name;    private int amount;} @Data@AllArgsConstructorpublic class Data2 {    private int id;    private String name;    private String type;} @Data@AllArgsConstructorpublic class OutputData {    private int id;    private String name;    private String type;    private int amount;}  @Testpublic void intersectByKeyTest(){    List<Data2> listOfData2 = new ArrayList<Data2>();     listOfData2.add(new Data2(10501, "JOE"  , "Type1"));    listOfData2.add(new Data2(10603, "SAL"  , "Type5"));    listOfData2.add(new Data2(40514, "PETER", "Type4"));    listOfData2.add(new Data2(59562, "JIM"  , "Type2"));    listOfData2.add(new Data2(29415, "BOB"  , "Type1"));    listOfData2.add(new Data2(61812, "JOE"  , "Type9"));    listOfData2.add(new Data2(98432, "JOE"  , "Type7"));    listOfData2.add(new Data2(62556, "JEFF" , "Type1"));    listOfData2.add(new Data2(10599, "TOM"  , "Type4"));      List<Data1> listOfData1 = new ArrayList<Data1>();     listOfData1.add(new Data1(10501, "JOE"    ,3000000));    listOfData1.add(new Data1(10603, "SAL"    ,6225000));    listOfData1.add(new Data1(40514, "PETER"  ,2005000));    listOfData1.add(new Data1(59562, "JIM"    ,3000000));    listOfData1.add(new Data1(29415, "BOB"    ,3000000));     List<OutputData> result = listOfData1.stream()            .flatMap(x -> listOfData2.stream()                    .filter(y -> x.getId() == y.getId())                    .map(y -> new OutputData(y.getId(), x.getName(), y.getType(), x.getAmount())))            .collect(Collectors.toList());    System.out.println(result);     /*difference by key*/    List<Data1> data1IntersectResult = listOfData1.stream().filter(data1 -> listOfData2.stream().map(Data2::getId).collect(Collectors.toList()).contains(data1.getId())).collect(Collectors.toList());    System.out.println(data1IntersectResult);}
  • faltMapToInt

首先看一下flatMapToInt方法定义:

IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);

跟flatMap不同的是,参数Function函数式接口提供由T到IntStream的转化,方法返回值是IntStream。

@Testpublic void flatMapToIntTest() {    List<List<String>> listOfLists = Arrays.asList(            Arrays.asList("1", "2"),            Arrays.asList("5", "6"),            Arrays.asList("3", "4")    );     IntStream intStream =            listOfLists.stream()                    .flatMapToInt(childList ->                            childList.stream()                                    .mapToInt(Integer::new));     int sum = intStream.peek(System.out::println).sum();    System.out.println("sum: " + sum);}

Stream接口中还存在类似的方法flatMapToDouble、flatMapToLong,使用方法跟flatMapToInt是一样的,这里就不多介绍了,仅罗列一下方法定义:

DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);

示例代码:码云 – 卓立 – Java8 flatMap示例


原网址: 访问
创建于: 2022-02-14 15:24:58
目录: default
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论