2017-02-11 17 views
9

Jak należy rozumieć zachowanie kompilatora Java?Nieosiągalne oświadczenie: while true vs if true

while (true) return; 
System.out.println("I love Java"); 
// Err: unreachable statement 

if (true) return; 
System.out.println("I hate Java"); 
// OK. 

Dzięki.

EDIT:

dowiem się punkt po kilku minutach:

W pierwszym przypadku kompilator zgłasza błąd z powodu nieskończonej pętli. W obu przypadkach kompilator nie myśli o kodzie wewnątrz instrukcji statement.

EDIT II:

Co zawiodła mnie na javac teraz jest:

if (true) return; // Correct 
} 
    while (true) return; // Correct 
} 

Wygląda javac wie, co jest w środku obu pętli i jeśli konsekwentnie, ale kiedy piszesz innego polecenia (jak w pierwszym przykładzie) otrzymujesz zachowanie nierównoważne (które wygląda tak, jak javac zapomniał, co jest wewnątrz pętli/jeśli).

public static final EDIT III: W wyniku tej odpowiedzi mogę uwaga (mam nadzieję, że poprawne): wyrażenia jak if (arg) { ...; return;} i while (arg) { ...; return;} równoważne zarówno semantycznie i składniowo (w kodu bajtowego) Java IFF argv jest nie- wyrażenie stałe (lub skutecznie typu końcowego). Jeśli argv jest stałym wyrażeniem bytecode (i zachowaniem) może się różnić.

Zastrzeżone To pytanie nie jest nieosiągalny sprawozdania, ale innego obchodzenia się z logicznie równoważne wyrażenia takie jak while true return i if true return.

+7

Jest to przypadek "Jeśli piszę szalony kodu, kompilator może również działać crazy". – Kayaman

+1

@Andremoniy Nope. Proszę czytać uważnie. – marek094

+0

@ marek094, jaki jest twój zamiar takiego porównania? Java nie jest językiem niższego poziomu i dlatego kompilator nie jest kompilatorem języka maszynowego. Jaka jest dokładna odpowiedź, której szukasz, lub dokładne pytanie, które zamierzasz zadać? Ponadto, biorąc pod uwagę liczbę wirtualnych maszyn i kompilatorów dostępnych obecnie, jest to, moim zdaniem, bardzo ogólne i mniej informujące pytanie. –

Odpowiedz

13

Istnieją dość ścisłe reguły, gdy wyciągi są osiągalne w java. Zasady te są zaprojektowane tak, aby były łatwe do oceny i nie mogą być w 100% dokładne. Powinno to zapobiegać podstawowym błędom programowania. Aby uzasadnić osiągalność w java, ograniczasz się do tych reguł, "wspólna logika" nie ma zastosowania.

Więc tutaj są zasady z języka Java Specification 14.21. Unreachable Statements

if-then oświadczenie może zakończyć normalnie IFF jest osiągalny.

Więc bez przeprowadzenia innego oświadczenia po if-then są zawsze osiągalne

Chwilę stwierdzenie może zakończyć normalnie IFF co najmniej jeden z następujących warunków:

  • while instrukcja jest osiągalna, a wyrażenie warunku nie jest wyrażeniem stałym (§15.28) o wartości true.

  • Istnieje dostępna instrukcja break, która kończy instrukcję while.

Warunkiem jest stały wyraz „prawda”, nie ma przerwy. W związku z tym nie jest kompletny normalnie.

+1

Pamiętam, że widziałem na to racjonalne uzasadnienie. Podstawową ideą jest to, że możesz zwrócić 'if (COMPILATION_SWITCH); A' i program poprawnie się kompiluje, niezależnie od wartości przełącznika. – zch

5

Według docs:

wyjątkiem specjalnego traktowania chwilę, czy i do sprawozdań których wyrażenie warunek ma wartość stałą prawdziwej wartości wyrażeń nie są brane pod uwagę w analizie przepływowej .

1

Jeśli zmienisz kod nieznacznie (usuń stałe wyrażenie), więc nie spowoduje to osiągnięcia javac, to faktycznie będzie tworzył identyczny kod bajtowy dla obu.

static boolean flag = true; 

static void twhile(){ 
    while (flag) return; 
    System.out.println("Java"); 
} 
static void tif(){ 
    if (flag) return; 
    System.out.println("Java"); 
} 

Otrzymany kod bajtowy:

static void twhile(); 
    descriptor:()V 
    flags: ACC_STATIC 
    Code: 
     stack=2, locals=0, args_size=0 
     StackMap locals: 
     StackMap stack: 
    0: getstatic  #10     // Field flag:Z 
    3: ifeq   7 
    6: return 
     StackMap locals: 
     StackMap stack: 
    7: getstatic  #20     // Field java/lang/System.out:Ljava/io/PrintStream; 
    10: ldc   #26     // String Java 
    12: invokevirtual #28     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    15: return 
     LineNumberTable: 
    line 8: 0 
    line 9: 7 
    line 10: 15 
     LocalVariableTable: 
    Start Length Slot Name Signature 
     StackMapTable: number_of_entries = 1 
    frame_type = 7 /* same */ 

    static void tif(); 
    descriptor:()V 
    flags: ACC_STATIC 
    Code: 
     stack=2, locals=0, args_size=0 
     StackMap locals: 
     StackMap stack: 
    0: getstatic  #10     // Field flag:Z 
    3: ifeq   7 
    6: return 
     StackMap locals: 
     StackMap stack: 
    7: getstatic  #20     // Field java/lang/System.out:Ljava/io/PrintStream; 
    10: ldc   #26     // String Java 
    12: invokevirtual #28     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    15: return 
     LineNumberTable: 
    line 12: 0 
    line 13: 7 
    line 14: 15 
     LocalVariableTable: 
    Start Length Slot Name Signature 
     StackMapTable: number_of_entries = 1 
    frame_type = 7 /* same */ 
+0

Tak, czytam kod bajtu dla przypadku stałego wyrażenia i jego różnic, które są dość niejasne. – marek094

+0

@ marek094, ponieważ nie dostarczałeś nadającego się do kompilacji przykładu dla przypadku wyrażenia stałego, ciężko go porównać. W moich testach tworzy "noops" z różnymi fluffami wokół niego. –

+0

Masz rację, miałem na myśli drugi przykład z mojego pytania. Wiem, że to nie jest ta sama sytuacja, ale także interesująca. – marek094