Проверка не пустой, а не пустой строки в Java

Я пытаюсь проверить, не является ли строка Java не null, а не пустой, а не пробельной.

На мой взгляд, этот код должен был полностью соответствовать задаче.

public static boolean isEmpty(String s) {
    if ((s != null) && (s.trim().length() > 0))
        return false;
    else
        return true;
}

В соответствии с документацией String.trim() должно работать так:

Возвращает копию строки с опущенными пробелами в начале и конце.

Если этот объект String представляет собой пустую последовательность символов, или первый и последний символы последовательности символов, представленные этим объектом String, оба имеют коды больше, чем '\u0020' (символ пробела), то ссылка на это Возвращается объект String.

Однако, apache/commons/lang/StringUtils.java делает это несколько иначе.

public static boolean isBlank(String str) {
    int strLen;
    if (str == null || (strLen = str.length()) == 0) {
        return true;
    }
    for (int i = 0; i < strLen; i++) {
        if ((Character.isWhitespace(str.charAt(i)) == false)) {
            return false;
        }
    }
    return true;
}

В соответствии с документацией Character.isWhitespace():

Определяет, является ли указанный символ пробелом в соответствии с Java. Символ является символом пробела Java тогда и только тогда, когда он удовлетворяет одному из следующих критериев:

  • Это символ пробела в Юникоде (SPACE_SEPARATOR, LINE_SEPARATOR или PARAGRAPH_SEPARATOR), но также не является неразрывным пробелом ('\u00A0', '\u2007', '\u202F').
  • Это '\t', U + 0009 ГОРИЗОНТАЛЬНАЯ ТАБУЛЯЦИЯ.
  • Это '\n', U + 000A LINE FEED.
  • Это '\u000B', U + 000B ВЕРТИКАЛЬНАЯ ТАБУЛЯЦИЯ.
  • Это '\f', U + 000C FORM FEED.
  • Это '\r', U + 000D CARRIAGE RETURN.
  • Это '\u001C', U + 001C FILE SEPARATOR.
  • Это '\u001D', U + 001D GROUP SEPARATOR.
  • Это '\u001E', U + 001E RECORD SEPARATOR.
  • Это '\u001F', U + 001F UNIT SEPARATOR.

Если я не ошибаюсь - возможно, я просто не читаю его правильно - String.trim() должен отнять любой из символов, которые проверяются Character.isWhitespace(). Все они выглядят выше '\u0020'.

В этом случае более простая функция isEmpty, по-видимому, охватывает все сценарии, охватывающие более длинный isBlank.

  • Есть ли строка, которая приведет к тому, что isEmpty и isBlank будут вести себя по-другому в тестовом примере?
  • Предполагая, что их нет, есть ли какое-либо другое соображение, из-за которого я должен выбрать isBlank и не использовать isEmpty?

Для тех, кто заинтересован в фактическом выполнении теста, здесь приведены методы и модульные тесты.

public class StringUtil {

    public static boolean isEmpty(String s) {
        if ((s != null) && (s.trim().length() > 0))
            return false;
        else
            return true;
    }

    public static boolean isBlank(String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(str.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }
}

И модульные тесты

@Test
public void test() {

    String s = null; 
    assertTrue(StringUtil.isEmpty(s)) ;
    assertTrue(StringUtil.isBlank(s)) ;

    s = ""; 
    assertTrue(StringUtil.isEmpty(s)) ;
    assertTrue(StringUtil.isBlank(s)); 

    s = " "; 
    assertTrue(StringUtil.isEmpty(s)) ;
    assertTrue(StringUtil.isBlank(s)) ;

    s = "   "; 
    assertTrue(StringUtil.isEmpty(s)) ;
    assertTrue(StringUtil.isBlank(s)) ;

    s = "   a     "; 
    assertTrue(StringUtil.isEmpty(s)==false) ;    
    assertTrue(StringUtil.isBlank(s)==false) ;       

}

Обновление: Это была действительно интересная дискуссия, и именно поэтому я люблю Qaru и людей здесь. Кстати, вернувшись к вопросу, мы получили:

  • Программа, показывающая, что все символы будут вести себя по-другому. Код находится в https://ideone.com/ELY5Wv. Спасибо @Dukeling.
  • Связанная с производительностью причина выбора стандарта isBlank(). Спасибо @devconsole.
  • Полное описание @nhahtdh. Спасибо друг.

Ответ 1

Есть ли строка, в которой поведение isEmpty и isBlank будет вести себя по-другому в тестовом случае?

Обратите внимание, что Character.isWhitespace может распознавать символы Unicode и возвращать true для символов Unicode пробелов.

Определяет, является ли указанный символ пробелом в соответствии с Java. Символ является символом пробела Java тогда и только тогда, когда он удовлетворяет одному из следующих критериев:

  • Это символ пробела в Юникоде (SPACE_SEPARATOR, LINE_SEPARATOR или PARAGRAPH_SEPARATOR), но также не является неразрывным ('\u00A0', '\u2007', '\u202F').

  • [...]

С другой стороны, метод trim() обрезает все управляющие символы, чьи кодовые точки ниже U + 0020 и пробельный символ (U + 0020).

Следовательно, эти два метода будут вести себя по-разному в присутствии символа пробела Unicode. Например: "\u2008". Или, когда строка содержит управляющие символы, которые не учитывают пробелы методом Character.isWhitespace. Например: "\002".

Если вы должны были написать регулярное выражение для этого (что медленнее, чем выполнение цикла через строку и проверка):

  • isEmpty() будет эквивалентен .matches("[\\x00-\\x20]*")
  • isBlank() будет эквивалентен .matches("\\p{javaWhitespace}*")

(Методы isEmpty() и isBlank() допускают null ссылку на String, поэтому он не совсем эквивалентен решению регулярного выражения, но отбрасывает его в сторону, это эквивалентно).

Обратите внимание, что \p{javaWhitespace}, как следует из его имени, является синтаксисом, специфичным для Java, для доступа к классу символов, определенному методом Character.isWhitespace.

Предполагая, что их нет, есть ли какое-либо другое соображение, из-за которого я должен выбрать isBlank и не использовать isEmpty?

Это зависит. Тем не менее, я думаю, что объяснение в части выше должно быть достаточным для вас. Подводя итог разнице:

  • isEmpty() будет считать, что строка пуста, если она содержит только управляющие символы 1 ниже U + 0020 и символ пробела (U + 0020)

  • isBlank будет считать, что строка пуста, если она содержит только пробельные символы, определенные методом Character.isWhitespace, который включает символы пробела Unicode.

1 Существует также управляющий символ в U+007F DELETE, который не обрезается методом trim().

Ответ 2

Цель двух стандартных методов состоит в том, чтобы различать эти два случая:

org.apache.common.lang.StringUtils.isBlank(" ") (вернет true).

org.apache.common.lang.StringUtils.isEmpty(" ") (вернет false).

Ваша пользовательская реализация isEmpty() вернет значение true.


UPDATE:

  • org.apache.common.lang.StringUtils.isEmpty() используется для определения того, является ли строка длиной 0 или нулевой.

  • org.apache.common.lang.StringUtils.isBlank() делает шаг вперед. Он не только проверяет, является ли String длиной 0 или нулевым, но также проверяет, является ли это только строка пробела.

В вашем случае вы обрезаете строку в своем методе isEmpty. Единственное различие, которое может произойти сейчас, не может произойти (случай, который вы даете ему " "), потому что вы обрезка его (удаление конечного пробела - которое находится в этот случай похож на удаление всех пробелов).

Ответ 3

Я бы выбрал isBlank() над isEmpty(), потому что trim() создает новый объект String, который должен быть собран позже. isBlank(), с другой стороны, не создает никаких объектов.

Ответ 4

Вы можете взглянуть на JSR 303 Bean Validation, в котором содержатся Annotatinos @NotEmpty и @NotNull. Bean Валидация классная, потому что вы можете отделить вопросы проверки от первоначального намерения метода.

Ответ 5

Почему вы не можете просто использовать вложенный тернарный оператор для достижения этого. Пожалуйста, ознакомьтесь с примером кода public static void main(String[] args) { String s = null; String s1=""; String s2="hello"; System.out.println(" 1 "+check(s)); System.out.println(" 2 "+check(s1)); System.out.println(" 3 "+check(s2)); } public static boolean check(String data) { return (data==null?false:(data.isEmpty()?false:true)); }

и вывод следующий

1 false 2 false 3 true

здесь 1-й 2 сценария возвращает false (i.e null и empty), а третий сценарий возвращает true

Ответ 6

<% 
System.out.println(request.getParameter("userName")+"*");

if (request.getParameter("userName").trim().length() == 0 | request.getParameter("userName") == null) { %>
<jsp:forward page="HandleIt.jsp" />
<% }
 else { %>
Hello ${param.userName}
<%} %>

Ответ 7

Этот простой код будет достаточно:

public static boolean isNullOrEmpty(String str) {
    return str == null || str.trim().equals("");
}

И модульные тесты:

@Test
public void testIsNullOrEmpty() {
    assertEquals(true, AcdsUtils.isNullOrEmpty(""));
    assertEquals(true, AcdsUtils.isNullOrEmpty((String) null));
    assertEquals(false, AcdsUtils.isNullOrEmpty("lol    "));
    assertEquals(false, AcdsUtils.isNullOrEmpty("HallO"));
}

Ответ 8

С помощью Java 8 вы также можете использовать опцию "Дополнительно" с фильтрацией. Чтобы проверить, является ли строка пустой, код является чистым Java SE без дополнительной библиотеки. Следующий код иллюстрирует реализацию isBlank().

поведение String.trim()

!Optional.ofNullable(tocheck).filter(e -> e != null && e.trim().length() > 0).isPresent()

поведение StringUtils.isBlank()

Optional.ofNullable(toCheck)
    .filter(e -> 
        {
            int strLen;
            if (str == null || (strLen = str.length()) == 0) {
                return true;
            }
            for (int i = 0; i < strLen; i++) {
                if ((Character.isWhitespace(str.charAt(i)) == false)) {
                    return false;
                }
            }
            return true;

        })
    .isPresent()