¿Por qué preferir un comodín a un discriminador de tipo en una API de Java (Re: Java efectivo)

8

En la sección de genéricos de Bloch's Effective Java (que es el capítulo "gratuito" disponible para todos: http://java.sun.com/docs/books/effective/generics.pdf ), dice:

Si un parámetro de tipo aparece solo una vez en una declaración de método, reemplácelo con un comodín.

(Ver páginas 31-33 de ese pdf)

La firma en cuestión es:

public static void swap(List<?> list, int i, int j)

vs

public static void swap(List<E> list, int i, int j)

Y luego procede a utilizar una función privada "auxiliar" estática con un parámetro de tipo real para realizar el trabajo. La firma de la función auxiliar es EXACTAMENTE la de la segunda opción.

¿Por qué es preferible el comodín, ya que NO necesita usar un comodín para hacer el trabajo de todos modos? Entiendo que en este caso ya que está modificando la Lista y no se puede agregar a una colección con un comodín ilimitado, entonces, ¿por qué usarlo?

Michael Campbell
fuente

Respuestas:

5

¿Por qué es preferible el comodín?

Creo que Josh lo dice claramente:

En una API pública, el [comodín] es mejor porque es más simple.

Es decir, para los usuarios de la API. La pequeña complejidad adicional en la implementación no es visible desde el exterior. Y como la implementación se escribe solo una vez, pero la API puede ser utilizada muchas veces por diferentes personas, simplificar la API a costa de hacer que la implementación sea un poco más compleja sigue siendo una victoria general.

> ¿Por qué usarlo?

¿Quieres decir por qué es mejor que

public static void swap(List list, int i, int j)

? Debido a que este último perdería los genéricos por completo, permitiendo que el compilador omita toda comprobación de tipos genéricos y permitiéndonos escribir código descuidado. Creo que es mejor usar firmas de tipo genérico, incluso si son tan generales, solo para mantener el hábito.

Actualización que se refleja en el comentario a continuación

Olvidó la declaración de parámetro genérico de la segunda firma, correctamente debería ser

public static <E> void swap(List<E> list, int i, int j)

Es decir, <E>aparece dos veces, sin beneficio adicional, frente a <?>aparecer solo una vez en la primera firma. Por eso es más simple.

Péter Török
fuente
1
No, ¿por qué es preferible intercambiar (Lista <?>, ...) a intercambiar (Lista <E>, ...). No veo por qué es más simple, en cualquier contexto.
Michael Campbell
1
Realmente no veo el beneficio. Para que un usuario use el método de intercambio, una llamada a cualquiera de las versiones public static <E> void swap (List <E> list, int i, int j) o public static void swap (List <?> List, int i, int j) buscaría exactamente lo mismo, es decir, swap (myList, 0, 1). Entonces, si el <E> aparece dos veces o si tiene un comodín en su lugar, realmente no importa en mi opinión. Tal vez me estoy perdiendo algo?
Será el
1
@Will, antes de llamar, usted (generalmente) lee la declaración de la API. La versión comodín de la declaración es (marginalmente) más simple para que nuestros cerebros la interpreten.
Péter Török
1
ok, entonces se trata realmente de esta pequeña simplificación. Gracias.
Será el
2
Tengo que estar de acuerdo con @Will, la simplificación es tan pequeña que casi no vale la pena hacerlo.
Andres F.