概要
Java 1.7より導入されたjava.util.Objectsクラスのおさらいメモです。
環境
- Windows 10 Professional
- Oracle JDK 1.8.0_144
- Oracle JDK 9.0.4
- Oracle JDK 10.0.1
参考
- [Oracle JDK 9ドキュメント] (https://docs.oracle.com/javase/jp/9/index.html)
- [Oracle JDK 10ドキュメント] (https://docs.oracle.com/javase/jp/10/index.html)
- [Objects (java SE 10 & JDK 10)] (https://docs.oracle.com/javase/jp/10/docs/api/java/util/Objects.html)
- [Apache Commons Lang ObjectUtils] (https://commons.apache.org/proper/commons-lang/javadocs/api-release/index.html)
Employeeクラス
この記事のサンプルコードでは下記のEmployeeクラスを使います。
public class Employee {
private Long id;
private String name;
public Employee(Long id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
// getter/setterは省略
}
[Objects] (https://docs.oracle.com/javase/jp/8/docs/api/java/util/Objects.html)
compare
Employee emp1 = new Employee(100L, "rubytomato");
Employee emp2 = new Employee(200L, "garnetpepper");
System.out.println(Objects.compare(emp1, emp2, Comparator.comparing(Employee::getId)));
// → -1
System.out.println(Objects.compare(emp1, emp1, Comparator.comparing(Employee::getId)));
// → 0
System.out.println(Objects.compare(emp2, emp1, Comparator.comparing(Employee::getId)));
// → 1
第1引数の比較対象がnullの場合、NullPointerExceptionが発生しますが、nullを許容したい場合はComparator#nullsFirst
(nullを最小値とする)またはComparator#nullsLast
(nullを最大値とする)を指定します。
Employee emp1 = new Employee(null, "rubytomato");
Employee emp2 = new Employee(200L, "garnetpepper");
System.out.println(Objects.compare(emp1, emp2,
Comparator.comparing(Employee::getId, Comparator.nullsLast(Comparator.naturalOrder()))));
// → 1
LocalDateTimeでの例です。
LocalDateTime d1 = LocalDateTime.of(2017, 8, 1, 0, 0, 0);
LocalDateTime d2 = LocalDateTime.of(2017, 8, 2, 0, 0, 0);
System.out.println(Objects.compare(d1, d2, LocalDateTime::compareTo));
// → -1
System.out.println(Objects.compare(d1, d1, LocalDateTime::compareTo));
// → 0
System.out.println(Objects.compare(d2, d1, LocalDateTime::compareTo));
// → 1
Integerでの例です。
Integer i1 = 100;
Integer i2 = 200;
System.out.println(Objects.compare(i1, i2, Integer::compareTo));
// → -1
System.out.println(Objects.compare(i1, i1, Integer::compareTo));
// → 0
System.out.println(Objects.compare(i2, i1, Integer::compareTo));
// → 1
// 自然順序付け
System.out.println(Objects.compare(i1, i2, Comparator.naturalOrder()));
// → -1
System.out.println(Objects.compare(i1, i1, Comparator.naturalOrder()));
// → 0
System.out.println(Objects.compare(i2, i1, Comparator.naturalOrder()));
// → 1
equals
Objects#equalsは第1引数のオブジェクトのequalsメソッドを使ってオブジェクト同士が等しいか判定を行います。どちらかのオブジェクトがnullの場合はfalseを返します。
第1引数のオブジェクトがnullの場合でもNullPointerExceptionは発生しません。
ただし、判定する両方のオブジェクトがnullの場合はtrueが返ります。
Employee emp1 = new Employee(100L, "rubytomato");
Employee emp1Null = null;
Employee emp2 = new Employee(200L, "garnetpepper");
Employee emp2Null = null;
Objects#equals
Objects#equalsを使った例です。nullの場合でもNullPointerExceptionはスローされません。
System.out.println(Objects.equals(emp1, emp2));
// → false
System.out.println(Objects.equals(emp1, emp2Null));
// → false
System.out.println(Objects.equals(emp1Null, emp2));
// NullPointerExceptionはスローされない
// → false
System.out.println(Objects.equals(emp1, emp1));
// → true
System.out.println(Objects.equals(emp1Null, emp2Null));
// null同士はtrueが返る
// → true
Object.equals
System.out.println(emp1.equals(emp2));
// → false
System.out.println(emp1.equals(emp2Null));
// → false
System.out.println(emp1Null.equals(emp2));
// → NullPointerExceptionがスローされる
System.out.println(emp1.equals(emp1));
// → true
System.out.println(emp1Null.equals(emp2Null));
// → NullPointerExceptionがスローされる
deepEquals
使いどころがよくわかっていないのですが、配列同士を比較する際に使用するようです。
なお配列同士の比較を行うと内部的にArrays.deepEquals
へ処理を委譲しています。
Employee emp1 = new Employee(100L, "rubytomato");
Employee emp2 = new Employee(200L, "garnetpepper");
Employee emp3 = new Employee(300L, "rubytomato");
Employee[] emps1 = new Employee[]{emp1, emp2, emp3};
Employee[] emps2 = new Employee[]{emp1, emp2, emp3};
Objects#deepEquals
System.out.println(Objects.deepEquals(emps1, emps2));
// → true
emps1 = null;
System.out.println(Objects.deepEquals(emps1, emps2));
// NullPointerExceptionはスローされません
// → false
Object.equals
System.out.println(emps1.equals(emps2));
// → false
emps1 = null;
System.out.println(emps1.equals(emps2));
// → NullPointerExceptionがスローされる
ちなみにコレクション同士だと両方ともtrueが返ります。
Employee emp1 = new Employee(100L, "rubytomato");
Employee emp2 = new Employee(200L, "garnetpepper");
Employee emp3 = new Employee(300L, "rubytomato");
List<Employee> emps1 = Arrays.asList(emp1, emp2, emp3);
List<Employee> emps2 = Arrays.asList(emp1, emp2, emp3);
System.out.println(Objects.deepEquals(emps1, emps2));
// → true
System.out.println(emps1.equals(emps2));
// → true
isNull
導入されたバージョン: 1.8
[JavaDoc] (https://docs.oracle.com/javase/jp/8/docs/api/java/util/Objects.html#isNull-java.lang.Object-)
APIの注:
このメソッドは、Predicate(filter(Objects::isNull))として使用するために存在します。
配列にnullが含まれているかチェックする例です
String[] params = {"p1", "p2", null, "p4", null, "p6"};
System.out.println(Arrays.stream(params).anyMatch(Objects::isNull));
// → true
System.out.println(Arrays.stream(params).filter(Objects::isNull).count());
// → 2
nonNull
導入されたバージョン: 1.8
[JavaDoc] (https://docs.oracle.com/javase/jp/8/docs/api/java/util/Objects.html#nonNull-java.lang.Object-)
APIの注:
このメソッドは、Predicate(filter(Objects::nonNull))として使用するために存在します。
配列からnullの要素を除外する例です
String[] params = {"p1", "p2", null, "p4", null, "p6"};
Arrays.stream(params).filter(Objects::nonNull).forEach(System.out::println);
// → p1
// → p2
// → p4
// → p6
requireNonNull
導入されたバージョン: 1.8
引数に取るオブジェクトのnullチェックを行います。
引数がnullでなければ引数をそのまま返し、nullであればNullPointerExceptionをスローします。
Employee emp = null;
Objects.requireNonNull(emp);
// → java.lang.NullPointerException
第2引数にNullPointerExceptionをスローするときのエラーメッセージを指定することができます。
Employee emp = null;
Objects.requireNonNull(emp , "employee must not be null");
// メッセージ付きで例外がスローされる
// → java.lang.NullPointerException: employee is null
NullPointerExceptionをスローする前に何か実行する必要がある場合は、第2引数にラムダ式を指定します。
Employee emp = null;
Objects.requireNonNull(emp, () -> {
// do something else.
return "employee must not be null";
});
// メッセージ付きで例外がスローされる
// → java.lang.NullPointerException: employee is null
toString
Objects#toStringを使用するとオブジェクトがnullかどうかを気にしなくてもよくなります。
Objects#toString
empがnullのときは"null"という文字列を返します。
Employee emp = new Employee(100L, "rubytomato");
System.out.println(Objects.toString(emp));
// → Employee{id=100, name='rubytomato'}
emp = null;
System.out.println(Objects.toString(emp));
// "null"という文字列が返ります
// → null
第2引数にnullの場合の代替文字列を指定することができます。
System.out.println(Objects.toString(emp, "employee is null"));
// → employee is null
Object.toString
Employee emp = new Employee(100L, "rubytomato");
System.out.println(emp.toString());
// → Employee{id=100, name='rubytomato'}
emp = null;
System.out.println(emp.toString());
// → java.lang.NullPointerExceptionをスロー
[Java 9で追加されたAPI] (https://docs.oracle.com/javase/jp/9/docs/api/java/util/Objects.html)
requireNonNullElse
Java 1.8で追加されたrequireNonNullにバリエーションが増えました。
public void demo(String obj1, String obj2) {
String result = Objects.requireNonNullElse(obj1, obj2);
System.out.println("result : " + result);
}
demo("obj1", "obj2");
// result : obj1
demo("obj1", null);
// result : obj1
demo(null, "obj2");
// result : obj2
// demo(null, null);
// java.lang.NullPointerException: defaultObj
requireNonNullElseGet
public void demo2(String obj, Supplier<String> supplier) {
String result = Objects.requireNonNullElseGet(obj, supplier);
System.out.println("result : " + result);
}
demo("obj1", () -> "obj2");
// result : obj1
demo(null, () -> "obj2");
// result : obj2
//demo(null, () -> null);
// java.lang.NullPointerException: supplier.get()
checkIndex
indexが、0(inclusive)からlength(exclusive)の範囲内かチェックします。
public void demo(int index, String[] fruits) {
int result = Objects.checkIndex(index, fruits.length);
System.out.println("result : " + result + " fruits : " + fruits[index]);
}
String[] fruits = {"apple", "banana", "cherry"};
demo(0, fruits);
// result : 0 fruits : apple
demo(1, fruits);
// result : 1 fruits : banana
demo(2, fruits);
// result : 2 fruits : cherry
demo(3, fruits);
// java.lang.IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
checkFromToIndex
from(inclusive)からto(exclusive)のサブレンジが、0(inclusive)からlength(exclusive)の範囲内かチェックします。
public void demo(int from, int to, String[] fruits) {
int result = Objects.checkFromToIndex(from, to, fruits.length);
System.out.println("result : " + result + " fruits : " + fruits[from]);
}
String[] fruits = {"apple", "banana", "cherry"};
demo(0, 1, fruits);
// result : 0 fruits : apple
demo(1, 2, fruits);
// result : 1 fruits : banana
demo(2, 3, fruits);
// result : 2 fruits : cherry
demo(2, 4, fruits);
// java.lang.IndexOutOfBoundsException: Range [2, 4) out-of-bounds for length 3
checkFromIndexSize
from(inclusive)からfrom + size(exclusive)のサブレンジが、0(inclusive)からlength(exclusive)の範囲内かチェックします。
public void demo(int index, int size, String[] fruits) {
int result = Objects.checkFromIndexSize(index, size, fruits.length);
System.out.println("result : " + result + " fruits : " + fruits[index]);
}
String[] fruits = {"apple", "banana", "cherry"};
demo(0, 1, fruits);
// result : 0 fruits : apple
demo(1, 2, fruits);
// result : 1 fruits : banana
demo(2, 3, fruits);
// java.lang.IndexOutOfBoundsException: Range [2, 2 + 3) out-of-bounds for length 3
Preconditions
これらのstaticメソッドは、Preconditionsクラスへ処理を委譲しています。
Utility methods to check if state or arguments are correct.
[Java 10で追加されたAPI] (https://docs.oracle.com/javase/jp/10/docs/api/java/util/Objects.html)
追加されたAPIはありません。
[Java 11で追加されたAPI] (https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Objects.html)
追加されたAPIはありません。
[Java 12で追加されたAPI] (https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/Objects.html)
追加されたAPIはありません。
[Java 13で追加されたAPI] (https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/util/Objects.html)
追加されたAPIはありません。
[Java 14で追加されたAPI] (https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/Objects.html)
追加されたAPIはありません。
その他のおさらいメモ
- [Java NIO2のおさらいメモ] (https://qiita.com/rubytomato@github/items/6880eab7d9c76524d112)
- 2017年08月15日
- [Java Collections Frameworkのおさらいメモ] (https://qiita.com/rubytomato@github/items/554095ae21a2c36f131a)
- 2017年08月30日
- [パッケージ java.time.temporal のおさらいメモ] (https://qiita.com/rubytomato@github/items/e9325dd46aa11f1b8e2e)
- 2018年01月30日
- [クラス java.util.Optionalのおさらいメモ] (https://qiita.com/rubytomato@github/items/92ac7944c830e54aa03d)
- 2018年03月22日