Sempre me perguntei por que o Java não faz inferência de tipo, uma vez que a linguagem é o que é e sua VM é muito madura. O Google's Go é um exemplo de idioma com excelente inferência de tipo e reduz a quantidade de digitação necessária. Existe alguma razão especial por trás desse recurso não fazer parte do Java?
44
Respostas:
Tecnicamente falando, Java possui inferências de tipo ao usar genéricos. Com um método genérico como
O compilador analisará e entenderá que quando você escreve
Uma String será retornada para a primeira chamada e um Inteiro para a segunda chamada com base no que foi inserido como argumento. Você obterá a verificação adequada em tempo de compilação como resultado. Além disso, no Java 7, é possível obter algumas inferências de tipo adicionais ao instanciar genéricos como esse
Java tem a gentileza de preencher os colchetes angulares em branco para nós. Agora, por que o Java não suporta inferências de tipo como parte da atribuição de variáveis? Em um ponto, havia uma RFE para inferir tipos nas declarações de variáveis, mas isso foi fechado como "Não será corrigido" porque
O colaborador que encerrou isso também observou que parece "não-java", com o qual concordo. A verbosidade do Java pode ser uma bênção e uma maldição, mas torna a linguagem o que é.
É claro que aquela RFE em particular não foi o fim dessa conversa. Durante o Java 7, esse recurso foi novamente considerado , com algumas implementações de teste sendo criadas, incluindo uma pelo próprio James Gosling. Novamente, esse recurso foi finalmente derrubado.
Com o lançamento do Java 8, agora obtivemos inferência de tipo como parte de lambdas como:
O compilador Java é capaz de examinar o método
Collections#sort(List<T>, Comparator<? super T>)
e, em seguida, a interfaceComparator#compare(T o1, T o2)
e determinar isso,first
esecond
deve ser umString
, permitindo assim que o programador renuncie à necessidade de reafirmar o tipo na expressão lambda.fonte
First, the redundant type serves as valuable documentation - readers do not have to search for the declaration of getMap() to find out what type it returns
- sim, seHashMap<String, Integer> map = foo.getMap()
eu concordar - em C # normalmente não usovar
nesses casos, mesmo que pudesse. Mas esse argumento não retém a água se forHashMap<String, Integer> map = new HashMap<String, Integer>()
. Isso é redundância real e não vejo benefício em ter que escrever o nome do tipo duas vezes. E como eu me beneficiaria com uma verificação cruzada do compilador, eu não entendo nada.var
em Java.Humans benefit from the redundancy
é a verdadeira resposta para a pergunta atual, porque toda justificativa que li parece uma desculpa gratuita, infundada e ridícula para designers de Java: C # e C ++ têm o recurso, designers de C # e C ++ não são menos competentes do que Java e todos estão felizes em usá-lo. O que faz com que os desenvolvedores Java sejam diferentes dos desenvolvedores de C # ou C ++? É por isso que concordo com @KonradMorawski: "É assim que as coisas são feitas aqui" parece novamente ser a verdadeira razão dos bastidores para isso.Bem, primeiro, a inferência de tipo não tem nada a ver com a maturidade do tempo de execução, seja ele uma CPU de 30 anos ou uma VM tão nova que os bits ainda são brilhantes. é tudo sobre o compilador.
Dito isso, é permitido para genéricos, a razão pela qual não é permitido para tipos não genéricos parece ser por causa da filosofia - não há nada impedindo que os designers o adicionem.
Atualização: parece que o java 10 é compatível - http://openjdk.java.net/jeps/286
fonte
Até onde eu sei, quando o Java foi projetado no início dos anos 90, a inferência de tipo não era tão popular entre as linguagens convencionais (mas já era um conceito muito conhecido, por exemplo, no ML). Então, eu posso imaginar que a inferência de tipo provavelmente não era suportada porque o Java era destinado a programadores provenientes de C ++, Pascal ou outras linguagens mainstream que não possuíam (princípio de menor surpresa).
Além disso, um dos princípios de design do Java é escrever as coisas explicitamente para garantir que o programador e o compilador tenham o mesmo entendimento do código: duplicar informações reduz as chances de erros. Obviamente, pode ser uma questão de gosto se a digitação de mais alguns caracteres vale a segurança extra que ela oferece, mas essa foi a filosofia de design seguida para Java: escreva as coisas explicitamente.
Não sei se o Java obterá inferência de tipo no futuro, mas a IMO seria uma grande revolução para a linguagem (como Glenn Nelson mencionou, foi descrito como "não-java") e, em seguida, pode-se considerar a possibilidade de descartar o nomeie Java em favor de um novo nome.
Se você deseja usar um idioma da JVM com inferência de tipo, pode usar o Scala.
fonte
Eu posso pensar em algumas razões possíveis. Uma é que a digitação explícita é auto-documentada. Java geralmente faz disso uma prioridade sobre concisão. Outro motivo pode estar nos casos em que o tipo é um tanto ambíguo. Como quando um tipo ou qualquer subtipo pode satisfazer uma rotina. Digamos que você queira usar uma lista, mas alguém aparece e usa um método exclusivo para ArrayList. O JIT inferiria um ArrayList e continuaria mesmo se você quisesse um erro de compilação.
fonte
Let's say you want to use a List, but someone comes along and uses a method exclusive to ArrayList. The JIT would infer an ArrayList and carry on even if you wanted a compilation error
- Eu não entendo isso. A inferência de tipo ocorre no momento de instanciar uma variável, não chamando um método nela. Você poderia talvez mostrar um exemplo do que quis dizer?Isso contradiz a recomendação bem estabelecida de declarar variáveis usando a interface mais genérica que atenda às suas necessidades e inicializá-las com uma classe de implementação apropriada, como em
Efetivamente,
nada mais é do que açúcar sintático para
Se você desejar, seu IDE pode produzi-lo a partir da
new ArrayList<String>()
expressão com "um clique" (refatorar / criar variável local), mas lembre-se de que isso contradiz a recomendação "use interfaces".fonte