用Stream替换forEach

时间:2019-12-12 19:20:55

标签: java java-stream

我有以下代码

TreeMap<Integer, List<String>> myMap = new TreeMap<>();
List<Integer> myList = getDataForTest(true);
List<String> wordList = getWordList(true);
List<Integer> intList = Collections.emptyList();
intList = myObj.stream().filter(e->e.getType.equalsIgnoreCase("TEST")).map(e->e.getIntPos()).collect(Collectors.toList())
AtomicInteger pos = new AtomicInteger(0);
myList.stream()
            .forEach((entry) ->{
                                if(CollectionUtils.isEmpty(intList) || intList.contains(pos.get()))
                                {
                                    myMap.computeIfAbsent(myList.get(pos.get()),k-> new ArrayList<>()).add(wordList.get(pos.get()));
                                }
                                pos.incrementAndGet();
                                    });
return myMap;

上面的代码显然会引发编译错误,因为我使用的是 intList ,它在lambda中不是最终的。有没有办法将此lambda替换为流。

3 个答案:

答案 0 :(得分:1)

this answer中所述,空列表的初始分配已过时,并且当您删除它时,只剩下一个分配,这允许从lambda表达式中引用它。但是,当您要做的只是检查集合是否为空或在其上调用DECLARE @T TABLE ( [Col1] VARCHAR(20) , [RowNum] INT ) ; INSERT INTO @T VALUES ( N'second', 1 ) , ( N'fifth', 4 ) , ( N'fourth', 3 ) --, ( N'zzz', 1 ) , ( N'third', 2 ) ---- OR when "zzz" is part of this list --VALUES -- ( N'second', 2 ) -- , ( N'fifth', 5 ) -- , ( N'fourth', 4 ) -- , ( N'zzz', 1 ) -- , ( N'third', 3 ) SELECT STUFF (( SELECT ',' + [SQ].[Col1] FROM ( SELECT N'zzz' AS [Col1] , 0 AS [RowNum] UNION SELECT [Col1] , [RowNum] FROM @T ) AS [SQ] ORDER BY [RowNum] FOR XML PATH ( '' ), TYPE ).[value] ( '.', 'varchar(MAX)' ), 1, 1, '' ) ; 时,最好使用contains,以便更快地进行查找:

Set

但是有另一种选择。代替通过测试集合中所有列表索引的存在来过滤所有列表索引,我们可以首先迭代集合的索引。我们只需要对它们进行排序和区分即可,使其与通过过滤器的List<Integer> myList = getDataForTest(true); List<String> wordList = getWordList(true); Set<Integer> intSet = myObj.stream() .filter(e -> e.getType().equalsIgnoreCase("TEST")).map(e -> e.getIntPos()) .collect(Collectors.toSet()); IntStream indices = IntStream.range(0, myList.size()); if(!intSet.isEmpty()) indices = indices.filter(intSet::contains); return indices.boxed().collect(Collectors.groupingBy(myList::get, TreeMap::new, Collectors.mapping(wordList::get, Collectors.toList()))); 索引相同。对于此类操作,更适合使用原始range值的数组:

int

如果没有将“无索引”视为“无过滤”的特殊处理,我们甚至可以在单个流操作中做到这一点。

答案 1 :(得分:0)

假设这是您的实际代码,为什么不只是将其定型呢?替换

List<Integer> intList = Collections.emptyList();
intList = myObj.stream().filter(e->e.getType.equalsIgnoreCase("TEST")).map(e->e.getIntPos()).collect(Collectors.toList())

final List<Integer> intList = myObj.stream().filter(e -> e.getType.equalsIgnoreCase("TEST")).map(e -> e.getIntPos()).collect(Collectors.toList())

除此之外,我认为不可能用流替换您的forEach,因为您在迭代列表时实际上并没有使用列表的entry做任何事情。实际上,我不太确定您实际上要完成什么。但是为什么不用简单的for循环替换它呢?

for (Integer myVal : myList){
    if (CollectionUtils.isEmpty(intList) || intList.contains(pos.get())){
        myMap.computeIfAbsent(myList.get(pos.get()), k -> new ArrayList<>()).add(wordList.get(pos.get()));
    }
    pos.incrementAndGet();
}

答案 2 :(得分:0)

我看了一段时间,然后根据自己的清单提出了一个解决方案 测试数据。

给出以下内容:

      List<Integer> myList = List.of(1, 2, 3, 4, 2);
      List<String> wordList = List.of("A", "B", "C", "D", "E");
      List<Integer> intList = List.of(1, 4, 2);

此流解决方案

      AtomicInteger pos = new AtomicInteger(-1);
      System.out.println(myMap);
      Map<Integer, List<String>> myMap2 = myList.stream().filter(
            d ->!intList.isEmpty() &&
                  intList.contains(pos.incrementAndGet())).collect(
                  Collectors.groupingBy(d -> d,
                        TreeMap::new,
                        Collectors.mapping(d -> wordList.get(pos.get()),
                              Collectors.toList())));
      System.out.println(myMap2);

您的解决方案产生

  

{2 = [B,E],3 = [C]}

我确定可以对其进行调整以提供所需的内容。

但是,在forEach上使用常规myList循环并没有错。由于没有atomic integer限制,它还使您可以摆脱effective final

      int i = 0;
      for (int entry : myList) {
         if (!intList.isEmpty() && intList.contains(i)) {
            System.out.println("entry = " + entry);
            myMap.computeIfAbsent(myList.get(i), k -> new ArrayList<>()).add(
                  wordList.get(i));
         }
         i++;
      }