Java: String: equalsIgnoreCase против переключения всего на верхний / нижний регистр - PullRequest
25 голосов
/ 15 декабря 2010

До меня дошло, что есть несколько способов сравнить строки в Java.

Я только что привык использовать equalsIgnoreCase, чтобы избежать проблем с чувствительными к регистру строками.

Другие же предпочитают передавать все в верхнем или нижнем регистре.

С того места, где я стою (даже если технически я сижу), я не вижу реальной разницы.

Кто-нибудь знает, лучше ли одна практика, чем другая?И если да, то почему?

Ответы [ 8 ]

49 голосов
/ 15 декабря 2010

Используйте equalsIgnoreCase, потому что это удобнее для чтения, чем преобразование обеих строк в верхний регистр перед сравнением. Читаемость превосходит микрооптимизацию .

Что читабельнее?

if (myString.toUpperCase().equals(myOtherString.toUpperCase())) {

или

if (myString.equalsIgnoreCase(myOtherString)) {

Думаю, мы все можем согласиться с тем, что equalsIgnoreCase более читабелен.

10 голосов
/ 18 апреля 2013

equalsIgnoreCase позволяет избежать проблем, касающихся различий, характерных для локали (например, в турецкой локали есть две разные заглавные буквы «i»). С другой стороны, в Картах используется только метод equals ().

3 голосов
/ 15 декабря 2010

Но проблема в последнем случае, когда вы делаете предположение , что прописные или строчные буквы пропущены, вы не можете слепо доверять вызывающему. Таким образом, вы должны включить оператор ASSERT в начале метода, чтобы убедиться, что ввод всегда соответствует ожидаемому.

2 голосов
/ 15 декабря 2010

Ни то, ни другое, они оба используются в разных сценариях.

Во многих случаях, когда вам нужно выполнить сравнение строк, есть возможность помассировать хотя бы одну из строк, чтобы было легче сравнивать, и в этих случаях вы увидите строки, преобразованные в конкретный случай, обрезанные и т. Д. Перед по сравнению.

Если, с другой стороны, вы просто хотите выполнить сравнение двух строк без учета регистра на лету, не стесняйтесь использовать equalsIgnoreCase, вот для чего он все-таки нужен. Однако я хотел бы предостеречь, что если вы видите много equalsIgnoreCase, это может быть запахом кода.

1 голос
/ 31 января 2018

equalsIgnoreCase документация в jdk 8

  • Сравнивает эту строку с другой строкой, игнорируя соображения регистра.Две строки считаются равными без учета регистра, если они имеют одинаковую длину, а соответствующие символы в двух строках равны без учета регистра.

    Два символа c1 и c2 считаются одним и тем же регистром игнорирования, если хотя бы одинверно следующее:

    • Два символа одинаковы (по сравнению с оператором ==)
    • Применение метода java.lang.CharactertoUpperCase (char) к каждому символу дает одинаковый результат
    • Применение метода java.lang.CharactertoLowerCase (char) к каждому символу приводит к одинаковому результату

Мои мысли:

Итак, используя equalsIgnoreCase, мы перебираемСтроки (только если их размеры одинаковы), сравнивающие каждый символ.В худшем случае производительность будет O (3cn), где n = размер ваших строк.Мы не будем использовать лишний пробел.

Используя toUpper (), затем сравнивая, если строки равны, вы ВСЕГДА просматриваете каждую строку один раз, конвертируя все строки в верхние, затем выполняете эквивалентность путем проверки ссылок (equals ()).Это тета (2n + c).Но помните, что когда вы делаете toUpperCase (), вам действительно нужно создать две новые строки, потому что строки в Java неизменны.

Поэтому я бы сказал, что equalsIgnoreCase более эффективен и проще для чтения.

Снова я бы рассмотрел вариант использования, потому что это будет то, к чему это сводится для меня.Подход toUpper может быть допустимым в некоторых случаях, но в 98% случаев я использую equalsIgnoreCase ().

1 голос
/ 02 ноября 2016

Зависит от варианта использования.

Если вы выполняете сравнение строк один к одному, equalsIgnoreCase, вероятно, быстрее, поскольку внутренне он просто прописывает каждый символ в верхнем регистре, поскольку он перебирает строки (код ниже из java.lang.String), которыйнемного быстрее, чем верхний или нижний регистр, перед тем как выполнить такое же сравнение:

if (ignoreCase) 
{
    // If characters don't match but case may be ignored,
    // try converting both characters to uppercase.
    // If the results match, then the comparison scan should
    // continue.
    char u1 = Character.toUpperCase(c1);
    char u2 = Character.toUpperCase(c2);
    if (u1 == u2) {
        continue;
    }
    // Unfortunately, conversion to uppercase does not work properly
    // for the Georgian alphabet, which has strange rules about case
    // conversion.  So we need to make one last check before
    // exiting.
    if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
        continue;
    }
}

Но когда возникает ситуация, когда вы хотите выполнить поиск в структуре данных, полной строк (особенно строк, которые находятся вUS Latin / ASCII) без учета регистра, будет быстрее обрезать / опустить строковые строки для проверки и поместить их в нечто вроде HashSet или HashMap.

Это лучше, чем вызывать equalsIgnoreCase длякаждый элемент списка, потому что небольшой выигрыш в производительности equalsIgnoreCase () отменяется тем фактом, что вы в основном делаете модифицированную версию contains () для массива, который равен O (n).С предварительно нормализованной строкой вы можете проверять весь список строк с помощью единственного вызова contains (), который выполняется в O (1).

1 голос
/ 27 июня 2012

Производительность в обоих случаях одинакова в соответствии с этим постом:

http://www.params.me/2011/03/stringtolowercasestringtouppercase-vs.html

Поэтому я бы решил, основываясь на читаемости кода, в некоторых случаях было бы лучше, если toLowerCase () было бы лучше, если бы я всегда передавал значение одному методу для создания объектов, в противном случае equalsIgnoreCase () имеет больше смысла.

0 голосов
/ 13 мая 2016

Когда я работаю только с английскими символами, я всегда запускаю toUpperCase() или toLowerCase() перед тем, как начать сравнение, если я звоню .equalsIgnoreCase() более одного раза или если я ' используя оператор switch. Таким образом, он выполняет операцию смены регистра только один раз, и поэтому он более эффективен.

Например, в заводской схеме:

public static SuperObject objectFactory(String objectName) {
    switch(objectName.toUpperCase()) {
        case "OBJECT1":
            return new SubObject1();
            break;
        case "OBJECT2":
            return new SubObject2();
            break;
        case "OBJECT3":
            return new SubObject3();
            break;
    }
    return null;
}

(Использование оператора switch немного быстрее, чем if..else if..else блоков для сравнения строк)

...