Le specifiche del caso Java per questo (che probabilmente sono molto simili al caso C #) hanno a che fare con il modo in cui il compilatore Java determina se un metodo è in grado di restituire.
In particolare, le regole prevedono che un metodo con un tipo di restituzione non deve essere in grado di completarsi normalmente e deve invece sempre completarsi bruscamente (qui in modo brusco indicando un'istruzione di restituzione o un'eccezione) per JLS 8.4.7 .
Se viene dichiarato che un metodo ha un tipo restituito, si verifica un errore di compilazione se il corpo del metodo può essere completato normalmente. In altre parole, un metodo con un tipo restituito deve restituire solo usando un'istruzione return che fornisce un valore restituito; non è permesso "abbandonare la fine del suo corpo" .
Il compilatore cerca di vedere se la terminazione normale è possibile in base alle regole definite in JLS 14.21 Dichiarazioni non raggiungibili in quanto definisce anche le regole per il completamento normale.
In particolare, le regole per le affermazioni irraggiungibili rappresentano un caso speciale solo per i loop che hanno true
un'espressione costante definita :
Un'istruzione while può essere completata normalmente se almeno una delle seguenti condizioni è vera:
Pertanto, se l' while
istruzione può essere completata normalmente , è necessaria un'istruzione di ritorno di seguito poiché il codice è considerato raggiungibile e qualsiasi while
ciclo senza un'istruzione di interruzione raggiungibile o true
un'espressione costante è considerato in grado di completarsi normalmente.
Queste regole indicano che la tua while
affermazione con un'espressione vera costante e senza a nonbreak
viene mai considerata completata normalmente , e quindi qualsiasi codice sottostante non viene mai considerato raggiungibile . La fine del metodo è al di sotto del ciclo e poiché tutto ciò che si trova al di sotto del ciclo è irraggiungibile, così è la fine del metodo e quindi il metodo non può essere completato normalmente (che è ciò che cerca il complier).
if
le dichiarazioni, d'altra parte, non hanno l'esenzione speciale per quanto riguarda le espressioni costanti che sono concesse ai cicli.
Confrontare:
// I have a compiler error!
public boolean testReturn()
{
final boolean condition = true;
if (condition) return true;
}
Con:
// I compile just fine!
public boolean testReturn()
{
final boolean condition = true;
while (condition)
{
return true;
}
}
Il motivo della distinzione è piuttosto interessante ed è dovuto al desiderio di consentire flag di compilazione condizionali che non causano errori del compilatore (dal JLS):
Ci si potrebbe aspettare che l'istruzione if venga gestita nel modo seguente:
Un'istruzione if-then può essere completata normalmente iff è vera almeno una delle seguenti condizioni:
L'istruzione then è raggiungibile iff l'istruzione if-then è raggiungibile e l'espressione condizione non è un'espressione costante il cui valore è falso.
Un'istruzione if-then-else può essere completata normalmente iff l'istruzione then può essere completata normalmente o l'istruzione else può essere completata normalmente.
L'istruzione then è raggiungibile se l'istruzione if-then-else è raggiungibile e l'espressione della condizione non è un'espressione costante il cui valore è falso.
L'istruzione else è raggiungibile se l'istruzione if-then-else è raggiungibile e l'espressione della condizione non è un'espressione costante il cui valore è vero.
Questo approccio sarebbe coerente con il trattamento di altre strutture di controllo. Tuttavia, al fine di consentire l'utilizzo dell'istruzione if in modo conveniente per scopi di "compilazione condizionale", le regole effettive differiscono.
Ad esempio, la seguente istruzione genera un errore in fase di compilazione:
while (false) { x=3; }
perché la dichiarazione x=3;
non è raggiungibile; ma il caso superficialmente simile:
if (false) { x=3; }
non provoca un errore di compilazione. Un compilatore di ottimizzazione può rendersi conto che l'istruzione x=3;
non verrà mai eseguita e può scegliere di omettere il codice per quell'istruzione dal file di classe generato, ma l'istruzione x=3;
non è considerata "irraggiungibile" nel senso tecnico qui specificato.
La logica di questo diverso trattamento è quella di consentire ai programmatori di definire "variabili flag" come:
static final boolean DEBUG = false;
e quindi scrivere codice come:
if (DEBUG) { x=3; }
L'idea è che dovrebbe essere possibile cambiare il valore di DEBUG da falso a vero o da vero a falso e quindi compilare il codice correttamente senza altre modifiche al testo del programma.
Perché l'istruzione break condizionale provoca un errore del compilatore?
Come indicato nelle regole di raggiungibilità del ciclo, un ciclo while può anche completarsi normalmente se contiene un'istruzione break raggiungibile. Dal momento che le regole per la raggiungibilità di if
un'affermazione allora una clausola non prendono affatto if
in considerazione la condizione if
dell'affermazione, tale clausola allora di un'istruzione condizionale è sempre considerata raggiungibile.
Se break
è raggiungibile, anche il codice dopo il ciclo viene nuovamente considerato raggiungibile. Poiché non esiste un codice raggiungibile che comporti la chiusura improvvisa dopo il ciclo, il metodo viene quindi considerato in grado di completarsi normalmente, quindi il compilatore lo contrassegna come un errore.