Java SE 8是否有对或元组?

我在Java SE 8中玩懒惰的函数操作,我想将索引i map到一个pair / tuple (i, value[i]) ,然后基于第二个value[i]元素进行filter ,最后输出只是指数。

我还必须忍受这个问题: 什么是Java中的C ++ Pair <L,R>的等价物? 在大胆的lambda和stream的新时代?

更新:我提出了一个相当简单的例子,在下面的答案之一中有@dkatzel提供的整洁的解决scheme。 但是,它并没有概括。 因此,让我加一个更一般的例子:

 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] 。 我怎样才能得到这个结果?

更新:这个答案是在回应原来的问题, Java SE 8有双或元组? (隐含的,如果不是的话,为什么不呢?)OP已经用更完整的例子更新了这个问题,但似乎可以在不使用任何types的Pair结构的情况下解决。 [OP的注意事项:这是另一个正确的答案 。]


最简洁的答案是不。 你要么必须自己推出,要么带上实现它的几个库中的一个。

在Java SE中有一个Pair类被提议并拒绝至less一次。 在一个OpenJDK邮件列表上看到这个讨论主题 。 权衡不明显。 一方面,在其他库和应用程序代码中有许多Pair实现。 这表明需要,向Java SE添加这样的类将会增加重用和共享。 另一方面,拥有Pair类增加了从Pairs和Collection中创build复杂的数据结构的诱惑,而不需要创build必要的types和抽象。 (这是凯文Bourillion从该线程的消息释义。)

我build议大家阅读整个电子邮件线程。 这是非常有见识的,没有任何反感。 这很有说服力。 当它开始的时候,我想,“是的,在Java SE中应该有一个Pair类”,但是当线程结束的时候,我改变了主意。

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

从链接的问题可以看出,Java中C ++ Pair的等价物是什么? 围绕什么显然是如此简单的API有相当大的devise空间。 对象应该是不可变的吗? 它们应该是可序列化的吗? 他们应该是可比的吗? class级应该是最终决定吗? 这两个要素是否应该订购? 它应该是一个接口还是一个类? 为什么要停止对? 为什么不是三元组,四元组或N元组?

当然还有一些不可避免的命名:

  • (a,b)
  • (第一秒)
  • (左右)
  • (汽车,司机)
  • (foo,酒吧)
  • 等等

几乎没有提到的一个大问题是对和原始的关系。 如果您有一个表示二维空间中点的(int x, int y)数据,则将其表示为Pair<Integer, Integer>消耗三个对象而不是两个32位字。 而且,这些对象必须驻留在堆上,并且会导致GC开销。

看起来很清楚,就像Streams一样,对Pairs来说也是必不可less的。 我们想看看:

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

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

当然,这些让人想起Java SE 8 java.util.function包中函数接口的泛滥。如果你不想要一个臃肿的API,那么你会抛弃哪些接口? 你也可以争辩说这还不够,还应该增加Boolean专业化。

我的感觉是,如果Java在很久以前就已经添加了一个Pair类,那么将会是简单的,甚至是简单化的,而且它不会满足我们现在正在设想的许多用例。 考虑一下,如果Pair已经在JDK 1.0时间框架中添加了,它可能会是可变的! (看看java.util.Date)人们会对此感到满意吗? 我的猜测是,如果在Java中有一个Pair类,那么它就会有些不太实用,而且每个人都会自己去满足自己的需求,外部库中会有各种各样的Pair和Tuple实现,人们仍然会争论/讨论如何修复Java的Pair类。 换句话说,就是我们今天在同一个地方。

与此同时,一些工作正在解决基本问题,这是对JVM(最终是Java语言) 价值types的更好支持。 看到这个价值观状态文件。 这是初步的,投机性的工作,它只涵盖JVM视angular的问题,但它背后已经有相当多的想法。 当然,这并不能保证它能进入Java 9,或者到任何地方,但它确实显示了这个主题的当前思维方向。

可悲的是,Java 8没有引入对或元组。 当然可以使用org.apache.commons.lang3.tuple (我个人可以和Java 8结合使用),也可以创build自己的包装器。 或使用地图。 或者类似的东西,正如你所接受的对这个问题的回答所解释的那样。

看来,完整的例子可以解决而不使用任何types的Pair结构。 关键是过滤列索引,谓词检查整个列,而不是将列索引映射到该列中的false条目数。

这样做的代码在这里:

  System.out.println( IntStream.range(0, acyclic_graph.length) .filter(i -> IntStream.range(0, acyclic_graph.length) .noneMatch(j -> acyclic_graph[j][i])) .boxed() .collect(toList())); 

这导致[0, 2, 4]输出,这是我认为OP所要求的正确结果。

还要注意boxed()操作,将int值放入Integer对象中。 这使得人们可以使用预先存在的toList()收集器,而不必写出收集器function,自己做拳击。

既然你只关心索引,你根本不需要映射到元组。 为什么不写一个使用数组中查找元素的filter呢?

  int[] value = ... IntStream.range(0, value.length) .filter(i -> value[i] > 30) //or whatever filter you want .forEach(i -> System.out.println(i)); 

你可以看看这些内置的类:

  • AbstractMap.SimpleEntry
  • AbstractMap.SimpleImmutableEntry

Vavr(以前称为Javaslang)http://www.vavr.io )提供元组(直到8的大小)。 这里是javadoc: https : //static.javadoc.io/io.vavr/vavr/0.9.0/io/vavr/Tuple.html 。

这是一个简单的例子:

 Tuple2<Integer, String> entry = Tuple.of(1, "A"); Integer key = entry._1; String value = entry._2; 

为什么JDK本身没有提供一个简单的元组直到现在对我来说是一个谜。 编写包装类似乎是一个每天的业务。

是。

Map.Entry可以用作Pair

不幸的是,这对Java 8stream没有帮助,因为即使lambda可以接受多个参数,Java语言也只允许返回一个值(对象或原始types)。 这意味着只要你有一个stream,你最终会从前一个操作中传递一个对象。 这是Java语言中的一个缺点,因为如果支持多个返回值,并且stream支持它们,我们可以通过stream完成许多更好的非平凡任务。

在那之前,只有很less的用处。