在Java8
中,处理两个并行流中的项目对,如下所示:
final List<Item> items = getItemList();
final int l = items.size();
List<String> results = Collections.synchronizedList(new ArrayList<String>());
IntStream.range(0, l - 1).parallel().forEach(
i -> {
Item item1 = items.get(i);
int x1 = item1.x;
IntStream.range(i + 1, l).parallel()
.forEach(j -> {
Item item2 = items.get(j);
int x2 = item2.x;
if (x1 + x2 < 200) return;
// code that writes to ConcurrentHashMap defined near results
if (x1 + x2 > 500) results.add(i + " " + j);
});
}
);
每个流对都写入ConcurrentHashMap
,并且根据某些条件,它可以通过调用return;
来终止流执行,或者它可以写入同步列表。
我想让流返回像return i + " " + j
这样的结果,并将这些结果收集到外面的列表字符串中。它应该是部分的,因为必须支持返回任何内容(如果是x1 + x2 < 200
)。
实现这一目标的最省时(最快的代码)方法是什么?
答案 0 :(得分:0)
在这个答案中,我不会解决时间效率问题,因为事先应该处理正确性问题。
正如我在评论中所说,如果我们并行化流,则无法在某个条件之后停止流执行。否则,在触发停止条件(i,j)
的对之后,可能会有一些已经执行的对x1 + x2 < 200
在数字上。
另一个问题是lambda中的return;
,它所做的就是跳过if
所拥有的j
的第二个x1 + x2 < 200
,但是流将继续j+1
1}}。
没有简单的方法可以在Java中停止流,但是我们可以使用allMatch
实现这一点,因为我们可以预期,一旦找到false
值,它就会短路并以正确的方式返回false
。
因此,这将是您的代码的正确版本:
IntStream.range(0, l - 1).allMatch(i -> {
int x1 = items.get(i).x;
return IntStream.range(i + 1, l).allMatch(j -> {
int x2 = items.get(j).x;
if (x1 + x2 < 200) {
return false;
} else {
if (x1 + x2 > 500) results2.add(i + " " + j);
return true;
}
});
});
对于以下示例,使用构造函数Item(int x, int y)
:
final List<Item> items = Arrays.asList(
new Item(200, 0),
new Item(100, 0),
new Item(500, 0),
new Item(400, 0),
new Item(1, 0));
我的版本中results
的内容是:
[0 2, 0 3, 1 2]
使用您的代码(每次执行中的顺序和元素不同):
[2 4, 2 3, 1 2, 0 3, 0 2]
答案 1 :(得分:-1)
我认为这会更有效率(虽然没有做任何微观基准测试):
IntStream.range(0,l-1).forEach(
i -> IntStream.range(i+1,l)
.filter(j -> items.get(i).x + items.get(j).x > 500)
.forEach(j -> results.add(i + " " + j)));
但是,如果我真的担心这样做的时间,我会更加注意List
使用items
实现的类型。甚至可能在进入lambda之前将列表转换为HashMap<Integer, Item>
。例如,如果items
是LinkedList
,则对lambda的任何改进都可能无关紧要,因为items.get()
会一直消耗掉。