これは簡単な質問かもしれませんが、はっきりと理解したいと思います...
私はこのようなコードを持っています:
_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
を使用して順序が決定されます。」
自然な順序を明示的に設定するタイミングと方法、またはそれらが推論されるタイミングは混乱します。
パラメータを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
へのパラメーターが必要な理由です。これは、既存のコンパレーターの上に新しいコンパレーターを構築し、既存のコンパレーターが何であるかを伝えるためです。
では、パラメーターを省略した場合、なぜ自然な順序にならないのでしょうか。彼らがそれをそのように定義しなかったので。 nullsFirst
は javadoc で定義され、パラメーターを受け取ります。
_static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator)
_
デザイナーが望めば、パラメーターを取らないオーバーロードを追加できたと思います。
_static <T> Comparator<T> nullsFirst() // note: not legal
_
これは、nullsFirst(naturalOrder())
を使用する場合と同じです。しかし、そうではなかったので、そのように使用することはできません。
試してください:
final Comparator<Persona> comparator =
comparing(Persona::getName, nullsFirst(naturalOrder()));
名前と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]