2015-09-10 2 views
21

Возьмем следующий фрагмент кода Java:(Compiler) еще если (правда) против еще сценария

.... 
    else if (true){ //hard-coded as true 
    ///launch methodA 
    } 
    else { 
    ///launch methodA (same code as in the ` else if ` statement) 
    } 
.... 

Что мне было интересно то, как компилятор работает с этим. Не было бы логичным, если бы компилятор полностью удалил оператор else if(true), чтобы не выполнять проверку, даже если он жестко закодирован как истинный. В частности, в Eclipse, как интерпретируется код выше?

Или что насчет следующего сценария:

.... 
    else if (true){ //hard-coded as true 
    ///launch methodA 
    } 
    else { 
    ///launch methodBB 
    } 
.... 

это не было бы логичным в этом случае для компилятора, чтобы удалить else заявление? Потому что во время работы оператор else недоступен.

+0

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

+0

«Разве это не логично ...» Да, и это то, что на самом деле делают большинство современных компиляторов. –

ответ

19

Недопустимые операторы запрещены в Java и должны приводить к ошибкам компиляции. JLS определяет, что является недостижимым заявления: https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.21

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

if (false) { x=3; } 

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

Основания для такого различного лечения, чтобы позволить программистам определить «переменный флаг», такие как:

static final boolean DEBUG = false; 

, а затем написать код, такие как:

if (DEBUG) { x=3; } 

Идея заключается в том, что оно должно быть возможно изменить значение DEBUG с false на true или с true на false, а затем скомпилировать код правильно, без каких-либо изменений текста программы.

Таким образом, ответ будет зависеть от используемого вами компилятора и его опций оптимизации.

+2

Кроме того, было бы довольно неприятно, если бы программист, у которого есть переменная типа «static boolean enableLogging», которая на самом деле * используется как переменная *, не может впоследствии изменить ее на «статический конечный логический elableLogging = false;», не имея для ручного редактирования всего кода, который его читает. – supercat

2

О Eclipse, в частности, будет предупреждать вас, что блок последнего блока недоступен, но компиляция делегирована вашему jdk, поэтому, возможно, именно компилятор предупреждает Eclipse.

+3

На самом деле Eclipse имеет свой собственный компилятор 'ecj' (Eclipse Compiler for Java). Sun/Oracle 'javac' (написанный Мартином Одерским, разработчиком Scala) - пакетный компилятор, не предназначенный для интерактивного, инкрементного использования. 'ecj' (как и все Eclipse) получен из IBM VisualAge для Smalltalk и, следовательно, специально разработан для интерактивной инкрементной компиляции in-you-type внутри IDE. –

3

На этот вопрос нет конкретного ответа. Это зависит от компилятора Java. Большинство компиляторов игнорируют Dead Code, потому что это не изменит семантику кода, даже если это приведет к созданию более крупного файла класса.

Если вас интересует такой анализ, существует много литературы о ликвидации Dead Code.

3

Вы можете попробовать написать код и декомпилировать файл класса. Мой компилятор оптимизирует

else if (true){ //hard-coded as true 
///launch methodA 
} 
else { 
///launch methodA (same code as in the else if statement) 
} 

в

else { 
///launch methodA 
} 

и

else if (true){ //hard-coded as true 
///launch methodA 
} 
else { 
///launch methodBB 
} 

в

else { 
///launch methodA 
} 

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

10

Компилятор optmizes его во время компиляции:

public class Test { 
    public static void main(String[] args) { 
    if(true) { 
     System.out.println("Hello"); 
    } else { 
     System.out.println("Boom"); 
    } 
} 

дает мне (с моим Java 1.8.0_45):

Compiled from "Test.java" 
public class Test { 
    publicTest(); 
    Code: 
     0: aload_0 
     1: invokespecial #1  // Method java/lang/Object."<init>":()V 
     4: return 

    public static void main(java.lang.String[]); 
    Code: 
     0: getstatic  #2  // Field java/lang/System.out:Ljava/io/PrintStream; 
     3: ldc   #3  // String Hello 
     5: invokevirtual #4  // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     8: return 
} 

код просто печатает Hello. Boom даже не рассматривается.

Все последние компиляторы Java уничтожают мертвый код во время компиляции.

2

теперь я пишу код в затмить мой метод

 public static void aa(String b){ 
     if (true) { 

     } 

     else if (true) { 
      System.out.println("asas"); 
     } else { 

     } 
     } 

После того, как я составлен мой код, и я Decompiler мой код с JD-GUI.My кодом Decompiler является:

public static void aa(String b) {} 

}

результат очень хороший :)

1

ХОЧУ " t логично, чтобы компилятор вообще удалял оператор else if (true), чтобы не выполнять проверку, хотя он жестко закодирован как истинный.

Нет, не было бы, если бы оба блока не имели одинаковый контент и почему бы это проверить? Это было бы семантически неправильно. Что было бы логичным для компилятора, чтобы удалить окончательный недостижимый else, и это то, что он делает.

Смежные вопросы