我正在Java SE 8中使用惰性函数操作,我想将一个索引I映射到一个对/元组(I,值[I]),然后根据第二个值[I]元素进行筛选,最后只输出索引。
我还必须忍受这个问题:Java中的c++ Pair<L,R>等价于什么?在大胆的新时代的lambdas和溪流?
更新:我给出了一个相当简单的例子,在下面的一个答案中,@dkatzel提供了一个简洁的解决方案。然而,它并不能一概而论。因此,让我补充一个更普遍的例子:
package com.example.test;
import java.util.ArrayList;
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
boolean [][] directed_acyclic_graph = new boolean[][]{
{false, true, false, true, false, true},
{false, false, false, true, false, true},
{false, false, false, true, false, true},
{false, false, false, false, false, true},
{false, false, false, false, false, true},
{false, false, false, false, false, false}
};
System.out.println(
IntStream.range(0, directed_acyclic_graph.length)
.parallel()
.mapToLong(i -> IntStream.range(0, directed_acyclic_graph[i].length)
.filter(j -> directed_acyclic_graph[j][i])
.count()
)
.filter(n -> n == 0)
.collect(() -> new ArrayList<Long>(), (c, e) -> c.add(e), (c1, c2) -> c1.addAll(c2))
);
}
}
这给出了不正确的输出[0,0,0],它对应于三列的计数都是假的。我需要的是这三列的下标。正确的输出应该是[0,2,4]。我怎样才能得到这个结果?
遗憾的是,Java 8没有引入对或元组。当然,您总是可以使用org.apache.commons.lang3.tuple(我个人在与Java 8结合使用时使用它),或者您可以创建自己的包装器。或者使用地图。或者类似的东西,就像你链接的那个问题的公认答案所解释的那样。
更新:JDK 14将记录类作为预览特性引入,JDK 16将它们作为标准语言特性引入。它们不是元组,但可以用来解决许多相同的问题。在上面的具体例子中,可能是这样的:
public class Jdk14Example {
record CountForIndex(int index, long count) {}
public static void main(String[] args) {
boolean [][] directed_acyclic_graph = new boolean[][]{
{false, true, false, true, false, true},
{false, false, false, true, false, true},
{false, false, false, true, false, true},
{false, false, false, false, false, true},
{false, false, false, false, false, true},
{false, false, false, false, false, false}
};
System.out.println(
IntStream.range(0, directed_acyclic_graph.length)
.parallel()
.mapToObj(i -> {
long count = IntStream.range(0, directed_acyclic_graph[i].length)
.filter(j -> directed_acyclic_graph[j][i])
.count();
return new CountForIndex(i, count);
}
)
.filter(n -> n.count == 0)
.collect(() -> new ArrayList<CountForIndex>(), (c, e) -> c.add(e), (c1, c2) -> c1.addAll(c2))
);
}
}
当使用——enable-preview标志或JDK 16或更高版本编译并运行JDK 14时,你会得到以下结果:
[CountForIndex[index=0, count=0], CountForIndex[index=2, count=0], CountForIndex[index=4, count=0]]
更新:这个答案是在回应最初的问题,Java SE 8有对或元组吗?(如果没有,那为什么不呢?)OP已经用一个更完整的例子更新了这个问题,但它似乎可以在不使用任何形式的Pair结构的情况下解决。[OP注:这是另一个正确答案。]
简短的回答是否定的。您要么必须滚出您自己的,要么引入实现它的几个库之一。
Having a Pair class in Java SE was proposed and rejected at least once. See this discussion thread on one of the OpenJDK mailing lists. The tradeoffs are not obvious. On the one hand, there are many Pair implementations in other libraries and in application code. That demonstrates a need, and adding such a class to Java SE will increase reuse and sharing. On the other hand, having a Pair class adds to the temptation of creating complicated data structures out of Pairs and collections without creating the necessary types and abstractions. (That's a paraphrase of Kevin Bourillion's message from that thread.)
我建议大家阅读整封邮件。这是非常深刻的见解,没有火焰。这很有说服力。当它开始时,我想,“是的,在Java SE中应该有一个Pair类”,但当线程到达它的结尾时,我改变了我的想法。
但是请注意,JavaFX有JavaFX .util. pair类。JavaFX的api是从Java SE api独立发展而来的。
从链接的问题中可以看到,在Java中什么是等价的c++对?显然,如此简单的API有相当大的设计空间。对象应该是不可变的吗?它们应该是可序列化的吗?它们是否具有可比性?这门课到底要不要结束?这两个元素应该排序吗?应该是接口还是类?为什么止步于结对?为什么不是三元组、四元组或n元组?
当然,元素不可避免地会被命名为bikeshed:
(a, b)
(一、二)
(左,右)
(汽车,cdr)
(foo, bar)
等。
一个很少被提及的大问题是pair与原语的关系。如果有一个(int x, int y)数据表示2D空间中的一个点,表示为Pair<Integer, Integer>占用三个对象,而不是两个32位的单词。此外,这些对象必须驻留在堆上,并且会引起GC开销。
很明显,就像Streams一样,pair必须有基本的专门化。我们想看到:
Pair
ObjIntPair
ObjLongPair
ObjDoublePair
IntObjPair
IntIntPair
IntLongPair
IntDoublePair
LongObjPair
LongIntPair
LongLongPair
LongDoublePair
DoubleObjPair
DoubleIntPair
DoubleLongPair
DoubleDoublePair
即使是IntIntPair仍然需要堆上的一个对象。
当然,这让人联想到Java SE 8中的Java .util.function包中函数接口的激增。如果你不想要一个臃肿的API,你会舍弃哪些?您也可以认为这还不够,还应该添加布尔值的专门化。
My feeling is that if Java had added a Pair class long ago, it would have been simple, or even simplistic, and it wouldn't have satisfied many of the use cases we are envisioning now. Consider that if Pair had been added in the JDK 1.0 time frame, it probably would have been mutable! (Look at java.util.Date.) Would people have been happy with that? My guess is that if there were a Pair class in Java, it would be kinda-sort-not-really-useful and everybody will still be rolling their own to satisfy their needs, there would be various Pair and Tuple implementations in external libraries, and people would still be arguing/discussing about how to fix Java's Pair class. In other words, kind of in the same place we're at today.
与此同时,一些工作正在着手解决基本问题,即JVM(最终是Java语言)更好地支持值类型。请参阅“值的状态”文档。这是初步的、推测性的工作,它只涵盖了JVM角度的问题,但它背后已经有了相当多的思考。当然,并不能保证Java 9中会出现这种情况,或者任何情况下都会出现这种情况,但它确实显示了当前对这个主题的思考方向。