Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Java SE 8 have Pairs or Tuples?

People also ask

Does Java 8 have pair?

Finally, after a long wait, a Pair<K,V> class is added in Java 8 in javafx. util package. The class represent key-value pairs and supports very basic operations like getKey() , getValue() , hashCode() , equals(java.

Does Java have tuple?

Java doesn't have any such inbuilt data structure to support tuples. Whenever required, we can create a class that can act like a tuple. Also, in Java, part of the tuple functionality can be written using List or Array but those will not allow us to hold different types of data types by design.

Do pairs exist in Java?

Pairs provide a convenient way of handling simple key to value association, and are particularly useful when we want to return two values from a method. A simple implementation of a Pair is available in the core Java libraries.

Why does Java not have tuple?

Because it's easily readable and fun to read! This is a personal and subjective opinion, and not a reason why Java doesn't include them. As a C++ dev, tuples are highly useful when used correctly and can actually add semantic meaning by saying these few things belong together, even if its just temporarily.


UPDATE: This answer is in response to the original question, Does Java SE 8 have Pairs or Tuples? (And implicitly, if not, why not?) The OP has updated the question with a more complete example, but it seems like it can be solved without using any kind of Pair structure. [Note from OP: here is the other correct answer.]


The short answer is no. You either have to roll your own or bring in one of the several libraries that implements it.

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.)

I recommend everybody read that entire email thread. It's remarkably insightful and has no flamage. It's quite convincing. When it started I thought, "Yeah, there should be a Pair class in Java SE" but by the time the thread reached its end I had changed my mind.

Note however that JavaFX has the javafx.util.Pair class. JavaFX's APIs evolved separately from the Java SE APIs.

As one can see from the linked question What is the equivalent of the C++ Pair in Java? there is quite a large design space surrounding what is apparently such a simple API. Should the objects be immutable? Should they be serializable? Should they be comparable? Should the class be final or not? Should the two elements be ordered? Should it be an interface or a class? Why stop at pairs? Why not triples, quads, or N-tuples?

And of course there is the inevitable naming bikeshed for the elements:

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

One big issue that has hardly been mentioned is the relationship of Pairs to primitives. If you have an (int x, int y) datum that represents a point in 2D space, representing this as Pair<Integer, Integer> consumes three objects instead of two 32-bit words. Furthermore, these objects must reside on the heap and will incur GC overhead.

It would seem clear that, like Streams, it would be essential for there to be primitive specializations for Pairs. Do we want to see:

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

Even an IntIntPair would still require one object on the heap.

These are, of course, reminiscent of the proliferation of functional interfaces in the java.util.function package in Java SE 8. If you don't want a bloated API, which ones would you leave out? You could also argue that this isn't enough, and that specializations for, say, Boolean should be added as well.

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.

Meanwhile, some work is going on to address the fundamental issue, which is better support in the JVM (and eventually the Java language) for value types. See this State of the Values document. This is preliminary, speculative work, and it covers only issues from the JVM perspective, but it already has a fair amount of thought behind it. Of course there are no guarantees that this will get into Java 9, or ever get in anywhere, but it does show the current direction of thinking on this topic.


You can have a look on these built-in classes :

  • AbstractMap.SimpleEntry
  • AbstractMap.SimpleImmutableEntry

Sadly, Java 8 did not introduce pairs or tuples. You can always use org.apache.commons.lang3.tuple of course (which personally I do use in combination with Java 8) or you can create your own wrappers. Or use Maps. Or stuff like that, as is explained in the accepted answer to that question you linked to.


UPDATE: JDK 14 introduced record classes as a preview feature, JDK 16 introduced them as a standard language feature. These aren't tuples, but can be used to save many of the same problems. In your specific example from above, that could look something like this:

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))
        );
    }
}

When compiled and run with JDK 14 using the --enable-preview flag or JDK 16 or later, you get the following result:

[CountForIndex[index=0, count=0], CountForIndex[index=2, count=0], CountForIndex[index=4, count=0]]

Since Java 9, you can create instances of Map.Entry easier than before:

Entry<Integer, String> pair = Map.entry(1, "a");

Map.entry returns an unmodifiable Entry and forbids nulls.


It appears that the full example can be solved without the use of any kind of Pair structure. The key is to filter on the column indexes, with the predicate checking the entire column, instead of mapping the column indexes to the number of false entries in that column.

The code that does this is here:

    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()));

This results in output of [0, 2, 4] which is I think the correct result requested by the OP.

Also note the boxed() operation that boxes the int values into Integer objects. This enables one to use the pre-existing toList() collector instead having to write out collector functions that do the boxing themselves.


Vavr (formerly called Javaslang) (http://www.vavr.io) provides tuples (til size of 8) as well. Here is the javadoc: https://static.javadoc.io/io.vavr/vavr/0.9.0/io/vavr/Tuple.html.

This is a simple example:

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

Integer key = entry._1;
String value = entry._2;

Why JDK itself did not come with a simple kind of tuples til now is a mystery to me. Writing wrapper classes seems to be an every day business.


Yes.

Map.Entry can be used as a Pair.

Unfortunately it does not help with Java 8 streams as the problem is that even though lambdas can take multiple arguments, the Java language only allows for returning a single value (object or primitive type). This implies that whenever you have a stream you end up with being passed a single object from the previous operation. This is a lack in the Java language, because if multiple return values was supported AND streams supported them we could have much nicer non-trivial tasks done by streams.

Until then, there is only little use.

EDIT 2021-05-10: Java 16 brought records which is a very nice solution to this and other issues. A very strong reason to target Java 17 LTS coming soon