web-dev-qa-db-ja.com

Java 8コンパレータnullsFirst naturalOrder confused

これは簡単な質問かもしれませんが、はっきりと理解したいと思います...

私はこのようなコードを持っています:

_public final class Persona
{
   private final int id;
   private final String name
   public Persona(final int id,final String name)
   {
       this.id = id;
       this.name = name;
   }
   public int getId(){return id;}    
   public String getName(){return name;}     
   @Override
   public String toString(){return "Persona{" + "id=" + id + ", name=" + name+'}';}    
 }
_

そして、私はこのコードをテストしています:

_import static Java.util.Comparator.*;
private void nullsFirstTesting()
{               
    final Comparator<Persona>comparator = comparing(Persona::getName,nullsFirst(naturalOrder()));
    final List<Persona>persons = Arrays.asList(new Persona(1,"Cristian"),new Persona(2,"Guadalupe"),new Persona(3,"Cristina"),new Persona(4,"Chinga"),new Persona(5,null));
    persons
            .stream()
            .sorted(comparator)
            .forEach(System.out::println);                           
}
_

次の結果が表示されます。

_Persona{id=5, name=null}
Persona{id=4, name=Chinga}
Persona{id=1, name=Cristian}
Persona{id=3, name=Cristina}
Persona{id=2, name=Guadalupe}
_

これらの結果は私には問題ありませんが、理解に問題があります。

new Persona(5,null)オブジェクトを無視してコンパレーターを渡すと、次のようになります。

_final Comparator<Persona>comparator = comparing(Persona::getName);
_

それは魅力のように働きます。私の並べ替えは_natural order of name property_です。 _name=null_を使用してオブジェクトを追加すると問題が発生します。このようにコンパレータが必要だと思いました。

_final Comparator<Persona>comparator = comparing(Persona::getName,nullsFirst());
_

私の考えは誤った:「OK、名前がnull以外の場合、前のコンパレータと同じように_natural order of name_で並べ替えられ、nullであれば最初にするただし、私のnull以外の名前は自然な順序でソートされます "。

しかし、正しいコードはこれです:

_final Comparator<Persona>comparator = comparing(Persona::getName,nullsFirst(naturalOrder()));
_

nullsFirstのパラメーターがわかりません。 _natural order of name_がnull値を明示的に[デフォルト]で処理することさえ考えていました。

しかし、ドキュメントは言う:

nullが非ヌルより小さいと見なすヌル対応のコンパレーターを返します。両方がnullの場合、それらは等しいと見なされます。両方がnullでない場合、指定されたComparatorを使用して順序が決定されます。指定されたコンパレータがnullの場合、返されるコンパレータはnull以外のすべての値が等しいと見なします。

この行:「両方がnullでない場合、指定されたComparatorを使用して順序が決定されます。」

自然な順序を明示的に設定するタイミングと方法、またはそれらが推論されるタイミングは混乱します。

14
chiperortiz

パラメータを1つだけ使用してcomparingを使用すると得られる「自然順序」コンパレータは、nullを処理しません。 (あなたがどこでそれをしたという考えを得たかはわかりません。)Comparableクラスの「自然順序」は、次のように使用されるcompareTo()メソッドによって定義されます。

_obj1.compareTo(obj2)
_

もちろん、これは_obj1_がnullの場合は機能しません。 Stringの場合、_obj2_がnullの場合も例外をスローします。

naturalOrder()メソッドは、2つのオブジェクトを比較するComparatorを返します。 javadoc は、nullを比較するときにこのコンパレータがNullPointerExceptionをスローすることを明示的に示しています。

nullsFirst()メソッド(およびnullsLast()も同様)は、基本的にComparatorを新しいComparatorに変換します。 nullを比較しようとすると例外をスローする可能性があるコンパレータを配置し、null引数を許可することを除いて同じように機能する新しいコンパレータを吐き出します。これがnullsFirstへのパラメーターが必要な理由です。これは、既存のコンパレーターの上に新しいコンパレーターを構築し、既存のコンパレーターが何であるかを伝えるためです。

では、パラメーターを省略した場合、なぜ自然な順序にならないのでしょうか。彼らがそれをそのように定義しなかったので。 nullsFirstjavadoc で定義され、パラメーターを受け取ります。

_static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator)
_

デザイナーが望めば、パラメーターを取らないオーバーロードを追加できたと思います。

_static <T> Comparator<T> nullsFirst()  // note: not legal
_

これは、nullsFirst(naturalOrder())を使用する場合と同じです。しかし、そうではなかったので、そのように使用することはできません。

27
ajb

試してください:

final Comparator<Persona> comparator =
  comparing(Persona::getName, nullsFirst(naturalOrder()));
23
zgmnkv

名前とIDが指定されたStudentを持つEmployeeのリストがあります。

 import Java.util.ArrayList;
import Java.util.Iterator;

import Java.util.List;
import Java.util.Comparator;

public class TestClass {

    public static void main(String[] args) {

        Student s1 = new Student("1","Nikhil");
        Student s2 = new Student("1","*");
        Student s3 = new Student("1",null);
        Student s11 = new Student("2","Nikhil");
        Student s12 = new Student("2","*");
        Student s13 = new Student("2",null);
        List<Student> list = new ArrayList<Student>();
        list.add(s1);
        list.add(s2);
        list.add(s3);
        list.add(s11);
        list.add(s12);
        list.add(s13);

        list.sort(Comparator.comparing(Student::getName,Comparator.nullsLast(Comparator.naturalOrder())));

        for (Iterator iterator = list.iterator(); iterator.hasNext();) {
            Student student = (Student) iterator.next();
            System.out.println(student);
        }


    }

}

次のように出力を生成します

Student [name=*, id=1]
Student [name=*, id=2]
Student [name=Nikhil, id=1]
Student [name=Nikhil, id=2]
Student [name=null, id=1]
Student [name=null, id=2]
4
Nikhil Kumar K