J'ai une situation où le return
déclaration imbriquée dans deux for
boucles sera toujours atteinte, en théorie.
Le compilateur n'est pas d'accord et nécessite un return
déclaration en dehors de la for
boucle. J'aimerais connaître un moyen élégant d'optimiser cette méthode qui dépasse ma compréhension actuelle, et aucune de mes tentatives d'implémentation de break ne semble fonctionner.
Ci-joint une méthode à partir d'une affectation qui génère des entiers aléatoires et retourne les itérations parcourues jusqu'à ce qu'un deuxième entier aléatoire soit trouvé, généré dans une plage transmise à la méthode en tant que paramètre int.
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)
boucle plutôt qu'une boucle indexée. Cela indique au compilateur que la boucle ne reviendra jamais.oneRun(0)
) et vous voyez que vous atteignez rapidement votre inaccessiblereturn
nextInt
lève une exception pourrange < 0
Le seul cas où le retour est atteint est quandrange == 0
Réponses:
L'heuristique du compilateur ne vous laissera jamais omettre le dernier
return
. Si vous êtes sûr qu'il ne sera jamais atteint, je le remplacerais par unthrow
pour clarifier la situation.la source
throw new AssertionError("\"unreachable\" code reached");
throw
qui ne sera jamais atteint. Trop souvent, les gens veulent simplement appliquer rapidement «une solution pour les gouverner tous» sans trop penser au problème sous-jacent. Mais la programmation est bien plus qu'un simple codage. Surtout quand il s'agit d'algorithmes. Si vous inspectez (soigneusement) le problème donné, vous vous rendrez compte que vous pouvez factoriser la dernière itération de lafor
boucle externe et donc remplacer le retour "inutile" par un retour utile (voir cette réponse ).Comme @BoristheSpider l'a souligné, vous pouvez vous assurer que la deuxième
return
instruction est sémantiquement inaccessible:Compile et fonctionne bien. Et si jamais vous obtenez un,
ArrayIndexOutOfBoundsException
vous saurez que l'implémentation était sémantiquement fausse, sans avoir à lancer quoi que ce soit explicitement.la source
for(int count = 0; true; count++)
place.true
:for(int count = 0; ; count++) …
while(true)
, j'ai pensé que java était peut-être un peu plus strict à cet égard. C'est bien de savoir qu'il n'y avait pas lieu de s'inquiéter ... En fait, j'aimetrue
beaucoup mieux la version omise : cela montre clairement qu'il n'y a absolument aucune condition à regarder :-)Puisque vous avez posé une question sur la rupture de deux
for
boucles, vous pouvez utiliser une étiquette pour le faire (voir l'exemple ci-dessous):la source
returnValue
peut être utilisé non initialisé?Alors qu'une affirmation est une bonne solution rapide. En général, ce genre de problèmes signifie que votre code est trop compliqué. Quand je regarde votre code, il est évident que vous ne voulez pas vraiment qu'un tableau contienne les numéros précédents. Vous voulez un
Set
:Notez maintenant que ce que nous retournons est en fait la taille de l'ensemble. La complexité du code est passée de quadratique à linéaire et il est immédiatement plus lisible.
Maintenant, nous pouvons réaliser que nous n'avons même pas besoin de cet
count
index:la source
Comme votre valeur de retour est basée sur la variable de la boucle externe, vous pouvez simplement modifier la condition de la boucle externe,
count < range
puis renvoyer cette dernière valeur (que vous venez d'omettre) à la fin de la fonction:De cette façon, vous n'avez pas besoin d'introduire du code qui ne sera jamais atteint.
la source
...
) mais la boucle externe a été réduite par sa dernière itération. Le cas correspondant à cette dernière itération est traité séparément par la toute dernière instruction return. Bien que ce soit une solution élégante pour votre exemple, il existe des scénarios dans lesquels cette approche devient plus difficile à lire; si, par exemple, la valeur de retour dépendait de la boucle interne, alors - au lieu d'une seule instruction de retour à la fin - vous vous retrouveriez avec une boucle supplémentaire (représentant la boucle interne de la dernière itération de la boucle externe).Utilisez une variable temporaire, par exemple "result", et supprimez le retour interne. Changez la boucle for pour une boucle while avec la bonne condition. Pour moi, il est toujours plus élégant de n'avoir qu'un seul retour comme dernière instruction de la fonction.
la source
return result
saupoudré dedans et pensent ensuite vouloir faire une vérification de plus sur le trouvéresult
avant de le retourner, et ce n'est qu'un exemple). Il peut aussi y avoir des inconvénients, mais une déclaration aussi large que "En général, il n'y a aucune bonne raison d'avoir un seul retour" ne tient pas la route.Peut-être que c'est une indication que vous devriez réécrire votre code. Par exemple:
la source
Les méthodes qui ont une instruction return et ont une ou des boucles à l'intérieur nécessitent toujours une instruction return en dehors de la ou des boucles. Même si cette instruction en dehors de la boucle n'est jamais atteinte. Dans de tels cas, afin d'éviter des déclarations de retour inutiles, vous pouvez définir une variable du type respectif, un entier dans votre cas, au début de la méthode, c'est-à-dire avant et en dehors de la ou des boucles respectives. Lorsque le résultat souhaité à l'intérieur de la boucle est atteint, vous pouvez attribuer la valeur respective à cette variable prédéfinie et l'utiliser pour l'instruction return en dehors de la boucle.
Puisque vous voulez que votre méthode renvoie le premier résultat lorsque rInt [i] est égal à rInt [count], implémenter uniquement la variable mentionnée ci-dessus n'est pas suffisant car la méthode retournera le dernier résultat lorsque rInt [i] est égal à rInt [count]. Une des options consiste à implémenter deux "instructions break" qui sont appelées lorsque nous obtenons le résultat souhaité. Ainsi, la méthode ressemblera à quelque chose comme ceci:
la source
Je suis d'accord qu'il faut lever une exception là où une déclaration inaccessible se produit. Je voulais juste montrer comment la même méthode peut faire cela de manière plus lisible (java 8 streams requis).
la source
la source
result == -1
vérifications qui peuvent être omises avec l'return
intérieur de la boucle ...