どちらかまたは両方がnull
になる可能性がある場合、Javaで2つの文字列が等しいかどうかを比較したいので、単純に.equals()
を呼び出すことはできません。最善の方法は何ですか?
boolean compare(String str1, String str2) {
...
}
編集:
return ((str1 == str2) || (str1 != null && str1.equals(str2)));
これはJava内部コードが使用するものです(他のcompare
メソッドで):
public static boolean compare(String str1, String str2) {
return (str1 == null ? str2 == null : str1.equals(str2));
}
Java 7以降では、静的メソッド Objects.equals(Object, Object)
を使用して、2つのオブジェクトがnull
であることを気にせずに等しいチェックを実行できます。
両方のオブジェクトがnull
である場合は、true
を返します。一方がnull
であり、もう一方がそうでない場合は、false
を返します。それ以外の場合、最初のオブジェクトで equals
を呼び出した結果を返します。
これらの場合、 Apache CommonsStringUtils#equals を使用する方が良いでしょう。すでにnull文字列を処理しています。コードサンプル:
public boolean compare(String s1, String s2) {
return StringUtils.equals(s1, s2);
}
ライブラリを追加したくない場合は、StringUtils#equals
メソッドの ソースコード をコピーして、必要なときに適用してください。
API 19のObjects.equals(str1、str2)を使用できないAndroidの場合、次のようになります。
Android.text.TextUtils.equals(str1, str2);
Nullセーフです。 Android上の同一の文字列は、ほとんどの場合、 Androidの文字列プーリング のおかげで、「==」オペランドと真を比較するため、より高価なstring.equals()メソッドを使用する必要はほとんどありません。長さチェックは、ほとんどの不一致を迅速に除外する方法です。
ソースコード:
/**
* Returns true if a and b are equal, including if they are both null.
* <p><i>Note: In platform versions 1.1 and earlier, this method only worked well if
* both the arguments were instances of String.</i></p>
* @param a first CharSequence to check
* @param b second CharSequence to check
* @return true if a and b are equal
*/
public static boolean equals(CharSequence a, CharSequence b) {
if (a == b) return true;
int length;
if (a != null && b != null && (length = a.length()) == b.length()) {
if (a instanceof String && b instanceof String) {
return a.equals(b);
} else {
for (int i = 0; i < length; i++) {
if (a.charAt(i) != b.charAt(i)) return false;
}
return true;
}
}
return false;
}
バージョン3.5以降、Apache Commons StringUtilsには次のメソッドがあります。
static int compare(String str1, String str2)
static int compare(String str1, String str2, boolean nullIsLess)
static int compareIgnoreCase(String str1, String str2)
static int compareIgnoreCase(String str1, String str2, boolean nullIsLess)
これらは、nullセーフな文字列比較を提供します。
Apache Commons StringUtilsクラスのequals(-、-)およびequalsIgnoreCase(-、-)メソッドを使用して2つの文字列を比較します。
StringUtils.equals(-、-):
StringUtils.equals(null, null) = true
StringUtils.equals(null, "abc") = false
StringUtils.equals("abc", null) = false
StringUtils.equals("abc", "abc") = true
StringUtils.equals("abc", "ABC") = false
StringUtils.equalsIgnoreCase(-、-):
StringUtils.equalsIgnoreCase(null, null) = true
StringUtils.equalsIgnoreCase(null, "abc") = false
StringUtils.equalsIgnoreCase("xyz", null) = false
StringUtils.equalsIgnoreCase("xyz", "xyz") = true
StringUtils.equalsIgnoreCase("xyz", "XYZ") = true
Java 8:を使用する
private static Comparator<String> nullSafeStringComparator = Comparator
.nullsFirst(String::compareToIgnoreCase);
private static Comparator<Metadata> metadataComparator = Comparator
.comparing(Metadata::getName, nullSafeStringComparator)
.thenComparing(Metadata::getValue, nullSafeStringComparator);
public int compareTo(Metadata that) {
return metadataComparator.compare(this, that);
}
boolean compare(String str1, String str2) {
if(str1==null || str2==null) {
//return false; if you assume null not equal to null
return str1==str2;
}
return str1.equals(str2);
}
これはあなたが望んだものですか?
Java.util.Objects
は次のように使用できます。
public static boolean compare(String str1, String str2) {
return Objects.equals(str1, str2);
}
boolean compare(String str1, String str2) {
if (str1 == null || str2 == null)
return str1 == str2;
return str1.equals(str2);
}
boolean compare(String str1, String str2) {
return (str1==null || str2==null) ? str1 == str2 : str1.equals(str2);
}
OK、それでは「最良の解決策」とはどういう意味ですか?
最も読みやすいという意味であれば、可能なすべてのソリューションは、経験豊富なJavaプログラマーにとってほぼ同等です。しかし、最も読みやすいIMOはこれです
public boolean compareStringsOrNulls(String str1, String str2) {
// Implement it how you like
}
つまり、(理想的には)インライン化できる単純なメソッド内の実装を非表示にします。
(コードベースで既に使用している場合は、サードパーティのユーティリティライブラリに「アウトソース」することもできます。)
パフォーマンスが最も高い場合、次のとおりです。
null
引数の相対(動的)発生頻度です。