Ich habe eine Situation, in der die return
in zwei for
Schleifen verschachtelte Anweisung theoretisch immer erreicht wird.
Der Compiler ist anderer Meinung und benötigt eine return
Anweisung außerhalb der for
Schleife. Ich würde gerne einen eleganten Weg kennen, um diese Methode zu optimieren, der über mein derzeitiges Verständnis hinausgeht, und keine meiner versuchten Implementierungen von break scheint zu funktionieren.
Im Anhang befindet sich eine Methode aus einer Zuweisung, die zufällige Ganzzahlen generiert und die durchlaufenen Iterationen zurückgibt, bis eine zweite zufällige Ganzzahl gefunden wird, die innerhalb eines Bereichs generiert wird, der als int-Parameter an die Methode übergeben wird.
private static int oneRun(int range) {
int[] rInt = new int[range+1]; // Stores the past sequence of ints.
rInt[0] = generator.nextInt(range); // Inital random number.
for (int count = 1; count <= range; count++) { // Run until return.
rInt[count] = generator.nextInt(range); // Add randint to current iteration.
for (int i = 0; i < count; i++) { // Check for past occurence and return if found.
if (rInt[i] == rInt[count]) {
return count;
}
}
}
return 0; // Never reached
}
while(true)
eine indizierte Schleife anstelle einer indizierten Schleife verwenden. Dies teilt dem Compiler mit, dass die Schleife niemals zurückkehren wird.oneRun(0)
) auf und Sie sehen, dass Sie schnell Ihre nicht erreichbare erreichenreturn
nextInt
eine Ausnahme für wirftrange < 0
Der einzige Fall, in dem die Rückkehr erreicht wird, ist, wennrange == 0
Antworten:
Mit den Heuristiken des Compilers können Sie niemals die letzte weglassen
return
. Wenn Sie sicher sind, dass es niemals erreicht wird, würde ich es durch ein ersetzenthrow
, um die Situation klarer zu machen.quelle
throw new AssertionError("\"unreachable\" code reached");
throw
, der niemals erreicht werden kann. Viel zu oft wollen die Leute einfach schnell "eine Lösung anwenden, um sie alle zu regieren", ohne zu viel über das zugrunde liegende Problem nachzudenken. Programmieren ist jedoch viel mehr als nur Codieren. Besonders wenn es um Algorithmen geht. Wenn Sie das gegebene Problem (sorgfältig) untersuchen, werden Sie feststellen, dass Sie die letzte Iteration der äußerenfor
Schleife herausrechnen und somit die "nutzlose" Rückgabe durch eine nützliche ersetzen können (siehe diese Antwort ).Wie @BoristheSpider hervorhob, können Sie sicherstellen, dass die zweite
return
Anweisung semantisch nicht erreichbar ist:Kompiliert und läuft gut. Und wenn Sie jemals eine bekommen
ArrayIndexOutOfBoundsException
, wissen Sie, dass die Implementierung semantisch falsch war, ohne explizit etwas werfen zu müssen.quelle
for(int count = 0; true; count++)
stattdessen schreiben .true
:for(int count = 0; ; count++) …
while(true)
, dachte ich, dass Java in dieser Hinsicht vielleicht etwas strenger ist. Gut zu wissen, dass es keinen Grund zur Sorge gab ... Eigentlich mag ich die ausgelassenetrue
Version viel besser: Es macht visuell klar, dass es absolut keine Bedingung gibt, um sie anzusehen :-)Da Sie nach dem Ausbrechen von zwei
for
Schleifen gefragt haben , können Sie dazu ein Etikett verwenden (siehe Beispiel unten):quelle
returnValue
es nicht initialisiert verwendet werden kann?Während eine Behauptung eine gute schnelle Lösung ist. Im Allgemeinen bedeutet diese Art von Problemen, dass Ihr Code zu kompliziert ist. Wenn ich mir Ihren Code anschaue, ist es offensichtlich, dass Sie nicht wirklich möchten, dass ein Array vorherige Nummern enthält. Du willst ein
Set
:Beachten Sie nun, dass das, was wir zurückgeben, tatsächlich die Größe des Sets ist. Die Codekomplexität hat sich von quadratisch zu linear verringert und ist sofort besser lesbar.
Jetzt können wir erkennen, dass wir diesen
count
Index nicht einmal brauchen :quelle
Da Ihr Rückgabewert auf der Variablen der äußeren Schleife basiert, können Sie einfach den Zustand der äußeren Schleife ändern
count < range
und dann diesen letzten Wert (den Sie gerade weggelassen haben) am Ende der Funktion zurückgeben:Auf diese Weise müssen Sie keinen Code einführen, der niemals erreicht wird.
quelle
...
), aber die äußere Schleife wurde durch ihre letzte Iteration reduziert. Der dieser letzten Iteration entsprechende Fall wird von der allerletzten return-Anweisung separat behandelt. Obwohl dies eine elegante Lösung für Ihr Beispiel ist, gibt es Szenarien, in denen dieser Ansatz schwieriger zu lesen ist. Wenn zum Beispiel der Rückgabewert von der inneren Schleife abhängt, bleibt anstelle einer einzelnen return-Anweisung am Ende eine zusätzliche Schleife übrig (die die innere Schleife für die letzte Iteration der äußeren Schleife darstellt).Verwenden Sie eine temporäre Variable, zum Beispiel "result", und entfernen Sie die innere Rückgabe. Ändern Sie die for-Schleife für eine while-Schleife unter den richtigen Bedingungen. Für mich ist es immer eleganter, nur eine Rückgabe als letzte Anweisung der Funktion zu haben.
quelle
return result
streuten sich darin herum und überlegten dann, ob sie das gefundene noch einmal überprüfen möchten,result
bevor sie es zurückgeben, und dies ist nur ein Beispiel. Es kann auch Nachteile geben, aber eine so breite Aussage wie "Im Allgemeinen gibt es keinen guten Grund, nur eine Rückkehr zu haben" hält kein Wasser.Vielleicht ist dies ein Hinweis darauf, dass Sie Ihren Code neu schreiben sollten. Beispielsweise:
quelle
Methoden mit einer return-Anweisung und einer Schleife / Schleifen erfordern immer eine return-Anweisung außerhalb der Schleife (n). Auch wenn diese Aussage außerhalb der Schleife nie erreicht wird. In solchen Fällen können Sie zu Beginn der Methode, dh vor und außerhalb der jeweiligen Schleife (n), eine Variable des jeweiligen Typs definieren, in Ihrem Fall eine Ganzzahl, um unnötige Rückgabeanweisungen zu vermeiden. Wenn das gewünschte Ergebnis innerhalb der Schleife erreicht ist, können Sie dieser vordefinierten Variablen den entsprechenden Wert zuweisen und ihn für die return-Anweisung außerhalb der Schleife verwenden.
Da Ihre Methode das erste Ergebnis zurückgeben soll, wenn rInt [i] gleich rInt [count] ist, reicht es nicht aus, nur die oben genannte Variable zu implementieren, da die Methode das letzte Ergebnis zurückgibt, wenn rInt [i] gleich rInt [count] ist. Eine Möglichkeit besteht darin, zwei "break-Anweisungen" zu implementieren, die aufgerufen werden, wenn das gewünschte Ergebnis erzielt wird. Die Methode sieht also ungefähr so aus:
quelle
Ich bin damit einverstanden, dass eine Ausnahme ausgelöst wird, wenn eine nicht erreichbare Aussage auftritt. Ich wollte nur zeigen, wie dieselbe Methode dies besser lesbar macht (Java 8-Streams erforderlich).
quelle
quelle
result == -1
Schecks , die mit der weggelassen werden kann , umreturn
die Schleife im Inneren ...