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与Java 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的用处。