Does Java SE 8 have Pairs or Tuples?

前端 未结 9 834
独厮守ぢ
独厮守ぢ 2020-11-28 18:37

I am playing around with lazy functional operations in Java SE 8, and I want to map an index i to a pair / tuple (i, value[i]), then <

相关标签:
9条回答
  • 2020-11-28 19:10

    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 2018-02-12: While working on a project I wrote a helper class which helps handling the special case of having an identifier earlier in the stream you need at a later time but the stream part in between does not know about it. Until I get around to release it on its own it is available at IdValue.java with a unit test at IdValueTest.java

    0 讨论(0)
  • 2020-11-28 19:14

    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 is introducing records as a preview 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 (at the time of writing, this an early access build) using the --enable-preview flag, you get the following result:

    [CountForIndex[index=0, count=0], CountForIndex[index=2, count=0], CountForIndex[index=4, count=0]]
    
    0 讨论(0)
  • 2020-11-28 19:14

    Since you only care about the indexes, you don't need to map to tuples at all. Why not just write a filter that uses the looks up elements in your array?

         int[] value =  ...
    
    
    IntStream.range(0, value.length)
                .filter(i -> value[i] > 30)  //or whatever filter you want
                .forEach(i -> System.out.println(i));
    
    0 讨论(0)
  • 2020-11-28 19:15

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

    • AbstractMap.SimpleEntry
    • AbstractMap.SimpleImmutableEntry
    0 讨论(0)
  • 2020-11-28 19:20

    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.

    0 讨论(0)
  • 2020-11-28 19:21

    Eclipse Collections has Pair and all combinations of primitive/object Pairs (for all eight primitives).

    The Tuples factory can create instances of Pair, and the PrimitiveTuples factory can be used to create all combinations of primitive/object pairs.

    We added these before Java 8 was released. They were useful to implement key/value Iterators for our primitive maps, which we also support in all primitive/object combinations.

    If you're willing to add the extra library overhead, you can use Stuart's accepted solution and collect the results into a primitive IntList to avoid boxing. We added new methods in Eclipse Collections 9.0 to allow for Int/Long/Double collections to be created from Int/Long/Double Streams.

    IntList list = IntLists.mutable.withAll(intStream);
    

    Note: I am a committer for Eclipse Collections.

    0 讨论(0)
提交回复
热议问题