java - 如何在Java中实现函数参数的元组解包?

标签 java java-8

我已经创建了一些 tuple类,并将它们放入 Java 集合中。但我不想使用 tuple在迭代集合时直接作为函数参数。所以我实现了元组解包,如下代码。

基本上它可以工作,但问题是需要进行类型转换:

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

有没有办法去掉这里的类型转换?


编辑:

可能是我没说清楚,不仅tuple2 , 还有 tuple3 , tuple4 ……应该支持。 @Flown 的回答对 Tuple2 非常有用, 但不适用于 tuple2 , tuple3 , tuple4同时

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

最佳答案

您可以使用与 JDK 开发人员对原始类型的 Stream 特化相同的技巧。在不同的接口(interface)中引入mapToTupleunwrap

我重写了您的一些代码并使用了一些现有的FunctionalInterfaces

import java.util.Arrays;
import java.util.Iterator;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

public class Test {

  public static void main(String... args) {
    MyIterable.from(Arrays.asList(1L, 2L)).mapToTuple(l -> Tuple2.tuple(l, l + 1L)).unwrap((a, b) -> a + b).get()
        .forEach(System.out::println);
  }
}

final class Tuple2<T1, T2> {

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

  public final T1 t1;
  public final T2 t2;

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

@FunctionalInterface
interface TupleIterable<T1, T2> extends Supplier<Iterable<Tuple2<T1, T2>>> {

  default <E> MyIterable<E> unwrap(BiFunction<T1, T2, E> func) {
    return () -> Iterables.transform(get(), t -> func.apply(t.t1, t.t2));
  }
}

@FunctionalInterface
interface MyIterable<T> extends Supplier<Iterable<T>> {

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

  default <E> MyIterable<E> map(Function<? super T, ? extends E> mapper) {
    return () -> Iterables.transform(get(), mapper::apply);
  }

  default <T1, T2> TupleIterable<T1, T2> mapToTuple(Function<? super T, ? extends Tuple2<T1, T2>> tupleMapper) {
    return () -> Iterables.transform(get(), tupleMapper::apply);
  }
}

final class Iterables {
  public static <T, E> Iterable<E> transform(Iterable<T> iterable, Function<? super T, ? extends E> mapper) {
    return () -> new Iterator<E>() {

      private final Iterator<T> iter = iterable.iterator();

      @Override
      public boolean hasNext() {
        return iter.hasNext();
      }

      @Override
      public E next() {
        return mapper.apply(iter.next());
      }
    };
  }
}

关于java - 如何在Java中实现函数参数的元组解包?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44365038/

相关文章:

java - 为什么会产生索引越界错误?

java - 如何(简单地)从java生成POST http请求来上传文件

java - 如何将 30 分钟添加到 java.sql.Time 对象?

java - 有没有一种方法/解决方法来增加 java8 中的整数

forEach 循环期间的 java8 java.util.ConcurrentModificationException

java - 显示索引数组

java - 自动邮件发送失败

Java流。只有一次

Java 8 - 将 LocalDate 转换为 ZonedDateTime

java - 将未修改列表中的元素包含在带有 Streams 的二维列表中的修改列表中