Ambiente
-
C# tem pregado o uso em um ambiente único, parece que Java tem buscado esse caminho também. Antes ambas tinham várias formas de executar seus códigos e apesar de ter algumas vantagens era bem confuso. Java tem muitos fornecedores e isso pode ser complicado. O Java que roda em certos ambientes não é o mesmo Java que roda em outros, ou seja, eles prometeram algo que não puderam cumprir.
-
Java tem um ambiente um pouco melhor desenvolvido, o JITter e o coletor de lixo e outros mecanismos são mais avançados. Por deficiências na linguagem eles precisam ser para não ficar pra trás. C# tem melhorado, mas de forma mais lenta por não ser tão necessário. Java tem mais opções alternativas.
-
É difícil afirmar qual é mais rápida, depende de cada caso, de como se faz os testes. É possível provar casos específicos, mas não no geral. O que pode valer em uma versão pode não ser verdade em outra. Mas em cada versão C# tem ficado melhor e cada vez é mais raro Java ter alguma vantagem.
-
O consumo de memória do Java é brutalmente maior. Não vou entrar em detalhes, cabe perguntas específicas, já tem alguma coisa no site.
-
C# possui muito mais metadados que Java.
-
Ambas possuem forte reflexão, mas o jeito de usar é bem diferente.
-
A serialização é feita de forma bem diferente (isso andou mudando e ainda mudará mais, C# tem/terá uma forma fantástica).
-
O sistema de segurança do ambiente é mais completo no C# (no .NET Framework).
-
O AOT do C# já está ficando muito bom, Java está se preparando.
-
Java tem virtual threads.
Tipagem
-
Em C# tudo deriva de
Object
, em Java os primitivos não. -
Java ainda não permite criar seus próprios tipos por valor (
structs
). Java só possui os poucos tipos primitivos prontos. Dizem que vai ter (há anos, nunca entregam), não sei o quanto poderá se integrar bem ao sistema de tipos atual. -
Por isso não tem tipos por referência que são alocados na pilha.
-
Java não permite criar tipos anônimos.
-
C# prefere que os tipos sejam por valor sempre que faça sentido, como o
DateTime
. Java coloca quase tudo como referência, que causa maior consumo de memória, processamento e pressão no GC. -
Java não possui tipos numéricos sem sinal.
-
Java não pode ligar e desligar a verificação de estouro numérico na linguagem.
-
Java pode garantir que o comportamento do ponto flutuante seja o mesmo em todas as plataformas (há consequências negativas).
-
Java só possui o tipo
decimal
na biblioteca e só na forma longa (ocupa mais memória). Existem alguns outros tipos que não existem na linguagem. -
C# possui arrays retangulares (multidimensionais).
-
C# não tem facilidades para fazer substring aproveitando a string já existente.Isso causa vazamento de memória. Java abandonou a prática, mas o custo de ter a facilidade permaneceu. C# agora tem facilidade mais correta que Java tentou adotar. -
Java não tem classes puramente estáticas, mas pode acessar membros estáticos diretamente pela instância enquanto C# só através de da classe (tem vantagens e desvantagens).
-
Os
enum
s do Java são mais orientados a objeto e mais fortemente tipados. Embora dê para simulá-los no C#, é ruim e o que a linguagem usa de fato, é pior que do Java em funcionalidade, mas melhor em eficiência. C# terá algo bem mais poderoso. -
Java não pode passar tipos "primitivos" por referência. Tem que encaixotar para fazer isso.
-
Java não tem tipos anuláveis, dá para simular, mas não é conveniente e a biblioteca não lida com isso então não teria muito valor.
-
Java não tem tipos e métodos parciais.
-
Java não permite mais de uma classe pública por arquivo.
-
Java não tem como ter tipos dinâmicos opcionais que só serão verificados em tempo de execução. Isso ajuda com interoperabilidade com outras linguagens e COM, por exemplo.
-
C# possui tuplas reais com membros nomeados permitindo retorno de múltiplos resultados em métodos, desconstrução e outros usos.
-
C# tem pattern matching bem poderoso e já avançado e melhora em cada versão. Java está soltando isso aos poucos.
-
C# e Java estão implantando records, C# está mais avançado e tem até
record struct
. -
C# está caminhando para ter roles e extensions, mas já tem algumas melhorias para dar mais semântica aos tipos e melhorar os contratos.
-
C# pode ter aliases de qualquer tipo.
-
C# permite usar array com alocação inline (como se fosse por valor).
-
C# deveria incorporar uma nova biblioteca de datas como Java fez.
Orientação a objeto
-
Java tem os métodos virtuais por default. C# escolheu não ter para facilitar a performance e encapsulamento. Poderia ter ido além e ter deixado a classe selada por default também, perdeu essa oportunidade.
-
Java tem classes escondidas e opcionalmente seladas com escolha do que pode herdar, que é bem interessante, C# deveria ter.
-
Em Java o override é implícito (há sintaxe para ajudar o compilador) ao passo que em C# precisa ser explícito.
-
Há diferenças de como corre o method hiding nas duas. O C# possui o
new
para explicitar isso. -
Java não chama finalizadores herdados.
-
Java não permite criar (sobrecarregar) operadores para os tipos. Com isso sobrecarrega-se :P a sintaxe do código. C# fez isso de uma forma melhor que do C++. O uso errado do recurso no C++ fez o Java não ter isso. Mas engenheiros devem encontrar solução, não abandonar o projeto. Inclui aí operadores de cast implícito e explícito.
-
Java não tem propriedades na linguagem, usa-se convenções.
-
Com isso Java não possui indexadores que é um operador sobrecarregado que funciona como uma propriedade.
-
C# não possui classes internas que é o que Java usa para simular a falta de delegados. Muito menos tem classes internas anônimas, até existe como aninhar classes, mas isto é feito de forma estática.
-
Java não tem métodos de extensão.
-
C# não pode declarar campos estáticos finais na interface, mas está previsto (tem parcialmente agora).
-
C# não tem métodos default dentro de interfaces. Tem que criar a interface e o método de extensão. Agora tem. -
C# permite implementar um método especificamente para uma interface.
-
Há diferença na ordem de inicialização de objetos e tipos.
-
Java não tem inicializadores de objetos e coleções.
Métodos
-
Java não possui parâmetros (default) e argumentos opcionais/nomeados.
-
C# não permite que os parâmetros originalmente mutáveis sejam declarados como imutáveis naquele contexto.
-
Java não possui métodos condicionais.
-
Java não possui funções locais.
-
Java não permite a passagem e retorno de tipos por valor como referência. C# já tem até campos por referência.
-
C# possui sintaxe simplificada para qualquer método de uma linha, incluindo propriedades, semelhante à lambda.
-
C# tem primary constructors
Exceções
-
C# não possui checked exceptions. Java é essencialmente a única linguagem que implementa isso. Mesmo entre os Javeiros não há consenso se é bom tê-las.
-
Java não possui filter exceptions.
-
Java tende a usar a exceção para controle de fluxo normal, C# evita isso, até porque seu mecanismo, quando gera exceção, é mais lento, algumas pessoas importam essa cultura do Java, mas isso é errado.
-
Em Java a exceção só pode ser um statement ao contrário de C# que pode ser uma expressão.
Funcional
-
O uso de lambdas do Java é bem mais limitado ao do C#. Melhoraram a sintaxe, mas não semântica. Isso foi o motivo do C# existir, mas não vou falar da briga entre a Sun e Microsoft aqui. Em C# melhora em cada versão.
-
Java não possui eventos. Tem que implementar o padrão Observer na mão, o que pode dar mais flexibilidade. Obviamente é possível fazer o mesmo em C#, se precisar.
-
Java não possui árvores de expressão.
-
Java não possui LINQ. Agora tem algo que ajuda um pouco (Java Streams), mas longe da facilidade total que o LINQ oferece. Vi coisas bem esquisitas em Java.
-
Java não possui geradores (iteradores).
-
Java possui só uma forma mais limitada de inferência de tipo.
Módulos
-
Todo o funcionamento de módulos de ambos é muito diferente. Java possui pacotes, C# possui namespaces e assemblies. O primeiro é para separar os tipos em grupos de nomes, de famílias. O outro funciona de forma semelhante ao pacote do java, mas não possui uma nomenclatura semântica na linguagem. A organização é mais flexível e não depende de como está implantado.
-
Com isso a visibilidade do C# pode ser restrita de forma mais granular.
-
Em C# os assemblies podem ser amigos de outros e permitir acesso extra.
-
Java não pode mudar o nome do pacote importado (alias) para facilitar o uso.
-
C# permite importação global.
-
C# permite não só não usar um namespace, mas até mesmo uma classe é opcional.
Operadores
-
Java não tem o operador
nameof
. -
C# possui dois tipos de cast explícito.
Facilidades extras
-
Java não possui diretivas de processamento condicional (
#if
). C# não possui um pré-processador, é integrado na linguagem e é limitado em relação ao que dá para fazer no C/C++. -
C# tem mais facilidades para trabalhar com assincronicidade, inclusive na linguagem.
-
Java pode ter métodos sincronizados pela linguagem, C# só pode ter blocos (ainda que possa ser o método todo) ou com o uso de bibliotecas ou anotações. No fundo parece ser só uma diferença sintática.
-
A genericidade do C# não usa type erasure, o que é uma grande ajuda para performance e uso geral. Há uma semântica de genericidade, enquanto que no Java é só um truque do compilador. Me parece que a restrição de variância ocorre no local certo.
-
C# permite mais usos, variedade de tipos e restrições nos tipos genéricos.
-
Java não pode fazer interpolação de string. Nem tem verbatim strings (passou ter alguma coisa).
-
Java não tenta simplificar a sintaxe de muitas coisas, especialmente de métodos de uma linha que em C# pode usar a sintaxe de lambda, mesmo não sendo.
-
Java não suporta
goto
, apesar de tê-lo como palavra-chave. -
C# pode ser compilado em tempo de execução, tem um sistema de scripting e um REPL. O .NET Compiler Platform é um avanço para a linguagem, biblioteca e para facilitar o aumento de todo o ecossistema de ferramentas. Java permite alguma coisa nesse sentido de forma bem mais limitada.
-
Java não permite código unsafe o que dificulta a interoperabilidade com outras linguagens e performance em algumas situações. Java possui JNI para interoperabilidade. É raro quem ache isto uma boa solução. Alguns acham ruim permitir ter código inseguro na linguagem e que isto faz a linguagem ser menos segura, mas está longe de ser verdade, a pessoa precisa entender melhor o recursos para criticar. Eu nunca usei de fato o unsafe, mas adoro saber que ele está lá quando eu precisar. Java tem um projeto para melhorar isso, mas não terá como ser tão bom pela limitação da linguagem atual. Tem algumas melhorias mais recentes. C# está melhorando cada vez mais.
-
Então Java não pode usar ponteiros, nem gerenciados em áreas específicas, como são em C# em casos pontuais onde eles são mais adequados. E C# tem introduzido mecanismos cada vez melhores onde usa a vantagem do ponteiro sem ter a desvantagem.
-
Java possui soft/phantom references.
-
Java não faz otimização de tail recursion. C# faz em x64 (não sei se já tem em x86 ou ARM).
-
C# permite representação de literais binários e uso de separadores para melhor legibilidade.
-
C# tem o
switch
com expressão, Java está começando ter. -
C# tem um mecanismo de assincronicidade que é referência no mercado, Java promete que terá algum mecanismo que servirá para o mesmo propósito.
-
Java parece estar um passo adiante no uso de NVM. Isso pode ser ruim porque ainda não se sabe a melhor forma de usar essa nova tecnologia.
-
C# tem geradores de código que está ajudando revolucionar alguns códigos.
-
C# tem feito uma quantidade imensa de pequenas melhorias sintáticas e algumas semânticas, Java vai bem mais devagar nisso, tem feito muito preview antes de lançar algo.
-
Java tem um garbage collector mais sofisticado, até porque a linguagem gera muito mais lixo que C#.