web-dev-qa-db-fra.com

Pourquoi Java a-t-il des méthodes `void`?

Est-ce que/pourquoi Java doit-il avoir des méthodes void? Référence :

Toute méthode déclarée nulle ne renvoie pas de valeur.

Pour autant que je puisse penser, chaque utilisation de void serait mieux servie en renvoyant un indicateur de statut, l'objet invoqué ou null.

Cela ferait de chaque appel une instruction assignable et faciliterait les modèles de générateur et le chaînage de méthodes. Les méthodes qui ne sont invoquées que pour leurs effets renvoient généralement un type booléen ou générique Success ou lèvent une exception en cas d'échec.

50
marisbest2

Parce qu'il y a une différence entre "Cette fonction peut réussir ou échouer et est suffisamment consciente d'elle-même pour faire la différence" et "Il n'y a pas de retour d'information sur l'effet de cette fonction". Sans void, vous vérifieriez sans cesse les codes de réussite et croiriez que vous écrivez un logiciel robuste, alors qu'en fait vous ne faites rien de la sorte.

156
Kilian Foth
  1. Parce que C a un type void et Java a été conçu pour suivre la plupart des conventions de la famille de langage C.
  2. Il existe de nombreuses fonctions que vous ne souhaitez pas voir renvoyer une valeur. Qu'allez-vous faire avec "un type générique Success" de toute façon? En fait, les valeurs de retour pour indiquer le succès sont encore moins importantes dans Java que dans C, car Java a des exceptions pour indiquer l'échec et pas C).
94
Mason Wheeler

La raison originale pour laquelle la langue a un type void est parce que comme dans C, les créateurs de la langue ont ne pas vouloir compliquer inutilement la syntaxe du langage avec procédure s et fonction s comme Pascal l'a fait.

C'était la raison d'origine.

Vos suggestions:

renvoyant un indicateur de statut

C'est un non-non. Nous n'utilisons pas d'indicateurs d'état. En cas de problème, nous le signalons via des exceptions.

l'objet invoqué

Le style fluide des invocations est un développement récent. Beaucoup de programmeurs qui utilisent très couramment le fluent aujourd'hui et roulent les yeux s'ils doivent utiliser une interface qui ne la prend pas en charge ne sont même pas nés lorsque Java a été créé.

retour nul

Cela vous obligerait à déclarer une méthode comme retournant quelque chose, alors qu'en fait elle ne retourne rien, cela serait très déroutant pour quelqu'un qui regarde une interface essayant de comprendre ce qu'elle fait. Les gens inventeraient inévitablement une classe autrement inutile qui signifie "aucune valeur de retour" afin que toutes les fonctions qui n'ont rien à retourner puissent retourner une référence nulle à une telle classe. Ce serait maladroit. Heureusement, il existe une solution à cela, elle s'appelle void. Et c'est la réponse à votre question.

64
Mike Nakis

Certaines méthodes, comme System.out.println ne renvoie rien d'utile, mais est appelé uniquement pour cet effet secondaire. void est un indicateur utile pour le compilateur et pour le lecteur de code qu'aucune valeur utile n'est renvoyée.

Renvoyer null au lieu de void signifie que vous obtiendrez simplement un NullPointerException au moment où vous utilisez cette valeur pour quoi que ce soit. Vous échangez donc une erreur de compilation pour une erreur d'exécution qui est bien pire. De plus, vous devrez définir le type de retour comme Object, ce qui serait trompeur et déroutant. (Et le chaînage ne fonctionnerait toujours pas.)

Les codes d'état sont généralement utilisés pour indiquer des conditions d'erreur, mais Java a des exceptions à cet effet.

Renvoyer this n'est pas possible à partir de méthodes statiques.

Le retour d'un objet générique Success n'aurait aucun but utile.

20
JacquesB

L'une des raisons est qu'il peut être trompeur de ne jamais renvoyer autre chose que, disons, null. Exemple:

Que doit renvoyer Arrays.sort(a)?

Si vous soutenez que a doit être retourné pour que l'appel puisse être enchaîné (ce qui semble être votre réponse à en juger par votre question), alors il n'est plus clair si la valeur de retour est un copie de l'objet d'origine, ou de l'objet d'origine lui-même. Les deux sont possibles. Et oui, vous pouvez le mettre dans la documentation, mais c'est suffisamment ambigu pour que vous ne deviez pas créer l'ambiguïté en premier lieu.

D'un autre côté, si vous soutenez que null doit être retourné, cela pose la question de savoir quelles informations la valeur de retour fournit éventuellement à l'appelant, et pourquoi le programmeur devrait être forcé d'écrire return null quand il ne transmet aucune information.

Et si vous retournez quelque chose d'autre totalement absurde (comme la longueur de a), cela rend la utilisation de cette valeur de retour vraiment déroutante - pensez à quel point il est encore plus déroutant de dire int len = Arrays.sort(a) à la place de int len = A.length!

11
user541686

Renvoyer un boolean qui est toujours égal à true que vous suggérez, est non seulement inutile (la valeur de retour ne contient aucune information), mais serait en fait trompeur. La plupart du temps, il est préférable d'utiliser des types de retour qui ne contiennent que le nombre d'informations réellement disponibles - c'est pourquoi dans Java vous avez boolean pour true/false plutôt que de renvoyer un int avec 4 milliards de valeurs possibles. De même, renvoyer un boolean avec deux valeurs possibles où il n'y a qu'une seule valeur possible ("succès générique") , serait trompeur.

Cela ajouterait également des frais généraux de performances inutiles.

Si une méthode n'est utilisée que pour son effet secondaire, il n'y a rien à retourner, et le type de retour void reflète exactement cela. Les erreurs rares potentielles peuvent être signalées via des exceptions.

Une chose qui pourrait être améliorée serait de faire de void un type réel, comme le Unit de Scala. Cela résoudrait certains problèmes tels que la manipulation des génériques.

7
Michał Kosmulski

Java est un langage relativement ancien. Et en 1995 (lors de sa création) et peu de temps après, les programmeurs étaient très préoccupés par la durée pendant laquelle un processus prenait le contrôle du processeur ainsi que par la consommation de mémoire. Renvoyer void éliminerait quelques cycles d'horloge et un peu de consommation de mémoire d'un appel de fonction car vous n'auriez pas à mettre la valeur de retour sur la pile et vous n'auriez pas à la supprimer par la suite.

Un code efficace ne vous rend pas quelque chose que vous n'utiliseriez jamais, et donc mettre vide dans quelque chose qui a une valeur de retour sans signification est une bien meilleure pratique que de renvoyer une valeur de succès.

4
The Lazy Coder

J'ai lu des arguments qui suggèrent que la deuxième option (return this) devrait être l'approche au lieu de void. C'est une assez bonne idée mais l'approche de style constructeur n'était pas populaire à l'époque Java a été créée. Si elle était aussi populaire à l'époque qu'elle l'est maintenant, cela aurait pu être le approche adoptée. Renvoyer null est une très mauvaise idée OMI. Je souhaite que null ne soit même pas du tout dans la langue.

Le problème est maintenant que si une méthode retourne une instance de son propre type, il n'est pas clair s'il s'agit d'un nouvel objet ou du même. Souvent, cela n'a pas (ou ne devrait pas) d'importance, mais d'autres fois, cela compte. Je suppose que la langue pourrait être modifiée pour renvoyer implicitement this sur les méthodes void. Le seul problème auquel je peux penser pour le moment est que si la méthode était modifiée plus tard pour renvoyer un nouvel objet du même type, il n'y aurait pas d'avertissement de compilation, mais ce n'est peut-être pas un gros problème. Le système de type actuel ne se soucie plus de ces types de changements maintenant. La façon dont cela interagit avec l'héritage/les interfaces nécessiterait une certaine réflexion, mais cela permettrait aux anciennes API sans style de générateur d'être facilement appelées comme si elles le faisaient.

2
JimmyJames

Un autre aspect:

Java est un langage statique avec des fonctionnalités assez strictes. Cela signifie que beaucoup de choses qui seraient assez ouvertes ou dynamiques dans d'autres langues (c/f Ruby, LISP etc.) sont strictement déterminées.

Il s'agit d'une décision de conception générale. Le "pourquoi" est difficile à répondre (enfin, parce que les concepteurs de la langue pensaient que ce serait bien!). Le "pourquoi" est assez clair: il permet au compilateur de détecter un lot d'erreurs, ce qui est généralement une très bonne fonctionnalité pour n'importe quelle langue. Deuxièmement, il est relativement facile de raisonner sur la langue. Par exemple, il est relativement facile de créer une correction formelle prouvant dans (des sous-ensembles de) le Java; en comparaison, cela serait pratiquement impossible dans un langage dynamique comme Ruby et al.

Cette réflexion imprègne le langage, par exemple, la déclaration forcée des exceptions possibles qu'une méthode peut lancer, le type distinct de interface contre class pour éviter l'héritage multiple ambigu, et ainsi de suite. Pour ce que c'est (un impératif statique OOP langage réel avec un fort accent sur la gestion des erreurs de compilation)), ces choses sont en fait assez élégantes et puissantes. Elles se rapprochent de la théorie (science'y) des langues qui sont faites à dessein juste pour explorer certaines de ces questions que toute autre langue du monde réel avant (à cette époque, faites attention).

Donc. Avoir un type void strict est un message clair: cette méthode ne renvoie rien, point final. C'est ce que c'est. Le remplacer par l'application pour toujours renvoyer quelque chose conduirait à un comportement beaucoup plus dynamique (comme dans Ruby où every def a une valeur de retour explicite ou implicite, toujours)) , ce qui serait mauvais pour la prouvabilité et le raisonnement; ou pour un ballonnement massif en utilisant un autre mécanisme ici.

(Et NB, Ruby (par exemple) gère cela différemment, et sa solution est toujours exactement aussi acceptable que Java, car elle a une philosophie complètement différente. Par exemple il jette la prouvabilité et la raisonnabilité complètement par la fenêtre tout en mettant un grand accent sur une expressivité extrêmement élevée du langage.)

2
AnoE