¿Por qué Java tiene métodos 'nulos'?

52

¿Tiene / por qué Java necesita tener los métodos void ? Referencia :

  

Cualquier método declarado vacío no devuelve un valor.

Por lo que puedo pensar, cada uso de void se servirá mejor devolviendo un indicador de estado, el objeto que se invoca, o null .

Esto haría de cada llamada una declaración asignable, y facilitaría los patrones de construcción y el encadenamiento de métodos. Los métodos que solo se invocan para sus efectos generalmente devolverán un tipo booleano o genérico Success o lanzarán una excepción en caso de error.

    
pregunta marisbest2 24.04.2017 - 16:09

9 respuestas

159

Debido a que existe una diferencia entre "Esta función puede tener éxito o fallar y es lo suficientemente consciente de sí misma como para poder distinguir la diferencia" y "No hay comentarios sobre el efecto de esta función". Sin void , verificará sin cesar los códigos de éxito y creerá que está escribiendo un software robusto, cuando en realidad no está haciendo nada por el estilo.

    
respondido por el Kilian Foth 24.04.2017 - 16:19
96
  1. Porque C tiene un tipo void y Java fue diseñado para seguir muchas de las convenciones de la familia del lenguaje C.
  2. Hay muchas funciones que no desea que devuelvan un valor. ¿Qué vas a hacer con "un tipo genérico Success " de todos modos? De hecho, los valores de retorno para indicar el éxito son aún menos importantes en Java que en C, porque Java tiene excepciones para indicar el fracaso y C no.
respondido por el Mason Wheeler 24.04.2017 - 16:14
65

El original por el cual el idioma tiene un tipo void se debe a que, como en C , los creadores del idioma no quisieron complicar innecesariamente la sintaxis del idioma con Los procedimientos s y funcionan s como lo hizo Pascal.

Esa fue la razón original.

Tus sugerencias:

  

devolver un indicador de estado

Eso es un no-no. No utilizamos banderas de estado. Si algo sale mal, lo informamos a través de excepciones.

  

el objeto que se invoca

El estilo fluido de invocaciones es un desarrollo reciente. Muchos de los programadores que hoy están muy contentos de usar fluidez y poner los ojos en blanco si alguna vez tienen que usar una interfaz que no la admite ni siquiera nacieron cuando se creó Java.

  

devolviendo nulo

Eso te obligaría a declarar que un método devuelve algo, cuando en realidad no está devolviendo nada, por lo que sería muy confuso para alguien que está mirando una interfaz intentando averiguar qué es lo que hace. La gente inevitablemente inventaría alguna clase que de otra manera sería inútil que significa "sin valor de retorno", de modo que todas las funciones que no tienen nada que devolver pueden devolver una referencia nula a dicha clase. Eso sería torpe. Afortunadamente, hay una solución para esto, se llama void . Y esa es la respuesta a tu pregunta.

    
respondido por el Mike Nakis 24.04.2017 - 21:07
20

Algunos métodos, como System.out.println , no devuelven nada útil, pero se llaman únicamente para este efecto secundario. void es un indicador útil para el compilador y para el lector de código que no se devuelve ningún valor útil.

Devolver null en lugar de void significa que solo obtendrías NullPointerException en el momento en que uses este valor para cualquier cosa. Así que intercambias un error de tiempo de compilación por un error de tiempo de ejecución que es mucho peor. Además, tendría que definir el tipo de retorno como Object , lo que sería engañoso y confuso. (Y el encadenamiento aún no funcionaría).

Los códigos de estado generalmente se usan para indicar condiciones de error, pero Java tiene excepciones para este propósito.

No es posible devolver this desde métodos estáticos.

Devolver un objeto genérico Success no tendría un propósito útil.

    
respondido por el JacquesB 24.04.2017 - 21:48
11

Una razón es que puede ser engañoso devolver cualquier cosa que no sea, por ejemplo, null . Ejemplo:

¿Qué debería devolver Arrays.sort(a) ?

Si argumenta que a debe devolverse para que la llamada se pueda encadenar (lo que parece ser su respuesta a juzgar por su pregunta), ya no está claro si el valor de retorno es una copia del objeto original, o el objeto original mismo. Ambos son posibles. Y sí, podría ponerlo en la documentación, pero es lo suficientemente ambiguo como para no crear la ambigüedad en primer lugar.

Por otro lado, si argumenta que se debe devolver null , eso plantea la pregunta de qué información es posible que el valor devuelto le proporcione al llamante, y por qué el programador debe ser forzado a escribir return null cuando transmite no hay información.

Y si devuelves algo completamente absurdo (como la longitud de a ), entonces el uso de ese valor de retorno es realmente confuso, solo piensa en lo mucho más confuso que es decir int len = Arrays.sort(a) en lugar de int len = A.length !

    
respondido por el Mehrdad 26.04.2017 - 01:46
7

Devolver un boolean que siempre es igual a true que sugieres, no solo no tiene sentido (el valor devuelto no contiene información), sino que en realidad sería engañoso. La mayoría de las veces, es mejor usar tipos de devolución que solo lleven tanta información como esté realmente disponible; por eso, en Java tiene boolean para true / false en lugar de devolver un int con 4 mil millones posibles valores. Del mismo modo, devolver un boolean con dos valores posibles donde solo hay un valor posible ("éxito genérico"), sería engañoso.

También agregaría una sobrecarga de rendimiento innecesaria.

Si un método se usa solo por su efecto secundario, no hay nada que devolver, y el tipo de retorno void refleja exactamente eso. Los errores raros potenciales se pueden señalar a través de excepciones.

Una cosa que podría mejorarse, sería hacer que void sea un tipo real, como el Unit de Scala. Esto resolvería algunos problemas, como el manejo de genéricos.

    
respondido por el Michał Kosmulski 24.04.2017 - 19:12
4

Java es un lenguaje relativamente antiguo. Y en 1995 (cuando se creó) y poco después, los programadores estaban muy preocupados por la cantidad de tiempo que un proceso tomaba el control del procesador y el consumo de memoria. Devolver el vacío eliminaría algunos ciclos de reloj y un poco de consumo de memoria de una llamada de función porque no tendría que poner el valor de retorno en la pila, y posteriormente no tendría que eliminarlo.

El código eficiente no le devuelve algo que nunca usaría y, por lo tanto, anular algo que tiene un valor de retorno sin sentido es una práctica mucho mejor que devolver un valor de éxito.

    
respondido por el The Lazy Coder 24.04.2017 - 19:12
2

He leído argumentos que sugieren que la segunda opción (devolver this ) debería ser el enfoque en lugar de void . Esta es una idea bastante buena, pero el enfoque de estilo de constructor no era popular en el momento de la creación de Java. Si era tan popular en ese momento como lo es ahora, ese podría haber sido el enfoque adoptado. Devolver null es una idea realmente mala de la OMI. Ojalá null ni siquiera estuviera en el idioma.

El problema ahora es que si un método devuelve una instancia de su propio tipo, no está claro si es un objeto nuevo o el mismo. A menudo no importa (o no debería), pero otras veces sí importa. Supongo que el idioma podría cambiarse para devolver implícitamente this en los métodos void. El único problema que se me ocurre con eso en este momento es que si el método se cambiara más tarde para devolver un nuevo objeto del mismo tipo, no habría advertencias de compilación, pero tal vez eso no sea un gran problema. El sistema de tipos actual no se preocupa por estos tipos de cambios ahora. La forma en que esto interactúa con la herencia / interfaces necesitaría cierta consideración, pero permitiría que las API antiguas sin un estilo de constructor se llamen fácilmente como si lo hicieran.

    
respondido por el JimmyJames 24.04.2017 - 18:36
2

Otro aspecto:

Java es un lenguaje estático con características bastante estrictas. Esto significa que muchas cosas que serían bastante abiertas o dinámicas en otros idiomas (c / f Ruby, Lisp, etc.) están estrictamente determinadas.

Esta es una decisión de diseño general. El "por qué" es difícil de responder (bueno, ¡porque los diseñadores del lenguaje pensaron que sería bueno!). El "para qué" está bastante claro: le permite al compilador detectar un lote de errores, lo que generalmente es una característica bastante buena para cualquier idioma. En segundo lugar, hace que sea relativamente fácil razonar sobre el idioma. Por ejemplo, es relativamente fácil crear pruebas formales de corrección en (subconjuntos de) el lenguaje Java; como comparación, eso sería prácticamente imposible en un lenguaje dinámico como Ruby et al.

Este pensamiento impregna el lenguaje, por ejemplo, la declaración forzada de posibles excepciones que un método puede lanzar, el tipo separado de interface vs. class para evitar la herencia múltiple ambigua, y así sucesivamente. Para lo que es (un lenguaje del mundo real OOP imperativo estático con un fuerte enfoque en el manejo de errores de tiempo de compilación) esas cosas son bastante elegantes y potentes. Se acercan más a los lenguajes teóricos (científicos) diseñados específicamente para explorar algunos de estos problemas que cualquier otro lenguaje del mundo real anterior (en ese momento, imagínense).

Entonces. Tener un tipo void estricto es un mensaje claro: este método no devuelve nada, punto. Es lo que es. Reemplazarlo por la aplicación para devolver siempre algo llevaría a un comportamiento mucho más dinámico (como en Ruby donde cada def tiene un valor de retorno explícito o implícito, siempre), lo que sería malo para la probabilidad y el razonamiento ; o para la hinchazón masiva utilizando algún otro mecanismo aquí.

(Y NB, Ruby (por ejemplo) maneja esto de manera diferente, y su solución sigue siendo exactamente tan aceptable como la de Java, ya que tiene una filosofía completamente diferente. Por ejemplo, ofrece probabilidad y razonabilidad por completo. por la ventana mientras pone un gran enfoque en la expresividad extremadamente alta del lenguaje.)

    
respondido por el AnoE 25.04.2017 - 16:50

Lea otras preguntas en las etiquetas

Comentarios Recientes

¿Por qué Java no admite 2D? Java 8 trajo consigo la promesa de la noción siempre popular de implicits. Implicits abre un espacio conceptual completamente nuevo para describir a aquellos que escriben código de larga ejecución, como se muestra a continuación. ¿Modificador implícito vs. implícito? Un ejemplo de la diferencia entre los métodos modificadores "implícitos" e "implícitos": - Mi clase declara la palabra clave de anulación del operador de anulación interna. clase privada Foo {...} // X depende de... Lee mas