2016-03-28 9 views
7

の間であいまいです:メソッドの参照は、以下に減少テストケースを検討機能とBiFunctionパラメータ型

OracleのJDK 8u40からのjavacでコンパイル
import java.util.AbstractList; 
import java.util.Collection; 
import java.util.Iterator; 
import java.util.List; 
import java.util.function.BiFunction; 
import java.util.function.Function; 
public final class Example { 
    static class PairList<A, B> { 
     public void replaceAllSecond(Function<? super B, ? extends B> secondFunction) {} 
     public void replaceAllSecond(BiFunction<? super A, ? super B, ? extends B> secondFunction) {} 
    } 

    static class ImmutableList<E> extends AbstractList<E> { 
     public static <E> ImmutableList<E> copyOf(Iterable<? extends E> elements) {return null;} 
     public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) {return null;} 
     public static <E> ImmutableList<E> copyOf(Iterator<? extends E> elements) {return null;} 
     public static <E> ImmutableList<E> copyOf(E[] elements) {return null;} 

     @Override public E get(int index) {return null;} 
     @Override public int size() {return 0;} 
    } 

    public static void foo() { 
     PairList<Integer, List<Integer>> list = new PairList<>(); 
     list.replaceAllSecond(x -> ImmutableList.copyOf(x)); //accepted 
     list.replaceAllSecond(ImmutableList::copyOf); //error 
    } 
} 

を、ラムダと​​への呼び出しは受け入れられますが、メソッド参照を渡すコールが次のエラーで拒否されています

Example.java:26: error: reference to replaceAllSecond is ambiguous 
       list.replaceAllSecond(ImmutableList::copyOf); //error 
        ^
    both method replaceAllSecond(Function<? super B,? extends B>) in PairList and method replaceAllSecond(BiFunction<? super A,? super B,? extends B>) in PairList match 
    where B,A are type-variables: 
    B extends Object declared in class PairList 
    A extends Object declared in class PairList 
1 error 

BiFunctionを取って過負荷がここに潜在的に適用される理由を私は理解していません。 JLS 15.12.2.1から(省略いくつかの弾丸を持つ):

A member method is potentially applicable to a method invocation if and only if all of the following are true:

  • If the member is a fixed arity method with arity n, the arity of the method invocation is equal to n, and for all i (1 ≤ i ≤ n), the i'th argument of the method invocation is potentially compatible, as defined below, with the type of the i'th parameter of the method.

An expression is potentially compatible with a target type according to the following rules:

  • A method reference expression (§15.13) is potentially compatible with a functional interface type if, where the type's function type arity is n, there exists at least one potentially applicable method for the method reference expression with arity n (§15.13.1), and one of the following is true:

    • The method reference expression has the form ReferenceType :: [TypeArguments] Identifier and at least one potentially applicable method is i) static and supports arity n, or ii) not static and supports arity n-1.

私はそれを解釈するように、BiFunctionの関数型アリティは2であるが、メソッド参照が潜在的に互換性がないのでcopyOfのすべてのオーバーロードは、静的であり、アリティ1を有しますBiFunctionパラメータを使用しているため、replaceAllSecond(BiFunction)は適用されません。

私はJLSを誤解していますか、これはjavacのバグですか? JDK-8026231は仕様を実装するためのjavacの更新について説明していますが、そのバグはJava 8の最初のリリース(2014年3月)前の2013年に解決されました。

答えて

5

あなたの例では、さらに次のように減少させることができます。このコードは、Java-9アーリーアクセス(9ea57のようにもかなり古いもの)を構築すると罰金コンパイルするため

import java.util.Collection; 
import java.util.List; 
import java.util.function.BiFunction; 
import java.util.function.Function; 

public final class Example { 
    static class PairList<A, B> { 
     public void replaceAllSecond(Function<? super B, ? extends B> secondFunction) {} 
     public void replaceAllSecond(BiFunction<? super A, ? super B, ? extends B> secondFunction) {} 
    } 

    public static <E> List<E> copyOf(Iterable<? extends E> elements) {return null;} 
    public static <E> List<E> copyOf(Collection<? extends E> elements) {return null;} 

    public static void foo() { 
     PairList<Integer, List<Integer>> list = new PairList<>(); 
     list.replaceAllSecond(x -> Example.copyOf(x)); //accepted 
     list.replaceAllSecond(Example::copyOf); //error 
    } 
} 

は、私は、これはjavacの問題であると仮定し、 Java-8では(最新のアップデートでも)失敗します。

+1

面白いことに、競合する「copyOf」オーバーロードが存在するため、エラーが発生します。もし2つのうちの1つしかなければ、それはコンパイルされます。さらにそれを減らすためにありがとう。私は「大丈夫、それはJLSを通って作業した後、SOの質問のための十分な研究」のようなものでした。 :) –

+1

新しいAPIを設計するときに一般的に@JeffreyBosboomこれは、メソッド参照とあいまいさを引き起こす可能性があるため、受け入れられた関数型のインターフェイスでのみ異なるオーバーロードを作成しないようにします(この型のアリティが異なる場合でも)。この不具合がなくても、次のGuavaバージョンで 'ImmutableList.copyOf(Whatever foo、Whatever bar)'が追加されたとしましょう(これは道徳的にこれを行う権利があります)。これは、あなたの 'PairList.replaceAllSecond (ImmutableList :: copyOf) 'と呼びます。そのような場合、私は異なるメソッド名を使用します。 –

関連する問題