Java의 두 객체를 가능한 null 값과 비교


189

Java에서 두 문자열이 동일한 지 비교하고 싶습니다. 둘 중 하나 또는 둘 다 일 수 있으므로 null간단히 호출 할 수 없습니다 .equals(). 가장 좋은 방법은 무엇입니까?

boolean compare(String str1, String str2) {
    ...
}

편집하다:

return ((str1 == str2) || (str1 != null && str1.equals(str2)));

답변:


173

이것은 Java 내부 코드가 다른 compare방법으로 사용하는 것입니다 .

public static boolean compare(String str1, String str2) {
    return (str1 == null ? str2 == null : str1.equals(str2));
}

3
왜 문자열 유형을 객체로 변경하지 않는 것이 더 일반적인가? 그리고 Java 7로 전환하면 얻을 수있는 것과 동일합니다.
Tom

3
제공 한 메소드를 포함하는 Java 클래스는 무엇입니까?
Volodymyr Levytskyi

30
야! true / false를 리턴하는 비교 메소드가 없어야합니다. 같음은 비교와 다릅니다. 비교는 정렬에 유용해야합니다. 당신은 반환해야합니다 <0, ==0또는 >0하나가 다른 것보다 낮은 / 강판 인 나타냅니다
coya가

10
Objects.equals(Object, Object)Mark Rotteveel이 그의 답변에서 지적한대로 사용 하는 것이 좋습니다 (공개하십시오)
Neuron

1
@Eric은 실제로 좋은 대답을하지 않습니다. 최선의 대답은 항상 존재했던 모든 자바 버전과 호환되는 코드 만 포함하고 있다는 것이 틀림 없다고 확신합니다
Neuron

317

Java 7부터는 정적 메소드 java.util.Objects.equals(Object, Object)를 사용하여 두 오브젝트에 대해 걱정하지 않고 두 오브젝트에 대해 동등 검사를 수행 할 수 있습니다 null.

두 객체가 모두 null반환 true되면 하나가 반환 null되고 다른 객체가 그렇지 않으면 반환 false됩니다. 그렇지 않으면 equals첫 번째 객체를 호출 한 결과를 두 번째 인자로 반환합니다 .


이 접근법은 프로그램의 런타임까지 타입 검사를 연기합니다. 두 가지 결과 : 런타임에 속도가 느려지고 실수로 다른 유형을 비교하려고하면 IDE에서 알려주지 않습니다.
averasko

10
@averasko 사용할 때 Object.equals(Object)컴파일 시간 유형 검사가 없습니다. 은 Objects.equals(Object, Object)매우 정상적인와 동일하게 작동 equals, 다시 추론 / IDE에 의해 검사, 그 규칙도 지원됩니다 추론이다 Objects.equals(Object, Object)(예를 들면하게 IntelliJ IDEA 2016.2 일반 등호와 객체의 하나 모두 같은 검사가 있습니다).
마크 Rotteveel

2
나는이 접근법을 좋아한다. 요즘에는 ApacheCommons 라이브러리를 포함시킬 필요가 없습니다.
Torsten Ojaperv

1
@SimonBaars 이것은 null 객체에서 함수를 실행하지 않습니다. 이것은 null 또는 객체에 대한 참조가 될 수있는 두 개의 인수를 전달하는 정적 메서드입니다.
Mark Rotteveel

8
이 답변은 허용되는 답변이어야합니다. 내가 쓰는 모든 단일 응용 프로그램에서 휠을 재발 명하고 싶지 않습니다
Neuron

45

이러한 경우 Apache Commons StringUtils # equals 를 사용하는 것이 좋으며 이미 널 문자열을 처리합니다. 코드 샘플 :

public boolean compare(String s1, String s2) {
    return StringUtils.equals(s1, s2);
}

라이브러리를 추가하지 않으려면 메소드 의 소스 코드 를 복사하여 StringUtils#equals필요할 때 적용하십시오.


29

API 19의 Objects.equals (str1, str2)를 사용할 수없는 안드로이드 사용자에게는 다음이 있습니다.

android.text.TextUtils.equals(str1, str2);

null 안전합니다. 안드로이드의 동일한 문자열이 안드로이드의 String Pooling 덕분에 "=="피연산자와 거의 항상 true를 비교 하고 길이 검사는 대부분의 불일치를 필터링하는 빠른 방법이기 때문에 더 비싼 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;
}

7

버전 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 안전 문자열 비교를 제공합니다.


6

사용 자바 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);
}

4

Apache Commons StringUtils 클래스의 equals (-,-) 및 equalsIgnoreCase (-,-) 메소드를 사용하여 두 문자열을 비교하십시오.

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

3

java.util.Objects다음과 같이 사용할 수 있습니다 .

public static boolean compare(String str1, String str2) {
    return Objects.equals(str1, str2);
}

2
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);
}

이것이 당신이 원하는 것입니까?


5
이 경우 false두 문자열 모두 null원하는 결과가 아닐 수 있습니다.
JScoobyCed

1
boolean compare(String str1, String str2) {
    if (str1 == null || str2 == null)
        return str1 == str2;

    return str1.equals(str2);
}

1
boolean compare(String str1, String str2) {
  return (str1==null || str2==null) ? str1 == str2 : str1.equals(str2);
}

0

그렇다면 "최상의 솔루션"이란 무엇입니까?

가장 읽기 쉬운 것을 의미한다면, 가능한 모든 솔루션은 숙련 된 Java 프로그래머와 거의 동일합니다. 하지만 가장 읽기 쉬운 IMO는

 public boolean compareStringsOrNulls(String str1, String str2) {
     // Implement it how you like
 }

다시 말해, (이상적으로) 인라인 될 수있는 간단한 메소드 안에 구현을 숨 깁니다.

(코드베이스에서 이미 사용중인 경우 타사 유틸리티 라이브러리에 "아웃소싱"할 수도 있습니다.)


가장 성능이 좋다면 다음을 수행하십시오.

  1. 가장 성능이 뛰어난 솔루션은 플랫폼과 상황에 따라 다릅니다.
  2. "문맥"문제 중 하나는 null인수 발생의 상대적 (동적) 빈도입니다 .
  3. 아마 의 차이는 전체 애플리케이션 성능에 차이를 만들 아마 너무 작기 때문에 ... 빠른 버전 문제, 그리고하지 않습니다
  4. 중요한 경우 플랫폼에서 가장 빠른 것을 파악하는 유일한 방법은 두 버전을 모두 사용하여 차이를 측정하는 것입니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.