How to implement tuple unpacking for function parameters in Java?

Viewed 2338

I have created some tuple classes, and put them into Java collection. But I don't want to use tuple as function parameters directly when iterating collection.So I implemented tuple unpacking as the following code.

Basically it works, but the problem is that a type casting is needed:

map((Func2<Long, Long, Long>) (a, b) -> a + b)

Is there any way to remove the type casting here?


edit:

Maybe I didn't make it clear, not only tuple2, but also tuple3, tuple4... should be supported. @Flown's answer works greatly for Tuple2, but doesn't work for tuple2, tuple3, tuple4 in the meantime

package test;


import com.google.common.collect.Iterables;

import java.util.Arrays;
import java.util.function.Function;

import static test.TupleIterable.Tuple.tuple;

public interface TupleIterable<T> {

    Iterable<T> apply();

    static <E> TupleIterable<E> from(Iterable<E> iterable) {
        return () -> iterable;
    }

    default <E> TupleIterable<E> map(Function<? super T, ? extends E> op) {
        return () -> Iterables.transform(TupleIterable.this.apply(), op::apply);
    }

    interface Func2<T1, T2, R> extends Function<Tuple.Tuple2<T1, T2>, R> {

        R apply(T1 t1, T2 t2);

        @Override
        default R apply(Tuple.Tuple2<T1, T2> t) {
            return apply(t.t1, t.t2);
        }
    }

    interface Func3<T1, T2, T3, R> extends Function<Tuple.Tuple3<T1, T2, T3>, R> {

        R apply(T1 t1, T2 t2, T3 t3);

        @Override
        default R apply(Tuple.Tuple3<T1, T2, T3> t) {
            return apply(t.t1, t.t2, t.t3);
        }
    }

    interface Tuple {

        static <T1, T2> Tuple2<T1, T2> tuple(T1 t1, T2 t2) {
            return new Tuple2<>(t1, t2);
        }

        static <T1, T2, T3> Tuple3<T1, T2, T3> tuple(T1 t1, T2 t2, T3 t3) {
            return new Tuple3<>(t1, t2, t3);
        }

        class Tuple2<T1, T2> implements Tuple {

            public T1 t1;

            public T2 t2;

            public Tuple2(T1 t1, T2 t2) {
                this.t1 = t1;
                this.t2 = t2;
            }
        }

        class Tuple3<T1, T2, T3> implements Tuple {

            public T1 t1;

            public T2 t2;

            public T3 t3;

            public Tuple3(T1 t1, T2 t2, T3 t3) {
                this.t1 = t1;
                this.t2 = t2;
                this.t3 = t3;
            }
        }
    }

    public static void main(String[] args) {
        TupleIterable.from(Arrays.asList(1L, 2L))
                .map(x -> tuple(x, x)) // map long to tuple2
                .map((Func2<Long, Long, Tuple.Tuple3<Long, Long, Long>>) (a, b) -> tuple(a, b, a + b)) // map tuple2 to tuple3
                .map((Func3<Long, Long, Long, Long>) (a, b, c) -> a + b + c) // map tuple3 to Long
                .apply()
                .forEach(System.out::println);
    }
}
3 Answers
Related