C# и Java близкие родственники. Оба статически типизированы, объектно-ориентированы, используют сборку мусора и синтаксис в стиле C, оба компилируются в байт-код для виртуальной машины и оба применяются в крупных серверных системах. C# вышел в 2002 году отчасти как ответ Microsoft на Java, и за двадцать с лишним лет языки заимствовали друг у друга возможности (лямбды, обобщения, записи, сопоставление с образцом). Разработчик, знающий один из них, почти сразу может читать другой.
Различия, важные в повседневной работе, меньше и конкретнее. На этой странице они разобраны с кодом: фрагменты на C# можно запустить, а Java показана в статичных блоках для сравнения.
Коротко
| C# | Java | |
|---|---|---|
| Создатель | Microsoft (2002) | Sun Microsystems (1995), сейчас Oracle |
| Среда выполнения | CLR (.NET), компилирует IL в нативный код | JVM, компилирует байт-код в нативный код |
| Платформы | Windows, Linux, macOS | Windows, Linux, macOS |
| Свойства | Встроены в язык: public int Age { get; set; } | Методы-геттеры и сеттеры |
| Пользовательские типы значений | struct | Пока нет (Project Valhalla) |
| Обобщения | Реифицированные: типы существуют во время выполнения | Стираемые: типы удаляются после компиляции |
| Запросы к коллекциям | LINQ | Streams API |
| Асинхронность | async / await | Виртуальные потоки (Java 21), CompletableFuture |
| Проверяемые исключения | Нет | Да |
| Перегрузка операторов | Да | Нет |
| Защита от null | Ссылочные типы, допускающие null (C# 8) | Optional<T>, аннотации |
| Основные области | Игры на Unity, ASP.NET Core, настольные приложения Windows, Azure | Корпоративные бэкенды, Android, большие данные |
Синтаксис: почти одинаковый
Классы, методы, if, for, while, switch, try/catch выглядят почти идентично. Видимые различия в соглашениях об именовании и нескольких ключевых словах: методы в C# пишутся в PascalCase (ToUpper, WriteLine), в Java в camelCase (toUpperCase, println); в C# пишут string и bool, в Java String и boolean; наследование в C# записывается как class Dog : Animal, а в Java как class Dog extends Animal.
// 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());
}
}
}
Вывод:
ANA
BEN
Кроме того, в C# == сравнивает строки по значению, что убирает одну из классических ошибок новичков в Java: там == для двух объектов String сравнивает ссылки, поэтому две равные строки, созданные во время выполнения (прочитанные из ввода или склеенные), могут оказаться неравными.
Свойства вместо геттеров и сеттеров
Классы Java открывают состояние через методы getName() и setName(), которые обычно генерирует IDE или Lombok. В C# есть свойства: члены, которые читаются как поля, но выполняют код.
// 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;
}
}
Вывод:
Mug: 9.50
Инициализатор объекта new Product { Name = ..., Price = ... } задаёт свойства сразу после создания. Записи в Java (Java 16) покрывают случай неизменяемых данных; в C# тоже есть записи (C# 9), а для всего остального свойства.
Типы значений: структуры
В Java каждый пользовательский тип является ссылочным и хранится в куче; значениями являются только восемь примитивов (int, double, ...). C# позволяет определять собственные типы значений через struct. Структура копируется при присваивании и может храниться прямо внутри массивов и других объектов без отдельного выделения в куче.
Вывод:
a = (1, 2)
b = (99, 2)
1000
Это важно в играх и численном коде, где миллионы маленьких объектов нагружали бы сборщик мусора. См. структуры.
Обобщения: реифицированные и стираемые
Java стирает аргументы обобщённых типов при компиляции: во время выполнения List<Integer> это просто List, а List<int> запрещён (вы получаете упакованные объекты Integer). C# сохраняет аргументы типов во время выполнения, поэтому List<int> хранит обычные int, а код может узнать, что такое T.
Вывод:
3 items of type Int32
1 items of type String
List`1
typeof(T) и new T() работают, потому что среда выполнения знает T. В Java и то и другое вызывает ошибку компиляции, а обычный обходной путь передавать повсюду объект Class<T>.
LINQ и стримы
В обоих языках есть текучий API для фильтрации и преобразования коллекций. В Java это Streams API (Java 8), в C# это LINQ (C# 3), у которого есть ещё и синтаксис запросов и который работает с базами данных через Entity Framework.
// Java
List<String> expensive = products.stream()
.filter(p -> p.getPrice() > 20)
.sorted(Comparator.comparing(Product::getPrice))
.map(Product::getName)
.collect(Collectors.toList());
Вывод:
Lamp, Chair
Total: 126
Операции соответствуют друг другу один к одному (filter это Where, map это Select, collect(toList()) это ToList()), а версиям на C# не нужны ни stream(), ни коллектор. Объекты new { Name = ..., Price = ... } это анонимные типы, у которых нет прямого аналога в Java.
Асинхронность и конкурентность
C# представил async/await в 2012 году: метод async возвращает Task, а await приостанавливает его, не блокируя поток. Позже те же ключевые слова переняли JavaScript, Python и Rust. Java пошла другим путём: цепочки CompletableFuture, а начиная с Java 21 виртуальные потоки, которые делают обычный блокирующий код дешёвым.
// 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()));
}
Оба подхода масштабируются на множество одновременных запросов. C# делает асинхронность видимой в сигнатурах методов, а Java прячет её в среде выполнения.
Исключения, операторы и мелкие различия
- Проверяемые исключения. Java заставляет метод объявлять или перехватывать определённые исключения (
throws IOException). В C# проверяемых исключений нет вообще. - Перегрузка операторов. C# позволяет типам определять
+,==,<и другие операторы, поэтому арифметика сdecimalиDateTimeчитается естественно. В Java этого нет (BigDecimal.add). - Виртуальность по умолчанию. Методы Java можно переопределять, если они не помечены
final; методы C# нужно пометитьvirtual, чтобы их можно было переопределить, а переопределение должно содержатьoverride. - Методы расширения. C# может добавлять методы к существующим типам (
"text".IsPalindrome()); Java не может. - Типы значений, допускающие null.
int?в C# это int, который может быть null; в Java используется упакованныйInteger. - Беззнаковые типы. В C# есть
uint,ulong,ushortи беззнаковыйbyte; в Javabyteзнаковый, и, кроме 16-битногоchar, беззнаковых целых типов нет.
Экосистема, вакансии и что учить
Экосистема Java больше в мире открытого серверного ПО: Spring, Kafka, Spark, Hadoop, Elasticsearch и большинство проектов Apache написаны на Java. Приложения для Android пишут на Kotlin или Java. У C# более цельный стек: один производитель поддерживает язык, среду выполнения, веб-фреймворк (ASP.NET Core), ORM (Entity Framework) и основную IDE (Visual Studio), а Unity ставит его в центр разработки игр.
У обоих языков большой рынок труда, а баланс между ними зависит от региона и отрасли. C# силён в компаниях на Microsoft и Azure, в финансовом и медицинском ПО и в игровых студиях.
Выбирайте C#, если хотите делать игры на Unity, настольные приложения для Windows или работать в компании на .NET. Выбирайте Java, если цель Android, большие данные или компания с бэкендом на JVM. Любой из них научит понятиям, которые нужны для другого: классам, интерфейсам, обобщениям, коллекциям, исключениям и среде выполнения со сборкой мусора.
Часто задаваемые вопросы
Похож ли C# на Java?
Да, очень. Оба языка статически типизированы, объектно-ориентированы, используют сборку мусора, имеют синтаксис в стиле C и компилируются в байт-код для виртуальной машины. Разработчик на Java может читать код на C# с первого дня. Различия в деталях: в C# есть свойства, пользовательские типы значений, обобщения, сохраняющие типы во время выполнения, LINQ и async/await, а в Java есть проверяемые исключения и более крупная экосистема открытых серверных проектов.
Что учить первым, C# или Java?
Выбирайте по тому, что хотите делать. C# для игр на Unity, настольных приложений для Windows и компаний, построенных на Microsoft и Azure. Java для Android (вместе с Kotlin), крупных корпоративных бэкендов и инструментов больших данных вроде Kafka и Spark. Языки настолько близки, что переход потом займёт недели, а не месяцы.
C# быстрее Java?
Они в одном классе производительности: оба JIT-компилируются в нативный код и используют сборщики мусора с поколениями. C# даёт больше низкоуровневого контроля через структуры, Span<T> и обобщения над типами значений без упаковки, что помогает в коде с большим количеством выделений памяти. В типичных веб-нагрузках фреймворк и база данных значат гораздо больше, чем язык.
Есть ли в C# проверяемые исключения, как в Java?
Нет. В C# ни одно исключение не обязательно объявлять или перехватывать; сигнатура метода не перечисляет, что он выбрасывает. Авторы языка решили, что проверяемые исключения приводят к пустым блокам catch и хрупким сигнатурам. Вместо этого исключения документируют XML-комментариями /// <exception>.
Где больше вакансий, в C# или в Java?
У обоих языков большой рынок труда, а то, где вакансий больше, зависит от страны и отрасли, поэтому смотрите объявления там, где хотите работать. C# силён в корпоративных компаниях на стеке Microsoft, в финансах, медицине и игровых студиях, Java в крупных банках, телекоме, бэкендах интернет-магазинов и Android.