小编典典

Java SE 8 是否有对或元组?

all

我正在玩 Java SE 8 中的惰性函数操作,我想为pair / tuple 创建map一个索引,然后基于第二个元素,最后只输出索引。i``(i, value[i])``filter``value[i]

我还必须忍受这个:Java 中的 C++ Pair
等价物是什么?
在 lambda 和流的大胆新时代?

更新: 我提出了一个相当简化的示例,@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]其对应于所有 3 列的 计数false。我需要的是这三列的 索引
。正确的输出应该是[0, 2, 4]. 我怎样才能得到这个结果?


阅读 63

收藏
2022-06-22

共1个答案

小编典典

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


最简洁的答案是不。您要么必须自己动手,要么引入实现它的几个库之一。

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

我建议每个人都阅读整个电子邮件线程。它非常有洞察力,没有火焰。这很有说服力。当它开始时,我想,“是的,Java SE 中应该有一个 Pair
类”,但是当线程结束时,我改变了主意。

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

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

当然,元素的命名是不可避免的:

  • (a, b)
  • (first, second)
  • (left, right)
  • (car, cdr)
  • (foo, bar)
  • etc.

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

似乎很清楚,就像 Streams 一样,对 Pairs 有原始的专业化是必不可少的。我们想看到:

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

即使 anIntIntPair仍然需要堆上的一个对象。

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

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

同时,一些工作正在进行以解决基本问题,即 JVM(以及最终的 Java 语言)对 值类型
的更好支持。请参阅此《价值观状态》文件。这是初步的推测性工作,它仅涵盖
JVM 角度的问题,但背后已经有相当多的思考。当然,不能保证这会进入 Java 9 或任何地方,但它确实显示了当前对该主题的思考方向。

2022-06-22