[Что есть в Java, чего нет в C#?](/questions/367569/%d0%a7%d1%82%d0%be-%d0%b5%d1%81%d1%82%d1%8c-%d0%b2-java-%d1%87%d0%b5%d0%b3%d0%be-%d0%bd%d0%b5%d1%82-%d0%b2-c)
=================================================================================================================================================================

Решил попробовать писать под андроид и столкнулся с необходимостью писать на Java. До этого писал больше на C#. Языки похожие во многом, но есть и отличия. И так как пока я C# знаю лучше Java, то так получается, что я пользуюсь только теми возможностями синтаксиса Java, которые знаю по C#. В общем, сейчас для меня java превратился в "урезаный C#", потому что каких-то чисто джавовских "фишек" я не знаю, а некоторых возможностей из C# в этом языке нет. Ну, например, в Java нет оператора `??`, нет linq, нет свойств, нет атрибутов.

Так вот сам вопрос: а что есть в Java, чего нет в C#? Именно из синтаксиса, различных удобностей и синтаксического сахара.

Смотрите.

В основном по фичам в данный момент C# идёт впереди Java, Java находится в позиции догоняющего. Однако есть несколько фич, которые есть в Java и нет в C# и которые при правильном использовании могут облегчить жизнь программисту.

1) Легковесные (анонимные) производные классы.

Пример:

```
new Thread(new Runnable() { // это анонимный производный класс!
        @override
        public void run() {
            // do some work
        }
    }).start();

```

В C# надо было бы объявить производный класс явно. Аналогичная, но не равносильная фича C# — анонимные *методы*, то есть лямбды.

2) Нестатические внутренние классы. В C# внутренние классы лишь логически находятся «внутри» и не имеют доступа к instance-переменным. В Java внутренние классы более богаты.

3) `enum`'ы. В C# они такие же, как в C++, и являются по существу именованными константами целочисленного типа. В Java `enum`'ы есть константы объектного типа, гораздо более богатые семантически.

4) checked exceptions. Вы можете объявлять как часть сигнатуры метода исключения, которые бросаются этим методом. В C# такой возможности нету. (Хотя разработчики C# считают, что эта фича не нужна [и даже вредна](http://www.artima.com/intv/handcuffs.html), тем не менее по факту это фича, которая есть в Java и нет в C#.)

5) `final`-параметры. В C# `const` могут лишь переменные и поля, в Java можно параметр объявить как `final`, и при попытке его изменить компилятор наругается на вас.

6) [`SoftReference`](https://stackoverflow.com/a/299702/276994) представляет собой «более сильную» версию `WeakReference` (которые тоже есть в Java): объекты, референсируемые ими, не удаляются, пока памяти хватает, даже если другие объекты уничтожаются в процессе сборки мусора.

7) У Java есть симпатичные [помеченные блоки](http://docs.oracle.com/javase/tutorial/java/nutsandbolts/branch.html), которые позволяют выйти из *любого* количества циклов за раз (`break`) или пропустить итерацию во внешнем цикле (`continue`). Также `break <label>;` может выйти из *любого* блока, не только цикла (что делает его равносильным `goto`).

8) В Java вы можете ловить в одном `catch` несколько исключений: `catch (IOException | SQLException ex)`. C# такое не умеет.

---

С выходом новой версии Java 8 добавилось ещё одно расхождение:

9) У Java есть очень полезная фича: [default interface implementation](https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html), с помощью которой можно устраивать подобие mixin'ов: написать код, который можно добавить к *любому* классу, с возможностью перегрузки.

У C# похожее поведение можно смоделировать при помощи extension-методов (которых в Java как раз нет) и маркерных интерфейсов, но вы не сможете *полиморфно* перегрузить метод в конкретном классе, только перекрыть. В результате если у вас есть указатель на базовый класс, вызов в случае C# приведёт к вызову метода для базового класса.



Вот теперь ведь никто мимо не пройдёт.

> 
> Ну, например, в Java нет
> оператора ??
> 
> 
> 

Зато есть обычный {o == null ? no : o}, это не урезание, а лишь отсутствие сахара. Функционально не обедняет.

> 
> нет linq
> 
> 
> 

Да, linq нет, но для работы с коллекциями можно библиотечку подыскать вроде Google Guava, если в самом деле так нужно. Для работы с результатами запросов из бд тоже можно решить проблему. На мой взгляд, решения делать через синтаксис языка лучше, чем liq, который работает примерно так: парсим один синтаксис, получаем другой, другой исполняем...

> 
> нет свойств
> 
> 
> 

Да, в java принято самому писать `get*` и `set*` методы. Это даже в спецификации java bean описано. (Ну, если вспомить C#, он просто делает методы `get_*`, `set_*` за кулисами). В настоящий момент нет необходимости всё подряд через геттеры получать... можно и поля аннотировать.

> 
> нет атрибутов
> 
> 
> 

Но есть аннотации.

Лично я считаю, .Net и Java - аналогичные технологии, призванные решать по большому счёту одни и те же задачи. Есть, конечно, свои особенности... и простое правило: пишешь только под Windows - используй .Net. Нет, Java лучше.

 

### Вкратце

**C# сильнее как язык:** в Java нет практически ничего, чего нет в C#. Как язык, Java отстал от времени и находится в роли догоняющего. Новые возможности натыкаются на несметное число проблем, унаследованных из-за обратной совместимости. Одна из критических проблем — type erasure.

**Java сильнее как платформа:** для C# нет такого количества библиотек, как для Java. Java гораздо популярнее в опен-сорсе. ~~Кросс-платформенность у джавы более чистая, не требует левых платных инструментов.~~ (Microsoft таки выкупила Xamarin и сделала бесплатным.)

Раньше C# был менее открытым, теперь он становится настоящим опен-сорсом (компилятор, рантайм и т.п.), поэтому ситуация с платформой может измениться. А вот Java как язык уже ничто не может спасти, ибо обратная совместимость.

### Про фичи

Достаточно поглядеть [Comparison of C# and Java](https://en.wikipedia.org/wiki/Comparison_of_C_Sharp_and_Java), чтобы понять пропасть между языками. Не верьте тем, кто говорит, что Джава сильна минимализмом — они врут (или просто привыкли писать огромные конструкции, когда достаточно одной строчки).

*Полный* список *важных* фич, которые отсутствуют в C#, но есть в Java:

* ~~Default interface implementation (расширение интерфейса без убийства обратной совместимости).~~ Default interface implementation пока отсутствует, но в следующей версии уже будет, потому что приходится портировать разные API на C# с языков с такой фичей.
* Strict floating point (детерминированные вычисления над числами с плавающей точкой). Можно получить костыльным способом, зависящим от ОС.
* Soft, phantom ссылки (польза спорная).
* Возможность запустить на большем количестве устройств (холодильник скорее будет поддерживать джаву, андроид нативно поддерживает джаву).

В общем-то, всё. Если же перечислять то, что есть в C#, но нет в Java, то список получится непомерно длинным.

Разумеется, даже в условиях серьёзного отставания джавы джависты не хотят предавать платформу. Определённое распространение получили альтернативные языки на JVM, например, Scala. В чём-то они мощнее C#, но по популярности они сильно уступают обоим языкам, и у них свои проблемы.

### Итог

По популярности в энтерпрайзе языки примерно на одном уровне (зависит от области разработки и страны проживания).

Если смотреть в будущее, выбирайте C#. Вы получите от программирования больше удовольствия.



Сила, брат, в простоте. Мощь Java как раз и кроется в простоте. Есть такой принцип [Бритва Оккама](https://ru.wikipedia.org/wiki/%D0%91%D1%80%D0%B8%D1%82%D0%B2%D0%B0_%D0%9E%D0%BA%D0%BA%D0%B0%D0%BC%D0%B0) - проще говоря:

> 
> Не умножай сущностей без необходимости
> 
> 
> 

Все эти linq, attributes - без них спокойно можно прожить.

Например, в C# есть такое понятие, как `partial` - так это вообще преступление и оксюморон!

 

Из того, что еще не было упомянуто: по-разному устроены способы реализации ко- и контра- вариантности в generics-ах.

Как оно работает в C#
---------------------

В шарпах, как известно, например, ковариантный интерфейс можно объявить вот так (пример нагло сворован с MSDN):

```
interface ICovariant<out R>
{
    R GetSomething();
}

```

Тогда, если у нас есть класс по типу:

```
class Implementation<T> : ICovariant<T> where T : new()
{
    public T GetSomething()
    {
        return new T();
    }
}

```

И два наследующих друг от друга класса:

```
class A {}
class B : A {}

```

Мы можем сделать так:

```
Implementation<B> b = new Implementation<B>();
ICovariant<A> a = b;

```

Т.е. получается, что `ICovariant<B>` как будто наследует от `ICovariant<A>`. Аналогично с контравариантностью, только там у type paramet-ра модификатор `in` вместо `out`, и все ровно наоборот - созданный от базового класса (`A`) экземпляр как бы "наследует" от производного (`B`). (на самом деле, это не наследование, а отношение is-a, т.е. если `B` есть `A`, то `ICovariant<B>` есть `ICovariant<A>`, но это уже семантические дебри).

Как оно работает в Java
-----------------------

А в Джаве по те же цели запилили другой механизм, который иногда ругают за ограниченность и меньшую безопасность, однако работает же!

Если я ничего не путаю, это называется call-site co/contra- variance. Фокус тут в том, что в шарпах вариантность (ко-, контра-, ин-) задается в декларации интерфейсов и делегатов, а у Джавы - в декларации самих объектов.

Это пашет через Джавины wildcard-ы (когда вместо `T` в "клювиках" стоит `?`). Аналогичный данному для шарпов пример тут будет выглядеть так:

```
class GenericClass<T> {
    public T field;
}

class A {}
class B extends A {}

GenericClass<B> b = new GenericClass<B>();
GenericClass<? extends A> a = b;

```

`?` (Wildcard) в качетсве type-paramet-ра обозначает, что черт его, собственно, знает, что это за тип такой, так что расслабиться с проверкой типов чуток можно.

Они бывают unbounded (просто один ? в клювиках), upper-bounded (`<? extends A>`, т.е. об этом типе есть информация, что он наследует от какого-то другого типа - `A`. По сути, `<? extends Object>` аналогично unbounded wildcard), и lower-bounded (`<? super B>`, т.е. этот тип должен быть одним из предков другого типа - `B`).

Upper-bounded wildcards используются, как я продемонстрировал выше, для ковариантности, а lower-bounded wildcards, как ясно, для контравариантности.

Вообще и wildcard-ы, и механизмы ко- и контра- вариантности в шарпах - тема большая и довольно интересная, рекомендую почитать по ним поподробнее (особенно про обход безопасности типов при помощи wildcard-ов, пример [тут](http://blogs.encodo.ch/news/view_article.php?id=14)).