C# e Java são parentes próximos. As duas são linguagens com tipagem estática, orientadas a objetos, com garbage collector e sintaxe no estilo C, as duas compilam para bytecode de uma máquina virtual e as duas são usadas em grandes sistemas de backend. C# foi lançada em 2002 em parte como a resposta da Microsoft ao Java, e em duas décadas as duas pegaram recursos uma da outra (lambdas, genéricos, records, pattern matching). Um desenvolvedor que conhece uma consegue ler a outra quase imediatamente.
As diferenças que importam no dia a dia são menores e mais específicas. Esta página passa por elas com código: trechos em C# que você pode executar, e Java em blocos estáticos para comparação.
Visão geral
| C# | Java | |
|---|---|---|
| Criada por | Microsoft (2002) | Sun Microsystems (1995), hoje Oracle |
| Runtime | CLR (.NET), compila IL para código nativo | JVM, compila bytecode para código nativo |
| Plataformas | Windows, Linux, macOS | Windows, Linux, macOS |
| Propriedades | Embutidas: public int Age { get; set; } | Métodos getter e setter |
| Tipos de valor definidos pelo usuário | struct | Ainda não (Project Valhalla) |
| Genéricos | Reificados: os tipos existem em tempo de execução | Apagados: os tipos são removidos depois da compilação |
| Consultar coleções | LINQ | API de Streams |
| Async | async / await | Virtual threads (Java 21), CompletableFuture |
| Exceções checadas | Não | Sim |
| Sobrecarga de operadores | Sim | Não |
| Segurança contra null | Tipos de referência anuláveis (C# 8) | Optional<T>, anotações |
| Principais usos | Jogos na Unity, ASP.NET Core, desktop Windows, Azure | Backends corporativos, Android, big data |
Sintaxe: quase igual
Classes, métodos, if, for, while, switch, try/catch se leem quase da mesma forma. As diferenças visíveis são as convenções de nomes e algumas palavras-chave: métodos em C# usam PascalCase (ToUpper, WriteLine), métodos em Java usam camelCase (toUpperCase, println); C# escreve string e bool, Java String e boolean; herança é class Dog : Animal em C# e class Dog extends Animal em Java.
// Java
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Ana");
names.add("Ben");
for (String n : names) {
System.out.println(n.toUpperCase());
}
}
}
Saída:
ANA
BEN
C# também compara strings por valor com ==, o que elimina um dos bugs clássicos de iniciante em Java: lá, == entre dois objetos String compara referências, então duas strings iguais montadas em tempo de execução (lidas da entrada, concatenadas) podem ser consideradas diferentes.
Propriedades em vez de getters e setters
Classes Java expõem estado por métodos getName() e setName(), normalmente gerados por uma IDE ou pelo Lombok. C# tem propriedades: membros que se leem como campos, mas executam código.
// Java
public class Product {
private double price;
public double getPrice() { return price; }
public void setPrice(double price) {
if (price < 0) throw new IllegalArgumentException("negative");
this.price = price;
}
}
Saída:
Mug: 9.50
O inicializador de objeto new Product { Name = ..., Price = ... } define propriedades logo depois da construção. Os records do Java (Java 16) cobrem o caso de dados imutáveis; C# também tem records (C# 9), além de propriedades para todo o resto.
Tipos de valor: structs
Em Java, todo tipo definido pelo usuário é um tipo de referência guardado no heap; só os oito primitivos (int, double, ...) são valores. C# permite definir seus próprios tipos de valor com struct. Uma struct é copiada na atribuição e pode ficar embutida em arrays e em outros objetos, sem uma alocação separada no heap.
Saída:
a = (1, 2)
b = (99, 2)
1000
Isso importa em jogos e em código numérico, em que milhões de objetos pequenos pressionariam o garbage collector. Veja structs.
Genéricos: reificados vs apagados
Java apaga os argumentos de tipo genéricos em tempo de compilação: em tempo de execução, uma List<Integer> é só uma List, e List<int> não é permitido (você recebe objetos Integer com boxing). C# mantém os argumentos de tipo em tempo de execução, então List<int> guarda ints puros e o código pode perguntar o que T é.
Saída:
3 items of type Int32
1 items of type String
List`1
typeof(T) e new T() funcionam porque o runtime conhece T. Em Java os dois são erros de compilação, e a solução usual é passar um objeto Class<T> adiante.
LINQ vs streams
As duas linguagens têm uma API fluente para filtrar e transformar coleções. A do Java é a API de Streams (Java 8); a de C# é o LINQ (C# 3), que também tem uma sintaxe de consulta e funciona com bancos de dados por meio do Entity Framework.
// Java
List<String> expensive = products.stream()
.filter(p -> p.getPrice() > 20)
.sorted(Comparator.comparing(Product::getPrice))
.map(Product::getName)
.collect(Collectors.toList());
Saída:
Lamp, Chair
Total: 126
As operações se correspondem uma a uma (filter é Where, map é Select, collect(toList()) é ToList()), e as versões em C# não precisam de stream() nem de coletor. Os objetos new { Name = ..., Price = ... } são tipos anônimos, que não têm equivalente direto em Java.
Async e concorrência
C# introduziu async/await em 2012: um método async retorna uma Task, e await o suspende sem bloquear uma thread. JavaScript, Python e Rust adotaram depois as mesmas palavras-chave. Java seguiu outro caminho: cadeias de CompletableFuture e, desde o Java 21, virtual threads que tornam barato o código bloqueante comum.
// C#
async Task<string> LoadAsync(HttpClient http, string url)
{
string body = await http.GetStringAsync(url);
return body.Substring(0, 100);
}
// Java 21 with virtual threads: plain blocking code on a cheap thread
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> client.send(request, BodyHandlers.ofString()));
}
As duas abordagens escalam para muitas requisições concorrentes. C# deixa a assincronia visível nas assinaturas dos métodos; Java a esconde no runtime.
Exceções, operadores e diferenças menores
- Exceções checadas. Java obriga um método a declarar ou capturar certas exceções (
throws IOException). C# não tem exceções checadas. - Sobrecarga de operadores. C# permite que tipos definam
+,==,<e parecidos, e é por isso que a aritmética comdecimaleDateTimese lê naturalmente. Java não permite (BigDecimal.add). - Virtual por padrão. Métodos Java podem ser sobrescritos a menos que sejam
final; métodos C# precisam ser marcados comovirtualpara poderem ser sobrescritos, e a sobrescrita precisa dizeroverride. - Métodos de extensão. C# pode adicionar métodos a tipos existentes (
"text".IsPalindrome()); Java não. - Tipos de valor anuláveis.
int?em C# é um int que pode ser null; Java usa oIntegercom boxing. - Tipos sem sinal. C# tem
uint,ulong,ushorte umbytesem sinal; obytedo Java tem sinal e, fora ocharde 16 bits, Java não tem tipos inteiros sem sinal.
Ecossistema, vagas e qual aprender
O ecossistema do Java é maior no mundo open source de servidores: Spring, Kafka, Spark, Hadoop, Elasticsearch e a maioria dos projetos Apache são em Java. Apps Android são escritos em Kotlin ou Java. C# tem a pilha mais integrada: um único fornecedor mantém a linguagem, o runtime, o framework web (ASP.NET Core), o ORM (Entity Framework) e a IDE principal (Visual Studio), e a Unity a coloca no centro do desenvolvimento de jogos.
As duas linguagens têm mercados de trabalho grandes, e o equilíbrio entre elas depende da região e do setor. C# é forte em empresas construídas sobre Microsoft e Azure, em software de finanças e saúde e em estúdios de jogos.
Escolha C# se você quer fazer jogos na Unity, construir apps desktop para Windows ou trabalhar em uma empresa .NET. Escolha Java se o seu alvo é Android, big data ou uma empresa cujo backend roda na JVM. Qualquer uma das duas ensina os conceitos de que você precisa para a outra: classes, interfaces, genéricos, coleções, exceções e um runtime com garbage collector.
Perguntas frequentes
C# é parecido com Java?
Sim, muito. As duas são linguagens com tipagem estática, orientadas a objetos, com garbage collector e sintaxe no estilo C, que compilam para bytecode de uma máquina virtual. Um desenvolvedor Java consegue ler C# no primeiro dia. As diferenças estão nos detalhes: C# tem propriedades, tipos de valor definidos pelo usuário, genéricos reificados, LINQ e async/await, enquanto Java tem exceções checadas e um ecossistema open source de servidor maior.
Devo aprender C# ou Java primeiro?
Escolha pelo que você quer construir. C# para jogos na Unity, apps desktop para Windows e empresas construídas sobre Microsoft e Azure. Java para Android (junto com Kotlin), grandes backends corporativos e ferramentas de big data como Kafka e Spark. As linguagens são próximas o bastante para que trocar depois leve semanas, não meses.
C# é mais rápido que Java?
Elas estão na mesma classe de desempenho: as duas fazem compilação JIT para código nativo e usam garbage collectors geracionais. C# dá mais controle de baixo nível com structs, Span<T> e genéricos sobre tipos de valor sem boxing, o que ajuda em código com muitas alocações. Em cargas web típicas, o framework e o banco de dados importam muito mais que a linguagem.
C# tem exceções checadas como Java?
Não. Em C#, nenhum tipo de exceção precisa ser declarado ou capturado; a assinatura de um método não lista o que ele lança. Os projetistas concluíram que exceções checadas levavam a blocos catch vazios e a assinaturas frágeis. Você documenta as exceções com comentários XML /// <exception>.
Qual tem mais vagas, C# ou Java?
As duas têm mercados de trabalho grandes, e qual tem mais vagas depende do país e do setor, então confira os anúncios onde você quer trabalhar. C# é forte em empresas corporativas que usam Microsoft, finanças, saúde e estúdios de jogos; Java em grandes bancos, telecomunicações, backends de e-commerce e Android.