【问题标题】:How to declare generics for a method that returns a Function with generics如何为返回具有泛型的函数的方法声明泛型
【发布时间】:2018-01-16 13:54:33
【问题描述】:

我正在尝试在java中使用某种模式匹配,所以我想出了这个方法:

public Function<SimpleEntry<T, R>[], R> matchWith(T match){
        return functions ->  Stream.of(functions)
                .filter(entry -> entry.getKey().equals(match))
                .findFirst()
                .map(Entry::getValue)
                .orElse(null);
    }

这显然行不通,我找不到相关的问题。

想法是使用这样的方法:

final String value = matchWith(Type.B).apply(
        new SimpleEntry<>(Type.A, "Type A matches"),
        new SimpleEntry<>(Type.B, "Type B matches")
)

注意:我可能需要像 Function&lt;Pair&lt;T, R&gt;..., R&gt; 这样声明返回类型才能拥有它..我也不知道该怎么做。

那么如何为一个返回泛型函数的方法声明泛型呢?

【问题讨论】:

  • 泛型和数组不能混用,因为数组在运行时有不同的类型,但泛型类型只有在编译时才知道。请改用列表或集合。

标签: java generics functional-programming pattern-matching


【解决方案1】:

您必须提供自己的功能接口:

@FunctionalInterface
interface Matcher<T, R> {
    R apply(Entry<T, R>...entries);
}

private static <T, R> Matcher<T, R> matchWith(T match) {
    return functions ->  Stream.of(functions)
            .filter(entry -> entry.getKey().equals(match))
            .findFirst()
            .map(Entry::getValue)
            .orElse(null);
}

final String value = EnclosingClass.<Type, String>matchWith(Type.B).apply(
        new SimpleEntry<>(Type.A, "Type A matches"), // could also use Map.entry in Java 9
        new SimpleEntry<>(Type.B, "Type B matches")
);

此外,类型推断似乎不够聪明,无法确定它应该返回 Matcher&lt;Type, String&gt;,因此您必须手动提供类型参数(就像我在上面所做的那样,其中 EnclosingClass 是声明matchWith)。


可以说效果更好的是直接将条目列表传递给matchWith,这样就不需要接口,它还能够自动计算出正确的返回类型:

private static <T, R> R matchWith(T match, Entry<T, R>...enries) {
    return Stream.of(enries)
            .filter(entry -> entry.getKey().equals(match))
            .findFirst()
            .map(Entry::getValue)
            .orElse(null);
}

String value = matchWith(Type.B,
        new SimpleEntry<>(Type.A, "Type A matches"),
        new SimpleEntry<>(Type.B, "Type B matches")
);

有趣的是,将来可能会将您尝试创建的一些类似功能添加到 switch 语句中:JEP draft: Switch Expressions for the Java Language

【讨论】:

  • 我在这里看到了这个cr.openjdk.java.net/~briangoetz/amber/pattern-match.html,看起来也不错,我不知道是提案还是什么,但很有趣
  • @GabrielDeOliveiraRohden 是的,这是 JEP:openjdk.java.net/jeps/305 这是他们正在研究的东西(但没有做出任何承诺)。这是一个关于它的讨论:youtube.com/watch?v=n3_8YcYKScw
  • 在使用您编写的最后一个方法时,eclipse java 编译器(我不使用,但团队中的一些成员使用)似乎存在错误,编译器似乎丢失了正确的类型推断,错误在这里:bugs.eclipse.org/bugs/show_bug.cgi?id=508834
  • @GabrielDeOliveiraRohden 看起来它已在最新版本中修复。我自己正在使用 eclipse,它在 Oxygen.1a Release (4.7.1a) 和 Photon Milestone 4 (4.8.0M4) 中都可以正常工作。该错误本身也被标记为“已验证已修复”,因此我建议您的团队成员进行更新。
【解决方案2】:

不仅使用函数式编程,您还可以使用目标类型为方法参数和返回类型定义泛型。

public <T, R> Function<Pair<T, R>[], R> matchWith(T match) {}

参考:https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html

【讨论】:

  • oooh :o,谢谢,现在“初始”钻石对我来说“有意义”(我不知道我应该在那里声明泛型)
  • @GabrielDeOliveiraRohden 要对您的评论进行挑剔,“钻石运算符”仅指赋值右侧的类型推断版本 - 例如new ArrayList&lt;&gt;()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多