programas programa leer imprimir faciles ejercicios ejemplo datos java java-8 optional

leer - programas en java



¿Por qué se implementa Java 8 Opcional como final, sin la jerarquía Algunos y Ninguno? (2)

En Java, Optional se implementa como public final class Optional<T> { ... } y no como una jerarquía sellada de Some y None .

¿Por qué este no es el caso aquí? ¿Es esta una solución para la ausencia de sealed en Java? ¿Hay algún razonamiento más profundo detrás de esto?

Si echa un vistazo a las implementaciones de los métodos, verá que al ir de esta manera los casos presenta verificaciones de nulos feos:

public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); } }

No solo son feos, sino que si tiene una cadena de métodos más larga, isPresent deberá evaluarse durante cada llamada, incluso si la Optional está vacía desde el principio.

Si pudiéramos pasar una implementación fija a lo largo de la cadena, podría evitarse.

optional .map(i -> i) // isPresent() .map(Object::toString) // isPresent() .map(String::length) // isPresent() .map(...) // isPresent()

Pregunta

¿Por qué no se usaron subtipos para modelar casos vacíos y no vacíos?

No estoy preguntando específicamente por qué Optional es final, sino por qué no se implementó con Some y None , como hacen muchos otros idiomas, por lo que ¿Por qué se declara opcionalmente como clase final no es realmente útil?


De hecho, esta pregunta no es nueva. y Natpryce lo propone en su libro: Growing Object Oriented Software . El Maybe es más parecido a java.util.Optional pero representa 2 estados por polimorfismo. De hecho, es más rápido que Optional ya que aplica el Patrón de estado para transitar el estado present estado de absent solo una vez. lo que significa que el siguiente estado siempre está absent si el estado actual está absent .

Pero quiero decir otro escenario: el principio orientado a objetos: la ley de Demeter

  • Cada unidad debe tener un conocimiento limitado sobre otras unidades: solo unidades " estrechamente " relacionadas con la unidad actual.
  • Cada unidad solo debe hablar con sus amigos ; no hables con extraños
  • Solo habla con tus amigos inmediatos .

Como puede ver, el principio de LoD evitará que escriba un código de choque de trenes que haga que el código se ajuste y rompa la encapsulación, y que sea más difícil de cambiar y mantener.

En pocas palabras, si, de acuerdo con el principio de LoD, no debe escribir ningún map(one).map(another).map(...) llamadas en cadena en su programa. desde ese punto de vista, no hay ningún beneficio en introducir una jerarquía de herencia para representar su estado interno. Dado que el patrón de estado es más difícil de mantener si introduce un nuevo estado y más difícil para la depuración.

Entonces solo hay 2 comprobaciones adicionales en Optional que Maybe . uno es el map operación intermedia y flatMap , otro es la operación de terminal orElse , orElseGet y .etc. Así que no hay una gran ventaja para aplicar el patrón de estado en Optional .


El modificador final está allí en preparación para una característica más grande: tipos de valor , un objetivo para el Proyecto Valhalla (características para Java 10+).

Puede leer todo sobre los tipos de valor para Java en el artículo de 2014 vinculado a continuación:

Tipos de valor para Java

¿Por qué necesitamos tipos de valor en Java?

En Java, los objetos instanciados a partir de tipos de referencia tienen una identity . Esto permite que los objetos específicos sean referenciados por variables y comparados por referencia . Todas las clases / enum / interfaces actualmente crean tipos de referencia. Así, todos los objetos tienen una identidad .

Pero, en teoría, no todos los objetos requieren una identidad , como se menciona explícitamente en el documento de 2014 vinculado anteriormente:

La identidad del objeto sirve solo para admitir la mutabilidad , donde el estado de un objeto puede ser mutado pero sigue siendo el mismo objeto intrínseco.

Las identidades no son libres, y los tipos inmutables no requieren mutación, lo que inherentemente significa que no requieren identidades.

Las identidades para tipos inmutables resultan en una huella excesiva:

La identidad del objeto tiene costos de huella y rendimiento , lo cual es una de las razones principales por las que Java, a diferencia de otros lenguajes orientados a objetos, tiene primitivos.

Implementando tipos de valor

James Gosling escribió un artículo en 1999 sobre la compilación de tipos de tipos inmutables en valores:

Es casi posible, bajo la especificación de lenguaje actual, que un compilador de optimización lo suficientemente inteligente como para transformar ciertas clases en objetos ligeros que no estén asignados en el montón y se pasen por valor en lugar de por referencia: declare que la clase y todas sus variables de instancia son finales .

Esta idea ha sido heredada por el Proyecto experimental Valhalla de Oracle, liderado por Brian Goetz . En preparación, se ha creado una especificación para las clases basadas en el valor , uno de los requisitos es que la clase sea final .

El documento de 2014 sobre tipos de valor en Java expone aún más la decisión de hacer cumplir el requisito final :

¿Pueden los valores participar en los subtipos basados ​​en herencia? No

¿Puede una clase de valor ser abstracta o no final? No

La decisión de limitar o prohibir la subclasificación y subtipo de tipos de valor es necesaria para evitar el polimorfismo de puntero.

Por lo tanto, podemos garantizar que todos los métodos se resuelvan de manera inequívoca en el tipo exacto del receptor de métodos. Invocar un método de valor es siempre invocestático o invocador especial y nunca invocador o invocador.

Los tipos de valor no pueden participar en subtipos tradicionales (si es que serían limitados).

Entonces, ¿qué tiene esto que ver con Optional ?

Optional es una clase basada en el valor.

Se menciona cómo las clases basadas en valor pueden actuar como la versión en caja de los tipos de valor :

De hecho, parece probable que la forma en caja de cada tipo de valor sea una clase basada en el valor.

La forma en caja de un tipo de valor debe compartir los mismos atributos que los tipos de valor (similar a Integer para int ), que incluyen evitar que las clases tradicionales se subtitulen.