具有以下示例代码(此示例代码仅用于说明特定问题):
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表达式吗?
答案 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));
现在收集器有第四个函数,它从中间状态对象转换为最终结果。