Использование StringUtils.isEmpty без потери предупреждений компилятора о нулевых указателях

Вместо обычного if (myString == null || myString.equals("")) я предпочитаю использовать класс org.apache.commons.lang.StringUtils и делать if (StringUtils.isEmpty(myString)).

Однако это — по крайней мере, так, как я это делаю — имеет огромный недостаток: потому что FindBugs — или механизм предупреждения компилятора, f. бывший. из Eclipse - больше не будет видеть явную проверку на ноль, он больше не будет рассматривать myString как потенциально нулевой, поэтому он больше не будет выдавать предупреждения о потенциальных (или уверенных) нулевых указателях на него, и эти предупреждения чрезвычайно полезны в моем случае. Посмотреть.

Пример (ДОБАВЛЕНО):

import org.apache.commons.lang.StringUtils;

public class TestWarning
{
    void testWarning(String myString)
    {
        //if (myString == null || myString.equals("")) // With this, the last line shows the warning.
        if (StringUtils.isEmpty(myString)) // With this, no warning.
        {
            // Anything.
        }
        int x = myString.length(); // Warning is here: "Potential null pointer access: The variable myString may be null at this location"
    }
}

Поэтому я просто пытаюсь убедиться, что нет никакого способа устранить или свести к минимуму этот недостаток, чтобы можно было использовать StringUtils.isEmpty и по-прежнему получать предупреждения об нулевом указателе. Может быть, какую-то аннотацию, например @Nullcheck, добавить к методу isEmpty или что-то еще?

ДОБАВЛЕНО: Например, было бы возможно создать пользовательскую аннотацию, например @Nullcheck, добавить ее к аргументу isEmpty, например public static boolean isEmpty(@Nullcheck String str), просто чтобы указать, что метод выполняет нулевую проверку этого аргумента, и сделать так, чтобы механизм предупреждения компилятора или FindBugs обрабатывают if (StringUtils.isEmpty(myString)) так же, как явную проверку на ноль?


person SantiBailors    schedule 05.06.2014    source источник
comment
StringUtils.isEmpty() обрабатывает нуль, так почему же FindBugs должен выдавать возможное нулевое предупреждение? Я не понимаю вашу проблему здесь ...   -  person WarrenFaith    schedule 05.06.2014
comment
Какое предупреждение о нулевых указателях вас беспокоит? Можете ли вы объяснить это немного больше? Вы хотите получить предупреждение о том, что он может выдать NPE при попытке проверить что-то вроде этого: StringUtils.isEmpty(null)? Потому что в этом случае вам не нужно беспокоиться об этом, так как StringUtils.isEmpty() обрабатывает null самостоятельно, и поэтому FindBugs не будет беспокоить вас ненужными предупреждениями. Читайте документы для получения дополнительной информации.   -  person RainMaker    schedule 05.06.2014
comment
Меня не беспокоит нулевой указатель внутри isEmpty; просто если я делаю if (myString == null) и несколько строк ниже - вне этого if - я делаю например. myString.length() Я получу предупреждение компилятора о потенциальном нулевом указателе на myString.length(). Я бы не получил это предупреждение, если бы вместо if (myString == null) я сделал if (StringUtils.isEmpty(myString))   -  person SantiBailors    schedule 05.06.2014
comment
Компилятор и даже такие инструменты, как FindBugs, имеют ограничения, и вы только что их нашли. По сути, именно поэтому вам, как программисту, нужно использовать мозг, который у вас есть :)   -  person WarrenFaith    schedule 05.06.2014
comment
Верно. Но это применимо ко многим конструкциям и инструментам, предназначенным для минимизации ошибок — случайных или по незнанию — и мне это нравится ;)   -  person SantiBailors    schedule 05.06.2014
comment
Пожалуйста, опубликуйте рабочий пример и отметьте строку, где вы ожидаете предупреждение. Похоже, вы нашли ошибку, если использование переменной находится за пределами блока if. Лучше опубликовать реальный код, чем описывать его прозой.   -  person David Harkness    schedule 06.06.2014
comment
Я не думаю, что это ошибка, просто с if (myString == null) компилятор или FindBugs понимают, что myString может быть нулевым, а с if (StringUtils.isEmpty(myString)) они этого не понимают, что я считаю достаточно справедливым. Однако я добавил пример к моему вопросу.   -  person SantiBailors    schedule 06.06.2014
comment
Почему бы вам просто не аннотировать аргумент myString с помощью JSR-305 @Nullable (code.google.com/p/jsr-305/source/browse/trunk/ri/src/main/java/ ) или аннотацию FindBugs @CheckForNull?   -  person JB Nizet    schedule 06.06.2014
comment
@JB Nizet: Потому что я не знал ни об одном из них :) Большое спасибо, я попробую и опубликую результат. Если это сработает, я думаю, что ваш ответ должен быть принятым.   -  person SantiBailors    schedule 06.06.2014
comment
Я загрузил JSR-305 и попробовал его @Nullable, но безрезультатно. Я использовал его в соответствии с одним из их примеров. import javax.annotation.Nullable; public class TestWarning { ` void testWarning(String myString) {` ` if (isEmpty(myString)) { /* Что угодно. */ }` ` int x = myString.length(); // Предупреждение об ошибке не отображается.` ` }` ` public static boolean isEmpty(@Nullable String str) {` ` return str == null || str.length() == 0;` ` }` }   -  person SantiBailors    schedule 06.06.2014
comment
И извините за беспорядочный код выше, но я не могу найти способы вставить читаемый фрагмент кода в комментарий. Я прочитал справку и попробовал несколько способов, после чего истекли 5 минут. Я не уверен, как можно публиковать код, кроме как с помощью ответа на ваш вопрос, который бесполезен.   -  person SantiBailors    schedule 06.06.2014


Ответы (3)


Если вы аннотируете myString с помощью @Nullable, т.е.

void testWarning(@Nullable String myString)

тогда, по крайней мере, eclipse сообщит о предупреждении, когда вы разыменуете его.

Я согласен, что FindBugs также должен предупреждать об этом, но я не могу заставить его сделать это.

person TimK    schedule 16.06.2014
comment
Это то, что я пробовал на примере в 10-м комментарии к моему вопросу; это не сработало в Eclipse, но, возможно, это не тот код, который вы имеете в виду. Код, который я разместил там, на самом деле не очень читабелен, поэтому я пытаюсь еще раз здесь. Должна быть возможность вставить его в IDE и отформатировать код. import javax.annotation.Nullable; public class TestWarning { void testWarning(String myString) { if (isEmpty(myString)) { /* Anything. */ } int x = myString.length(); /* No nullness warning */ } public static boolean isEmpty(@Nullable String str) { return str == null || str.length() == 0; }} - person SantiBailors; 17.06.2014
comment
Если вы имеете в виду, что я должен поставить @Nullable в вызывающий код (метод testWarning в моем примере), то я говорю не об этом. Если я это сделаю, то это я скажу, что myString может быть нулевым. Я хочу, чтобы компилятор сделал вывод из if (isEmpty(myString)), что myString может быть нулевым, точно так же, как он сделал бы вывод из if (myString == null). Я хочу, чтобы выполнение if (isEmpty(myString)) и выполнение if (myString == null) оказывали одинаковое влияние на предупреждение (то есть показывали предупреждение). - person SantiBailors; 17.06.2014
comment
Да, я хотел поставить @Nullable в качестве аргумента для testWarning. Когда вы говорите if (myString == null), вы сообщаете eclipse/findbugs, что знаете, что myString может быть нулевым. Если этого теста нет, другой способ предоставить ту же информацию — пометить myString как @Nullable. Когда вы вызываете isEmpty, даже если его аргумент помечен как @Nullable, вы не говорите ему об этом. Он принимает ненулевые параметры, но это не значит, что вы думаете, что myString может быть нулевым. - person TimK; 18.06.2014
comment
Понятно, спасибо. Использование @Nullable таким образом было бы разумным компромиссом; не так хорошо, как когда компилятор сам выясняет, что myString может быть нулевым, как это происходит с if (myString == null), но это, вероятно, самое близкое, что можно получить. - person SantiBailors; 18.06.2014

Получаете ли вы предупреждение о потенциальном нулевом указателе, действительно зависит от того, насколько хорош статический анализатор кода. Логически, если вы используете

if (myString == null || myString.equals(""))

ваш код ожидает, что myString будет нулевым. Однако в следующей строке вы разыменовываете myString. Статический анализатор кода видит эти два факта и создает предупреждение о нулевом указателе.

Если вы используете

if (StringUtils.isEmpty(myString))

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

person fajarkoe    schedule 09.06.2014
comment
Согласен, в этом суть. Поэтому мне интересно, можно ли аннотировать подпись isEmpty, чтобы компилятор знал, что if (StringUtils.isEmpty(myString)) является такой же нулевой проверкой для myString, как и if (myString == null). Я попробовал предложение JSR-305 @Nullable выше, но @Nullable, похоже, этого не делает. - person SantiBailors; 10.06.2014

Анализ кода Eclipse также может оценивать внешние нулевые аннотации (начиная с версии 4.5.0). Дополнительная информация доступна по адресу https://wiki.eclipse.org/JDT_Core/Null_Analysis/External_Annotations.

person Konrad Windszus    schedule 23.11.2015