Esta minha comparação vem no seguimento do tópico Why Mono? que coloquei no Gildot.
Bem, acho que vou tentar expor algumas das coisas que me fazem preferir o .NET. Espero que respostas a este post não sejam flames, e que sejam bem fundamentadas, como eu vou tentar fazer! :-) Infelizmente o Java parou no tempo... mas acho que tou a gente tem a lucrar se o Java melhorar e continuar a ser forte concorrente do .NET.
1. Checked Exceptions
As checked exceptions são aquelas excepções que somos obrigados a apanhar, e elas não existem no .NET. Porquê? Problemática de versões e manuntenção do código. Neste artigo do designer principal do C#, ele explica a fundo o porquê do C# não ter checked exceptions. Lendo com atenção só lhe podemos dar razão. O Bruce Eckel com o seu artigo Does Java need Checked Exceptions?, também dá a sua opinião sobre este tema. Contudo, embora estes dois artigos possam convencer muita gente, nas respostas ao artigo do Bruce Eckel logo vemos outros excelentes exemplos em como as checked exceptions são claramente necessárias em ambientes com vários programadores. Eu acho que as checked exceptions são necessárias, mas acho que o modelo do Java não é o melhor, pois conduz à má programação. Quem nunca engoliu uma excepção só porque não dava jeito apanhá-la? Mais sobre isto Ask a Language Designer: Why doesn't C# have exception specifications?
Nota: Um membro do gildot mostrou a sua maneira de tratar as excepções, que considero muito boa programação:
void myJavaMethod(int aX) throws BMFException
{
try {
//blablabla que faz o throw de um BMFException
} finally {
//código de limpeza aqui
}
}
2. Delegates vs Pattern Observer no Java
Os delegates são simplesmente pointers para métodos. Quando dei Java, eu achei brilhante o modelo de tratamento de eventos. Cria-se uma classe anónima, adiciona-se ao evento e puff, já está. Com o tempo, realmente comecei a ficar farto de ter no construtor tanto código devido a tratamento de eventos. Ainda para mais temos de tar a criar interfaces e/ou classes(Adaptadores...) para os nossos eventos, uma interface por evento? Agrupamos todos os eventos na mesma? E depois temos de tar com os adaptadores? Acho que é um pouco de mais do que é preciso. O problema é que a classe cliente tem de conhecer o evento, tem de implementar a interface (Inner classes ajudam). Em .NET basta registar um delegate(pointer) para um método... mais nada. Além disso os delegates são criados em compile time, se forem relativos a um método virtual, apontam logo para o método específico, por isso esse nível de indirecção vem de graça. E para iterar sobre eles não é preciso os casts normais que é preciso para os eventos no Java. Por isso os delegates são mais eficientes, até podem ser mais eficientes do que chamar um método virtual.
3. Virtual e Override
Em Java todos os métodos são virtuais. Será que sendo tudo virtual, os programadores de Java se lembram que os métodos virtuais são mais caros, e marcam como final aqueles que não precisam de ser virtuais? Não... É raro ver isso, e mesmo que os haja, tem de partir do programador, não é algo explícito na linguagem. Por isso em .NET todos os métodos por defeito são não virtuais. Se queremos polimorfismo então declaramos explicitamente. Este problema do plimorfismo por defeito em Java ainda traz mais problemas quando se trata de versões, como este
exemplo pode clarificar e bem.
Nota, um membro do Gildot alertou-me que a questão do final não é assim como eu a pintei. De facto o final é desencorajado no Java, é a VM que verifica se um método tem de ser virtual, e se não for, automaticamente o classifica como final e até o pode usar para fazer inline. Sim, é uma óptima ideia, mas é algo complexo de implementar, pois significa que se tem de re-JITar o código assim que uma nova classe é carregada, que deriva da class cujos métodos estavam marcados como hipoteticamente não virtuais. E isto é pesado.
4. Genéricos em .NET e em Java
Um dos problemas, quer do Java, quer do .NET, é o boxing e unboxing. Boxing é um termo que vi pela primeira vez no .NET que se refere à passagem de um tipo valor para um tipo referência, por exemplo em Java não podemos ter tipos valores nos contentores como o ArrayList, temos de criar um Integer (tipo referência), para alojar o tipo valor(int). O unboxing é a operação inversa. De facto o .NET faz isto automaticamente por nós, visto que em .NET podemos nós fazer os tipos valor que quisermos (em certas ocasiões são muito eficientes). Esta introdução foi mais porque, tanto em JAva, como em .NET, os genéricos dão mais jeito é para tipos valor, é onde se consegue melhor optimização. Em .NET, os genéricos são resolvidos em Runtime, se o JIT vê uma classe template, instancia um tipo correspondente. Ou seja podemos ter um ArrayList, e temos a certeza de que não há boxes e que defacto temos um contentor de ints, ponto. Os genéricos em .NET vão aparecer na próxima versão, e acho que vão trazer um autêntico boost de performance à paltaforma. Isto porque há Hashtables e coisas do género que precisam mesmo de tipos valor, e que perdem muito em eficiência por haver o boxing.
Bem, em .NET, os genéricos até são bacanos. E em Java? Em Java os genéricos infelizmente serão só syntax sugar. O que temos com ArrayList a;é só a facilidade sintática de trabalhar com inteiros. Se iterarmos pela lista, podemos fazer int x = a.get(0); temos um inteiro, mas o problema é que lá por baixo há todos os casts necessários, há todo o processo de boxing/unboxing necessários... O problema é que eles quiserem acrescentar genéricos sem alterar a VM, e assim há limitações visíveis. Podem ver uma comparação mais exaustiva sobre os genéricos em .NET, Java e até C++ aqui.
5. foreach, propriedades, atributos e XML
Digam o que quiserem, o foreach é algo excelente. Aumenta a produtividade e bem, só não vê isso que nunca usou o foreach -- pelo que ouvi dizer o foreach vai ser implementado no Java. As propriedades são outra coisa muito boa. Eu estava muito habituado aos get's do Java, e custou-me a entrar neste conceito de propriedades, mas agora acho-as muito necessárias, tanto a nível de uso, como a nível de gestão das nossas classes. E por último os atributos: os atributos permitem-nos expandir a metadata das nossas classes/métods/whatever, permitindo-nos fazer tudo o que quisermos. Um bom exemplo é o XmlSerializer do .NET, basta ter uma classe, dizer que ela é serializável (com o atributos Serializable), e passá-la ao XmlSerializer e puff: fez-se a serialização - nada a ver com o processo de serialização do Java. Isto é só um exemplo do uso de atributos. E digo: nem se compara o tratamento de XML em .NET com o de Java, eu tive de fazer uns quantos leitores de XML com o SAX e pah... simplesmente não tem comparação.
Nota: Naturalmente que comparar o DOM com o SAX é comparar batatas com presunto. Se alguém me puder dar uma visão actual do XML em Java, agradecia.
6. Invocação Nativa
Quem usou o JNI sabe o pesadelo que aquilo é. Nem se compara com a facilidade de interoperabilidade do .NET com DLLs e até com COM. Supostamente o Java não precisaria de JNI, que põe em causa a portabilidade do código. Mesmo assim às vezes é necessário por motivos de performance, ou outros.
7. Assembly
Aqui é mais o assembly vs package. Acho que ter uma unidade mínima de armazenamento de código é bom, e está muito melhor conseguido em .NET com os assemblies e com os módulos. Sem bem que isto seja relativo, e aqui não tenho muitos argumentos, além de dizer que é o que eu prefiro. Em Java, andar com os .class, ou até com os .jar atrás chatiava-me. Prefiro tudo organizado em Assemblies, que posso muito simplesmente incluir noutros projectos.
8. Múltiplas Linguagens
Podemos ter um Assemlby com módulos em várias linguagens. De notar a facilidade te ter por exemplo, o módulo de UI em C#, e ter um módulo lógico em Haskell.NET ou Sheme.NET, e ter ainda outro módulo em Managed C++ em que interagimos com o Sistema operativo muito melhor. E isto tudo é compilado para IL (os byte codes do .NET) e fica tudo num assembly pronto a usar, sem termos ideia de como foi implementado.
--
E pronto, não me lembro de mais nada por agora. :-) Está aqui um artigo com 10 razões para usar o C#, tem algumas coisas que eu disse, mas tem outras também, com exemplos e tudo. Também está aqui a thread no Gildot com esta opinião e respectivas respostas. Nota que eu não quero com esta comparação dizer que o Java é a pior coisa que existe... eu aprecio muito o Java, mas tem os seus defeitos e parou no tempo. Contudo acho que há espaço para ambas as tecnologias e acho que todos temos a lucrar com isso.
posted on Saturday, March 06, 2004 1:57 PM