Почему int someVal=0 для поля экземпляра не считается мертвым кодом?

Почему я не получаю предупреждения о мертвом коде для инициализации someVal здесь?

public class DeadCode {

    private int someVal = 0;

    public DeadCode(int someVal) {
        this.someVal = someVal;
    }

    public int getSomeVal() {
        return someVal;
    }

    public void setSomeVal(int someVal) {
        this.someVal = someVal;
    }

}

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

Это мертво дважды, потому что

  1. Java автоматически инициализирует поля экземпляра значением 0 или эквивалентным;
  2. значение someVal не может быть прочитано без записи.

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

Если есть различие между мертвым кодом и кодом, который не имеет эффекта, то я бы ожидал

Присвоение переменной someVal не имеет никакого эффекта.

что бы я получил, если бы написал

someVal = someVal;

в моем коде. Но я тоже этого не понимаю.

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


person chiastic-security    schedule 11.11.2014    source источник
comment
Избыточный код и мертвый код — это не одно и то же.   -  person azurefrog    schedule 11.11.2014
comment
Я не вижу мертвого кода. Такая ситуация возникает, когда компилятор считает, что часть вашего кода никогда не будет выполнена. Ваш пример - это всего лишь два разных способа инициализации параметра экземпляра и его изменения с помощью метода "на лету".   -  person energizer    schedule 11.11.2014
comment
@energizer Нет, это недостижимый код. Мертвый код — это код, который не имеет никакого эффекта, вот что это такое.   -  person chiastic-security    schedule 11.11.2014
comment
@azurefrog Я обновил вопрос, чтобы охватить это. Но Википедия считает, что удаление мертвого кода — это удаление кода, который не повлияет на вывод, и именно это Это.   -  person chiastic-security    schedule 11.11.2014
comment
@chiastic-security По крайней мере, в eclipse недостижимый код — это код, который не может быть выполнен (например, код после оператора return), а мертвый код — это код, который будет выполнен. не выполняться (например, if (a) { if (!a) { //this is dead } }). Код, который не действует, но будет выполняться, не недостижим и не мертв.   -  person azurefrog    schedule 11.11.2014
comment
Есть другой подход. Я думаю, что мертвый код можно представить так: предположим, что у вас есть какие-то вычисления: result = a + b; вернуть а+б; - поэтому «результат» вообще никогда не будет использоваться, поэтому компилятор пометит его как неиспользуемый или мертвый код. На самом деле понятие «мертвый код» в настоящее время вводит в заблуждение, потому что каждый программист может интерпретировать его так, как он его понимает.   -  person energizer    schedule 11.11.2014
comment
@azurefrog Я тоже не получаю предупреждения в вашем примере.   -  person chiastic-security    schedule 11.11.2014
comment
Либо компилятор проверяет этот случай для каждого поля с выражением инициализации, либо JVM избавляется от него, что, я думаю, уже делает.   -  person Sotirios Delimanolis    schedule 11.11.2014


Ответы (2)


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

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

person John Bollinger    schedule 11.11.2014
comment
Можете ли вы показать, как это может произойти? Я не думаю, что это возможно. Значение недоступно ни одному потоку, пока конструктор и инициализаторы не закончат работу. В Java невозможно получить неинициализированное значение, даже если вы возитесь с потоками. - person chiastic-security; 11.11.2014
comment
Вы ошибаетесь, @chiastic-security. Значение поля по умолчанию и значение после запуска его инициализатора, но до запуска конструктора, в принципе, могут быть видны другим потокам до завершения конструктора. У этой проблемы с синхронизацией даже есть название: неправильная публикация. Вы можете найти много обсуждений под этим именем, в том числе здесь. - person John Bollinger; 11.11.2014
comment
OK. Но значение по умолчанию и значение после инициализации одинаковы... так как инициализация может повлиять на поведение другого потока? - person chiastic-security; 11.11.2014
comment
В случае неправильной публикации значение может быть не только увидено до завершения конструктора, но и может быть изменено с помощью его мутатора до завершения конструктора. И эту мутацию, в принципе, тоже можно было увидеть. А затем быть перезаписанным инициализатором. - person John Bollinger; 11.11.2014
comment
Неплохо подмечено. Однако я мог бы избавиться от мутатора, и тогда эта проблема не возникла бы. - person chiastic-security; 11.11.2014
comment
Не так. Поля, даже приватные, в общем случае могут быть изменены отражающим образом. Политика безопасности может повлиять на это, но компилятор не может делать предположения о политике безопасности во время выполнения. - person John Bollinger; 12.11.2014
comment
Я думаю, проблема в том, что это сделало бы все предупреждения о x = x назначениях неверными. - person chiastic-security; 12.11.2014
comment
И да и нет. Да, тот же аргумент применим к любому инициализатору поля, и на самом деле вы заметили, что инициализаторы, которые вы считали мертвым кодом, не вызывали предупреждения. Нет, назначения локальным переменным методов и конструкторов не будут затронуты, поскольку они не используются совместно потоками. - person John Bollinger; 12.11.2014

Целочисленное поле является упрощенным вариантом использования. Что, если бы у вас было что-то подобное, обратите внимание на конструктор без параметров:

public class DeadCode {

    private List<Integer> someVal = new ArrayList<>();

    public DeadCode() {
    }

    public DeadCode(Iterable<Integer> someVal) {
        this.someVal.addAll(someVal);
    }

    public Iterable<Integer> getSomeVal() {
        return someVal;
    }

    public void addSomeVal(int someVal) {
        this.someVal.add(someVal);
    }
}

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

person LeffeBrune    schedule 11.11.2014
comment
this.someVal.addAll (someVal); --› может быть так.someVal = someVal; - person StackFlowed; 11.11.2014
comment
Это вовсе не мертво. Если я вызову конструктор без аргументов, а затем addSomeVal(0), инициализация поля позволит избежать NullPointerException. - person chiastic-security; 11.11.2014
comment
Я пытаюсь подчеркнуть, что лучше иметь компилятор, который последовательно обрабатывает все эти случаи, вместо того, чтобы заставлять меня удалять инициализацию поля, когда в ней нет необходимости. - person LeffeBrune; 11.11.2014