web-dev-qa-db-ja.com

Java 8 Lambda:コンパレーター

Lambdaでリストをソートしたい:

List<Message> messagesByDeviceType = new ArrayList<Message>();      
messagesByDeviceType.sort((Message o1, Message o2)->o1.getTime()-o2.getTime());

しかし、私はこのコンパイルエラーが発生しました:

 Multiple markers at this line
    - Type mismatch: cannot convert from long to int
    - The method sort(Comparator<? super Message>) in the type List<Message> is not applicable for the arguments ((Message o1, Message o2) 
     -> {})
40

Comparator#compareTointを返します。 getTimeは明らかにlongです。

このように書かれた方がいいでしょう:

 .sort(Comparator.comparingLong(Message::getTime))
77
Eugene

Comparatorcompare()メソッドはintを返す必要があり、あなたのメソッドはlongを返しているようです。

次のように変更できます。

(Message o1, Message o2)->Long.compare(o1.getTime(),o2.getTime())

これは、(エラーメッセージに基づいて)o1.getTime()longを返すことを前提としています。

21
Eran

ラムダ

ラムダは、やや面倒な匿名クラスの省略形と見なすことができます。

Java8バージョン:

Collections.sort(list, (o1, o2) -> o1.getTime() - o2.getTime());

Java8以前のバージョン:

    Collections.sort(list, new Comparator<Message>() {
        @Override
        public int compare(Message o1, Message o2) {
            return o1.getTime() - o2.getTime();
        }
    }); 

そのため、正しいラムダの書き方が混乱するたびに、事前のラムダバージョンを書き、それがどのように間違っているかを確認することができます。

応用

特定の問題では、compareintを返すことがわかります。ここで、getTimeはエラーの原因であるlongを返します。

次のような他の回答方法としていずれかの方法を使用できます。

Long.compare(o1.getTime(),o2.getTime())

通知

  • Comparator-を使用しないでください。オーバーフローにより、場合によってはプログラムがクラッシュする可能性があります。
19
Tony

コンパレータ

コンパレータインターフェイスを使用して、同種および異種の要素をデフォルトのカスタマイズされた並べ替え順序で並べ替えます。

int compare(T o1, T o2);

順序付けには2つの引数が必要です。を返します

    negative integer(-1) « if first argument is less than the other
    zero             (0) « if both are equal
    positive integer (1) « if first greater than the second.

匿名クラス以前のバージョンのJava 8 内部クラスを使用します。

無名クラスは、finalまたは実質的にfinalとして宣言されていない、そのスコープ内のローカル変数にアクセスできません。

Comparator<Employee> timeCompare = new Comparator<Employee>() {
    @Override public int compare(Employee e1, Employee e2) {
        return e1.getCreationTime().compareTo( e2.getCreationTime() );
    }
};

Java 8 Lambda Expressions uing compare method

ラムダ式はメソッドに似ています:正式なパラメーターのリストと、それらのパラメーターで表現された本体(式またはブロック)を提供します。

LambdaExpressionLambdaParameters -> LambdaBody

使用されているがラムダ式で宣言されていない任意のローカル変数、仮パラメーター、または例外パラメーターは、finalとして宣言されるか、実質的にfinalである必要があります。そうでない場合、使用しようとするとコンパイル時エラーが発生します。

Comparator<Employee> functional_semantics = (e1, e2) -> {
   return e1.getCreationTime().compareTo( e2.getCreationTime() );
};

Lambdaサポートを使用した基本的な並べ替え

Comparator<Employee> timeCompareLambda = (o1, o2) -> (int) ( o1.getCreationTime() - o2.getCreationTime());
Collections.sort(Java8, timeCompareLambda );

Extracted Keyおよび Comparing method抽出されたキーで比較するコンパレータ。 ::キーワードを使用して参照を渡します。

static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor)
ToLongFunction<Employee> keyExtracor = Employee::getCreationTime;
Comparator<Employee> byTime = Comparator.comparingLong( Employee::getCreationTime );

サンプルテストコード:

public class Lambda_Long_Comparator {
    public static void main(String[] args) {

        List<Employee> Java7 = getEmployees();

        // Sort with Inner Class
        Comparator<Employee> timeCompare = new Comparator<Employee>() {
            @Override public int compare(Employee e1, Employee e2) {
                return e1.getCreationTime().compareTo( e2.getCreationTime() );
            }
        };

        // Collections.sort(list); // Defaults to Comparable<T> « @compareTo(o1)
        Collections.sort(Java7, timeCompare); // Comparator<T> « @compare (o1,o2)
        System.out.println("Java < 8 \n"+ Java7);

        List<Employee> Java8 = getEmployees();
        Collections.sort(Java8, Comparator
                .comparing( Employee::getCreationTime )
                .thenComparing( Employee::getName ));
        //Java8.forEach((emp)-> System.out.println(emp));
        System.out.println("Java 8 \n"+Java8);
    }

    static List<Employee> getEmployees() {
        Date date = Calendar.getInstance().getTime();
        List<Employee> list = new ArrayList<Employee>();
        list.add( new Employee(4, "Yash", date.getTime()+7));
        list.add( new Employee(2, "Raju", date.getTime()+1));
        list.add( new Employee(4, "Yas", date.getTime()));
        list.add( new Employee(7, "Sam", date.getTime()-4));
        list.add( new Employee(8, "John", date.getTime()));
        return list;
    }
}
class Employee implements Comparable<Employee> {
    Integer id;
    String name;
    Long creationTime;

    public Employee(Integer id, String name, Long creationTime) {
        this.id = id;
        this.name = name;
        this.creationTime = creationTime;
    }

    @Override public int compareTo(Employee e) {
        return this.id.compareTo(e.id);
    }

    @Override public String toString() {
        return "\n["+this.id+","+this.name+","+this.creationTime+"]";
    }

    // Other getter and setter methods
}

これらの投稿もご覧ください。

7
Yash

変更する必要があります

 messagesByDeviceType.sort(
     (Message o1, Message o2) -> o1.getTime() - o2.getTime()
 );

messagesByDeviceType.sort(
    Comparator.comparing((Message m) -> m.getTime())
);

これは、値がComparableであり、自然なソート順を提供することを前提としています。

さらにフィールドを追加する場合は、それらをコンパレータにチェーンできます。例えば最初に時間でソートし、次に送信者でソートします。

messagesByDeviceType.sort(
    Comparator
        .comparing((Message m) -> m.getTime())
        .thenComparing((m)     -> m.getSender())
);

Comparatorの順序を逆にするには、reveresed()メソッドをそれにチェーンします。最初に時間の降順、次に送信者の順に並べ替えます:

messagesByDeviceType.sort(
    Comparator
        .comparing((Message m) -> m.getTime())
        .reversed()
        .thenComparing((m)     -> m.getSender())
);

https://docs.Oracle.com/javase/8/docs/api/Java/util/Comparator.html も参照してください

3
isapir

compare()メソッドはintを返す必要があり、あなたのメソッドはlongを返しているようです。

これを次のように変更できます。

Long.compare(o1.getTime(),o2.getTime())

以下のビデオでラムダコンパレーターについて詳しく説明します リンク

0
Raj