1
import java.util.*;

class TreeMapDemo
{
    public static void main(String args[])
    {
        Comparator <String> c1 = (str1, str2) -> 0;

        Comparator <String> c2 = (str1, str2) -> 1;

        TreeMap <String, Double> tm1 = new TreeMap(c1.thenComparing(c2));
        //Working fine

        TreeMap <String, Double> tm2 = new TreeMap(((str1, str2) -> 0).thenComparing((str1, str2) -> 1));
        //Error: Lambda expression not expected here
        //<none> can not be dereferenced
    }
}

私のクエリは次のとおりです。

もしも

c1 = (str1, str2) -> 0そしてc2 = (str1, str2) -> 1

それでなんで

c1.thenComparing(c2)正常に動作しており、

((str1, str2) -> 0).thenComparing((str1, str2) -> 1)ではありません?

4

3 に答える 3

7

Java は、ラムダ式のコンテキストに依存してその型を決定します。ラムダを変数に割り当てたり、メソッド引数として渡したりすると、十分なコンテキストが提供されますがthenComparing()、ラムダでメソッド (など) を呼び出すと、有用なコンテキストがまったく提供されません。

これはうまくいくはずです:

Comparator <String> c1 = (str1, str2) -> 0;
TreeMap <String, Double> tm2 = new TreeMap(c1.thenComparing((str1, str2) -> 1));

さらに詳細に:

ラムダ式は、何らかの機能インターフェースを実装するタイプのオブジェクトに評価され、Java は式が表示されるコンテキストに依存して、どの機能インターフェースであるかを判断します。2 番目のケースでは、コンストラクターの引数はラムダのコンテキストではありません。の呼び出しthenComparing()です。コンストラクターの引数は、そのメソッドの戻り値です。しかし、Java が何かを判断するには、Java が呼び出されているオブジェクトのタイプを知るthenComparing()必要があります。タイプはメソッドについて通知しますが、その逆ではありません。

Java は、引数の型からラムダの必要な型に逆方向に動作することはできません。これは、機能する関数インターフェイスがいくつでも存在する可能性があるためです。Java は、必要なインターフェースが標準ライブラリーにあると想定できません。

于 2015-09-13T23:09:53.510 に答える
4

ラムダ式は特定の型をターゲットにする必要があります。

c1 = (str1, str2) -> 0;

c1の型はわかっているのでOKです。

それ自体(str1, str2) -> 0はあいまいです。

例えば

BiFunction<String, String, Integer> x = (str1, str2) -> 0;

も理にかなっています。

これを具体的にするために、この例を見てください。

public interface Foo extends BiFunction<String, String, Integer> {
    default Comparator<String> thenComparing(Comparator<String> comparator) {
        return String.CASE_INSENSITIVE_ORDER;
    }
}

public static void main(String[] args) {
    Foo foo = (str1, str2) -> 0;        // overriding the sole method of BiFunction
    TreeMap<String, Double> treeMap = new TreeMap<>(foo.thenComparing((str1, str2) -> 1));
}

これは完全に正常にコンパイルされます。したがって、単に書くと

new TreeMap<>((str1, str2) -> 0).thenComparing((str1, str2) -> 1));

コンパイラ(str1, str2) -> 0が aFooか aかを知る方法はありませんComparator<String>。推論は、このように逆方向には機能しません。

于 2015-09-13T23:13:52.560 に答える
0

これは、Java の型推論の制限です。まず、raw-type を使用すると、コンパレータは a に解決され、Comparatornotに解決されますComparator<String>

TreeMap <String, Double> tm1 = new TreeMap((str1, str2) -> 0);// wouldn't work

どこ

TreeMap <String, Double> tm1 = new TreeMap<>((str1, str2) -> 0);// works

現在、型が推論される前に特定のメソッドを呼び出すことはできません。

Comparator<String> c1 = ((str1, str2) -> 0).thenComparing((str1, str2) -> 1); // doesn't work

コンパイラに追加のヘルプを提供しない限り

Comparator <String> c1 = ((Comparator<String>)((str1, str2) -> 0)).thenComparing((str1, str2) -> 1); // works
于 2015-09-13T23:46:02.953 に答える