使用ForEach转换为lambda表达式

时间:2017-09-10 19:31:43

标签: for-loop lambda foreach java-8 java-stream

具有以下示例代码(此示例代码仅用于说明特定问题):

package test;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {

    private static List<Integer> integerList = Arrays.asList(1,3,5,7,9,11,13);

    private static Map<Integer, Integer> integerMap = new HashMap<>();

    public static void main(String[] args) {
        Integer number = 0;
        for (Integer integer : integerList) {
            integerMap.put(number, integer);
            number++;
        }
        System.out.println(integerMap.get(3));
    }
}

我想使用stream()forEach()将其转换为Lambda表达式,但因为我的变量number不是final(在lambda表达式中需要) ),那么这个特定的for循环不适合转换为lambda表达式吗?

2 个答案:

答案 0 :(得分:4)

你正在循环中修改变量,流不是真正适合的(你可以使用AtomicInteger - 但它会太多了)。因此,您可以迭代键的索引:

IntStream.range(0, integerList.size())
        .boxed()
        .collect(Collectors.toMap(Function.identity(), integerList::get));

答案 1 :(得分:2)

如果您要前往的是内部迭代,则可以使用

Map<Integer, Integer> integerMap = new HashMap<>();
integerList.forEach(i -> integerMap.put(integerMap.size(), i));

为了支持目标地图本身无法表达的任意临时可变状态,您需要一个保持状态的可变对象,或者作为辅助对象,或者您想要将Consumer作为内部类来实现。

相当于有状态循环的流是Collector。要使用升序键编号来保持示例,可以使用

Map<Integer, Integer> integerMap = integerList.stream()
    .collect(HashMap::new,
             (m,i) -> m.put(m.size(),i),
             (m1,m2) -> {
                 if(m1.isEmpty()) m1.putAll(m2);
                 else if(!m2.isEmpty()) {
                     int offset = m1.size();
                     m2.forEach((k,v) -> m1.put(k+offset, v));
                 }
             });

其中最复杂的是用于合并部分结果的组合器函数,它甚至不用于顺序执行,但对于收集器是必需的。

Collector API已经支持使用临时对象来保存中间可变状态,以便在最后一步中转换为最终结果。

E.g。使用随机增量而不是一个:

Map<Integer, Integer> integerMap = integerList.stream()
    .collect(Collector.of(() -> new Object() {
                 HashMap<Integer,Integer> map = new HashMap<>();
                 int lastKey;
             },
             (tmp,i) -> tmp.map.put(
                 tmp.lastKey += ThreadLocalRandom.current().nextInt(10)+1,
                 i),
             (tmp1,tmp2) -> {
                 if(tmp1.map.isEmpty()) return tmp2;
                 if(tmp2.map.isEmpty()) return tmp1;
                 int offset = tmp1.lastKey;
                 tmp2.map.forEach((k,v) -> tmp1.map.put(k + offset, v));
                 tmp1.lastKey += tmp2.lastKey;
                 return tmp1;
             },
             tmp -> tmp.map));

现在收集器有第四个函数,它从中间状态对象转换为最终结果。