Должен ли я использовать string.isEmpty () или «» .equals (string)?

171

Название в основном говорит обо всем. Я обычно тестирую это вместе с a string == null, так что я не очень обеспокоен нулевым тестом. Какой я должен использовать?

String s = /* whatever */;
...
if (s == null || "".equals(s))
{
    // handle some edge case here
}

или

if (s == null || s.isEmpty())
{
    // handle some edge case here
}

На этой ноте - isEmpty()даже делает что-нибудь кроме return this.equals("");или return this.length() == 0;?

Мэтт Болл
источник
26
Имейте в виду, что isEmpty()это только Java 6+.
ColinD
1
Вы можете создать вспомогательный метод Util.String.hasValue (String s), который проверяет наличие пустых значений, пустоты и пробелов для обработки всех случаев.
Cloudanger
5
@ColinD Вероятно, не проблема - J2SE 5.0 завершил период окончания срока службы некоторое время назад.
Том Хотин - тэклайн
1
Еще одна вещь, которую нужно учитывать, это "" .equals () принимает Object в качестве аргумента, поэтому вы не получите ошибку компилятора, если тип аргумента изменится со String на что-то другое, в лучшую или худшую сторону.
Пол Джексон

Ответы:

251

Основное преимущество "".equals(s)заключается в том, что вам не нужна проверка на нулевое значение ( equalsпроверит ее аргумент и вернет значение, falseесли оно равно нулю), которая, по-видимому, вас не беспокоит Если вы не беспокоитесь о том, sчтобы быть нулевым (или иным образом проверяете это), я бы определенно использовал s.isEmpty(); он показывает именно то, что вы проверяете, вас волнует, sявляется ли он пустым или нет , равно ли оно пустой строке

Майкл Мрозек
источник
29
Спасибо за объяснение. Теперь я знаю, почему стоит отдавать предпочтение "" .equals (str) перед str.equals ("")! Мне всегда было интересно, почему другие используют это так часто, но не принимали во внимание нулевые значения. Отлично :-)
Питер Випперманн
10
ИМХО проверка нуля все еще необходима в приведенных выше примерах, поскольку мы предполагаем, что условие должно быть истинным для значения null. s == ноль || "" .equals (s)
mkorpela
5
@ Master.Aurora нет, если getValue()возвращено значение NULL, вы получите toString()
исключение
12
@RenniePet Это не значит, что в этом есть какая-то магия. Если sноль, вы не можете вызывать методы для него - это ноль. ""никогда не будет нулевым, поэтому вы можете безопасно вызывать методы для него и equals()обрабатывать случай, когда его аргумент равен нулю
Майкл Мрозек
5
Замечание по производительности: isEmpty()проверяет внутреннюю длину частного массива, тогда как equals(Object anObject)делает гораздо больше (например, проверяет instanceof). По производительности, isEmpty()как правило, быстрее.
Тьюринг85
82

String.equals("")на самом деле немного медленнее, чем просто isEmpty()звонок. Строки хранят переменную count, инициализированную в конструкторе, поскольку строки являются неизменяемыми.

isEmpty() сравнивает переменную count с 0, в то время как equals проверит тип, длину строки, а затем перебирает строку для сравнения, если размеры совпадают.

Таким образом, чтобы ответить на ваш вопрос, на isEmpty()самом деле будет делать гораздо меньше! и это хорошо.

Дэвид Янг
источник
3
Я думаю, что в этом случае разница не применяется; никогда не будет итерации по строкам для сравнения, потому что размеры не будут совпадать (если строка на самом деле не пуста, а затем нет символов для итерации)
Майкл Мрозек
2
Верно, но при равенстве вы сначала выполняете проверку ссылок, чтобы увидеть, являются ли они одним и тем же объектом, затем instanceof, затем приведением к String, проверкой длины и, наконец, итерацией. Если бы обе строки были пустыми, то это была бы простая проверка ссылок.
Дэвид Янг
исходный код для класса String доступен java2s.com/Open-Source/Java-Document/6.0-JDK-Core/lang/java/…
Дэвид Янг
1
@ Дэвид мертвая ссылка; вот живой docjar.com/html/api/java/lang/String.java.html#1011
Мэтт Болл,
17

Одной вещью, которую вы могли бы рассмотреть помимо других упомянутых проблем, является то, что isEmpty()было введено в 1.6, поэтому, если вы используете его, вы не сможете запустить код на Java 1.5 или ниже.

Фабиан Стиг
источник
4
Это определенно не беспокоит меня.
Мэтт Болл
1
Также этот ответ сейчас 6 лет назад. Я надеюсь, что больше никто не будет использовать что-то древнее, такое как Java 1.5.
Миша Наследов
1
На самом деле есть много вещей, которые могут сломаться при обновлении Java-версии. Это менее критично для фонового приложения, работающего на большом сервере, но имеет значение для клиентских приложений. Графические библиотеки и стратегии сборки мусора часто подвергаются серьезному и незначительному обновлению Java. Кроме того, клиентское программное обеспечение может работать в различных операционных системах и иногда с ограниченной памятью, что означает, что у вас часто не будет бюджета / ресурсов для тестирования всего. - Да, у меня есть клиенты, которые все еще придерживаются Java 5 в 2017 году.
bvdb
15

Вы можете использовать Apache Commons StringUtils isEmpty () или isNotEmpty ().

Холодные бобы
источник
1
@ 2019, и нам все еще нужна сторонняя библиотека для этого: sigh:
Адам
2

Это не имеет большого значения. "".equals(str)более понятно на мой взгляд.

isEmpty()возвращается count == 0;

Кайлар
источник
47
Я бы сказал, str.isEmpty()что гораздо яснее, чем "".equals(str). Это читается как то, что вы проверяете. Вопрос мнения, хотя, я думаю.
ColinD
7
Я думаю, что некоторые люди предпочитают делать "" .equals (str), чтобы избежать NPE. Мне лично это не нравится, потому что я бы предпочел, чтобы строка не была нулевой.
CoolBeans
2

Я написал класс тестера, который может проверить производительность:

public class Tester
{
    public static void main(String[] args)
    {
        String text = "";

        int loopCount = 10000000;
        long startTime, endTime, duration1, duration2;

        startTime = System.nanoTime();
        for (int i = 0; i < loopCount; i++) {
            text.equals("");
        }
        endTime = System.nanoTime();
        duration1 = endTime - startTime;
        System.out.println(".equals(\"\") duration " +": \t" + duration1);

        startTime = System.nanoTime();
        for (int i = 0; i < loopCount; i++) {
            text.isEmpty();
        }
        endTime = System.nanoTime();
        duration2 = endTime - startTime;
        System.out.println(".isEmpty() duration "+": \t\t" + duration2);

        System.out.println("isEmpty() to equals(\"\") ratio: " + ((float)duration2 / (float)duration1));
    }
}

Я обнаружил, что использование .isEmpty () занимает примерно половину времени .equals ("").

conapart3
источник
Это недействительный микробенчмарк. Я настоятельно рекомендую использовать Caliper или аналогичный специализированный инструмент для тестирования. stackoverflow.com/q/504103/139010
Мэтт Болл
Спасибо за чаевые! Когда у меня будет немного свободного времени, я поэкспериментирую с некоторыми микро-бенчмаркингами и обновлю свой ответ.
conapart3