Подтвердить что ты не робот

Должен ли я предварительно инициализировать переменную, которая перезаписывается в нескольких ветвях?

Есть метод:

private String myMethod(String gender)
{
    String newString = "";
    if(gender.equals("a"))
        newString = internal.getValue();
    else
        newString = external.getValue();

    return newString;
}

Я все переделал, но с одним небольшим изменением: String newString; вместо: String newString = "";

Улучшает ли этот рефактор код? Я знаю, что String - это null, когда мы его не инициализируем, но в этом примере он всегда будет иметь значение a из if или else. Этот рефактор что-то меняет?

4b9b3361

Ответ 1

Чтобы ответить на прямой вопрос: здесь нет необходимости присваивать значение изначально здесь; все ветки выполнения кода будут иметь значение, чтобы дать newString значение. Таким образом, вам вообще не нужно его инициализировать. В противном случае я бы инициализировал все, что вы хотите, в качестве значения по умолчанию.

Вместо двух возвратов или оператора ветвления для присвоения переменной, я бы просто вернулся с троичным:

private String myMethod(String gender) {
    return gender.equals("a")
            ? internal.getValue()
            : external.getValue();
}

Ответ 2

  Лучше инициализировать строку или оставить ее нулевой?

Ваша предпосылка ошибочна: отсутствие инициализации строки не означает, что ее значение равно нулю.

Вам не разрешено использовать локальную переменную до того, как она была назначена, чтобы избежать случайного использования значения, которое вы не намеревались. Таким образом, значение не является "нулевым", оно не определено (*).

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

Например, если код выглядит следующим образом:

private String myMethod(String gender)
{
    String newString = "";
    if(gender.equals("a"))
        newString = internal.getValue();
    else if (gender.equals("b");
        newString = external.getValue();
    // Oops! meant to check if gender.equals("c")

    return newString;
}

у вас может быть ошибка, потому что есть пропущенный случай, который вы еще не проверили.

Если бы вы явно присвоили null переменной, у вас возникла бы та же проблема; но теперь ваш метод будет возвращать ноль, и поэтому возможно вызовет NPE в вызывающем коде.

Если вы опустите = "", компилятор остановит вас, используя newString в возвращении.

(Присвоение и переназначение переменной также означает, что переменная не будет эффективно окончательной, поэтому вы не сможете использовать ее внутри лямбда-класса или анонимного класса).


(*) Это относится только к локальным переменным и элементам/статическим переменным final. Члены класса не должны определенно назначаться перед использованием, если они не являются окончательными, что является богатым швом для ошибок и хорошим поводом для того, чтобы сделать учащихся окончательными, где это возможно. И, технически, члены final сначала инициализируются значением по умолчанию их типа, так что вы можете фактически прочитать их как null перед их инициализацией.

Ответ 3

Лучше всего инициализировать String (или что-либо еще), только если есть сценарий, в котором используется начальное значение.

В вашем случае вы присвоили newString строковый литерал, который не преследует никакой цели, кроме как сбить с толку читателя.

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

Ответ 4

Мой взгляд на самую короткую форму без троичного оператора (который, я думаю, снижает читабельность):

private String myMethod(String gender)
{
    if(gender.equals("a"))
        return internal.getValue();
    return external.getValue();
}

Я бы, вероятно, имел полную конструкцию if {...} else {...}, как и другие ответы в моем собственном коде.

Также не все отладчики могут легко показать, что возвращается из метода как часть нормального потока, поэтому может быть проще, если возвращаемое значение записывается в переменную и возвращается THEN (где точка останова может быть помещена в оператор return)

Ответ 5

Вы можете сделать эту строку final и оставить ее без присмотра, чтобы убедиться, что все ветки if присваивают значение:

final String result;
if (condition1) {
    result = "one";
} else if (condition2) {
    result = "two";
} else {
    result = "other";
}
return result;

При таком подходе компилятор проверит, что переменная result была назначена один раз в каждой ветки. Это может быть полезно, если вы добавите еще одну ветвь условия или по ошибке попытаетесь перезаписать переменную - компилятор завершится с ошибкой и покажет ошибку.

Ответ 6

В вашем случае (если еще условие) нет необходимости инициализировать String, вы можете просто указать его как String newString;, и это будет нормально, так как в любом случае в конце он будет иметь другое значение.

private String myMethod(String gender)
{
    String newString;

    if(gender.equals("a"))
        newString = internal.getValue();
    else
        newString = external.getValue();

    // Missing return statement.
}

Также я вижу, что у вас есть функция, которая возвращает строку. Предполагая, что переменная newString - это то, что вы будете возвращать, вместо создания строковой переменной вы можете просто вернуть строку в условии:

private String myMethod(String gender)
{
    if(gender.equals("a"))
        return internal.getValue();
    else
        return external.getValue();
}

Ответ 7

Мои колледжи правы, это может быть сделано с оператором Tenary. Кроме того, я считаю, что очень важно предотвращать NullPoiterExeptions как можно чаще. Что, если пол будет нулевым? Исключение нулевого указателя Я бы поменял "а" и пол так:

    private String myMethod(String gender) {
        return "a".equals(gender)
            ? internal.getValue()
            : external.getValue();
    }

Ответ 8

Согласно Java документу:

Значения по умолчанию

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

Локальные переменные немного отличаются; компилятор никогда не назначает значение по умолчанию для неинициализированной локальной переменной. Если вы не можете инициализировать локальную переменную там, где она объявлена, убедитесь, что вы присвоили ей значение, прежде чем пытаться ее использовать. Доступ к неинициализированной локальной переменной приведет к ошибке во время компиляции.