Java SE 8 是否有对或元组?

我正在Java SE 8中玩懒惰的函数操作,并且我想将索引设置为一对/元组,然后基于第二个元素,最后只输出索引。mapi(i, value[i])filtervalue[i]

我必须仍然遭受这样的痛苦:在lambda和流的大胆新时代,Java中的C++ Pair<L,R>的等价物是什么

更新:我提出了一个相当简化的示例,其中包含@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]false[0, 2, 4]


答案 1

更新:这个答案是对原始问题的回应,Java SE 8是否有对或元组?(隐式地,如果没有,为什么不呢?OP用一个更完整的例子更新了这个问题,但似乎可以在不使用任何类型的对结构的情况下解决它。[OP注意:这是另一个正确答案


简短的答案是否定的。您要么必须推出自己的库,要么引入实现它的几个库之一。

在Java SE中拥有一个类被提出并被拒绝了至少一次。请参阅其中一个 OpenJDK 邮件列表上的此讨论线程。权衡并不明显。一方面,其他库和应用程序代码中有许多 Pair 实现。这表明了需求,将这样的类添加到Java SE将增加重用和共享。另一方面,拥有 Pair 类增加了从 Pair 和集合中创建复杂数据结构而不创建必要类型和抽象的诱惑。(这是对凯文·布里尔利翁(Kevin Bourillion)从该帖子中传达的信息的转述。Pair

我建议每个人都阅读整个电子邮件线程。它非常有见地,没有火焰。这是非常有说服力的。当它开始时,我想,“是的,Java SE中应该有一个Fair类”,但是当线程到达终点时,我已经改变了主意。

但请注意,JavaFX 具有 javafx.util.Pair 类。JavaFX的API与Java SE API分开发展。

从链接的问题中可以看出,Java中的C++对的等效物是什么?围绕着一个看似如此简单的API,有相当大的设计空间。对象应该是不可变的吗?它们应该是可序列化的吗?它们应该具有可比性吗?该类是否应该是最终的?是否应对这两个元素进行排序?它应该是一个接口还是一个类?为什么停在配对?为什么不是三元组、四元组或 N 元组?

当然,对于这些元素,不可避免地会命名自行车棚:

  • (一、二)
  • (第一、第二)
  • (左、右)
  • (汽车,cdr)
  • (foo, bar)
  • 等。

一个几乎没有被提及的大问题是对与基元的关系。如果基准表示 2D 空间中的某个点,则将其表示为将消耗三个对象,而不是两个 32 位字。此外,这些对象必须驻留在堆上,并且会产生 GC 开销。(int x, int y)Pair<Integer, Integer>

很明显,像Streams一样,对于对的原始特化至关重要。我们是否希望看到:

Pair
ObjIntPair
ObjLongPair
ObjDoublePair
IntObjPair
IntIntPair
IntLongPair
IntDoublePair
LongObjPair
LongIntPair
LongLongPair
LongDoublePair
DoubleObjPair
DoubleIntPair
DoubleLongPair
DoubleDoublePair

即使 a 仍然需要堆上有一个对象。IntIntPair

当然,这些都让人想起 Java SE 8 中包中功能接口的激增。如果你不想要一个臃肿的API,你会省略哪些?你也可以争辩说这还不够,而且也应该添加专业化。java.util.functionBoolean

我的感觉是,如果Java很久以前就添加了一个Fair类,那么它就会很简单,甚至过于简单,它不会满足我们现在设想的许多用例。考虑一下,如果在 JDK 1.0 时间范围内添加了 Pair,它可能是可变的!(看看java.util.Date。人们会对此感到满意吗?我的猜测是,如果Java中有一个Fair类,它将有点排序-不是真的有用,每个人都会滚动自己的来满足他们的需求,外部库中会有各种Fair和Tuple实现,人们仍然会争论/讨论如何修复Java的Fair类。换句话说,有点像我们今天所处的位置。

与此同时,一些工作正在进行中,以解决基本问题,即在JVM(最终是Java语言)中更好地支持值类型。请参阅此“值的状态”文档。这是初步的,推测性的工作,它只涵盖了从JVM角度的问题,但它背后已经有相当多的思考。当然,不能保证这会进入Java 9,或者永远不会进入任何地方,但它确实显示了当前关于这个主题的思维方向。


答案 2

您可以查看这些内置类: