Por que preferir um curinga a um discriminador de tipo em uma API Java (Re: Effective Java)

8

Na seção de genéricos do Effective Java de Bloch (que é o capítulo "gratuito" disponível para todos: http://java.sun.com/docs/books/effective/generics.pdf ), ele diz:

Se um parâmetro de tipo aparecer apenas uma vez em uma declaração de método, substitua-o por um curinga.

(Veja as páginas 31-33 do pdf)

A assinatura em questão é:

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

vs

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

E, em seguida, passa a usar uma função "auxiliar" privada estática com um parâmetro de tipo real para executar o trabalho. A assinatura da função auxiliar é EXATAMENTE a da segunda opção.

Por que o curinga é preferível, pois você NÃO precisa usá-lo para concluir o trabalho? Entendo que, nesse caso, como ele está modificando a lista e você não pode adicionar a uma coleção com um curinga ilimitado, então por que usá-la?

Michael Campbell
fonte

Respostas:

5

Por que o curinga é preferível

Eu acredito que Josh afirma claramente:

Em uma API pública, o [curinga] é melhor porque é mais simples.

Ou seja, para os usuários da API. A pequena complexidade extra na implementação não é visível de fora. E como a implementação é escrita apenas uma vez, mas a API pode ser usada muitas vezes por muitas pessoas diferentes, simplificar a API ao custo de tornar a implementação um pouco mais complexa ainda é uma vitória geral.

> por que usá-lo?

Você quer dizer, por que é melhor do que

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

? Como o último perderia os genéricos por completo, deixando o compilador omitir toda verificação de tipo genérico e permitindo escrever código incorreto. Eu acho que é melhor usar assinaturas de tipo genérico, mesmo que sejam tão gerais, apenas para manter o hábito.

Atualização refletida no comentário abaixo

Você esqueceu a declaração de parâmetro genérica da segunda assinatura, corretamente deve ser

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

Ou seja, <E>aparece duas vezes, sem benefício adicional, <?>comparando apenas uma vez na primeira assinatura. É por isso que é mais simples.

Péter Török
fonte
1
Não, por que o swap (Lista <?>, ...) é preferível ao swap (Lista <E>, ...). Não vejo por que é mais simples, em qualquer contexto.
Michael Campbell
1
Realmente não vejo o benefício. Para que um usuário use o método swap, uma chamada para a versão estática pública <E> void swap (lista <E> lista, int i, int j) ou para a estática pública void swap (lista <?> List, int i, int j) ficaria exatamente igual, ou seja, swap (myList, 0, 1). Portanto, se o <E> aparece duas vezes ou com um curinga, isso realmente não importa na minha opinião. Talvez esteja faltando alguma coisa?
Will
1
@ Antes de ligar, você (geralmente) lê a declaração da API. A versão curinga da declaração é (marginalmente) mais simples para nosso cérebro interpretar.
Péter Török
1
ok, é realmente sobre essa pequena simplificação. obrigado.
Will
2
Eu tenho que concordar com @Will, a simplificação é tão pequena que dificilmente parece valer a pena.
Andres F.