Comments 103
лучше бы структуры и unsigned добавили как в шарпе, ей богу. Без лямбд можо прожить
+2
И memory pinning для JNI!
0
Ну учитывая то, сколько они делали поддержку строк в switch, структуры тоже будут очень не скоро.
+6
UFO just landed and posted this here
Чтобы сборщик мусора отдыхал :)
+5
UFO just landed and posted this here
Структуры располагаются в стеке потока, а не в куче, в следствии чего не требуется освобождение памяти сборщиком мусора.
В Java есть примитивы(byte, short, int, float,...) это аналоги структур в .NET (они располагаются в стеке). Однако нет возможности создать пользовательский тип который бы располагался в стеке.
В Java есть примитивы(byte, short, int, float,...) это аналоги структур в .NET (они располагаются в стеке). Однако нет возможности создать пользовательский тип который бы располагался в стеке.
0
UFO just landed and posted this here
В C# от такой возможности больше пользы, чем проблем. Там структуры — это очень редко используемая штука, но иногда они могут очень сильно поднять производительность.
+2
Еще массивы структур располагаются в памяти одним блоком, а не массивом ссылок на объекты в куче. В некоторых случаях это принципиально.
+3
UFO just landed and posted this here
То, что благодаря Escape Analysis объекты создаются в стеке — миф. Подробнее, wikis.oracle.com/display/HotSpotInternals/EscapeAnalysis
0
Escape analysis уже решает эту проблему.
+1
Например, при парсинге JSON'a: удобнее сделать структуру. Сейчас приходится создавать «структуру», в которой много вложенных классов с геттерами/сеттерами.
-7
Вам заголовки файлов или TCP пакетов читать приходилось? Со структурами это делать куда приятнее, чем вручную парсить byte[].
-2
UFO just landed and posted this here
и еще честные дженерики, а не эту фигню с боксингом
+5
И protected нормальный! чтобы всем детям видно было, а не только тем что рядом лежат
-6
UFO just landed and posted this here
Про честные дженерики(если я правильно понял автора и не забыл джаву), имеется в виду, что в джаве нельзя написать:
Можно только:
Что может привести к лишнему боксингу/анбоксингу:
В С# можно написать:
ArrayList<int>
Можно только:
ArrayList<Integer>
Что может привести к лишнему боксингу/анбоксингу:
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(42); // Тут произойдет автоматический боксинг
int number = list.get(0); // а тут анбоксинг
В С# можно написать:
List<int> list = new List<int>();
list.Add(42); // никакого боксинга
int number = list[0]; // никакого анбоксинга
0
Вы понимаете, что такие генеральные переделки сломают совместимость со старыми JVM?
+3
Вообще не совсем понятно зачем держаться за нее? В мире .Net никого не удивляет, что новая программа может попросить новую версию фреймворка.
+1
И именно по этому многие выбирают java для серверов :)
+6
В смысле — новая программа требует новый фреймворк, новый фреймворк требует новую ОС, ОС требует новое железо?
Ну да, такой шанс есть. Но на данный момент мне почему-то кажется, что Oracle уже могли бы пожертвовать обратной совместимостью и избавиться от кучи костылей. Тем более, что насколько мне известно, совместимость все равно оставляет желать лучшего и не является стопроцентной. Поправьте меня, если я ошибаюсь.
Ну да, такой шанс есть. Но на данный момент мне почему-то кажется, что Oracle уже могли бы пожертвовать обратной совместимостью и избавиться от кучи костылей. Тем более, что насколько мне известно, совместимость все равно оставляет желать лучшего и не является стопроцентной. Поправьте меня, если я ошибаюсь.
0
Совместимость в джаве очень сильная. Это одна из главных стратегических линий платформы.
Преимуществ уйма.
Вы можете без опасений пользоватся старыми либами и они будут работать так как надо.
Например ваш проект использует либу А, которая давно не поддерживается и не совместима с новым фреймворком и вы захотели добавить либу Б, которой нужна новая версия фреймворка.Что выбрать?
И еще. Серьезное банковское серверное приложение. Вы обновили фреймворк, потеряв совместимость. Вы должны молить бога чтоб баги всплыли в тестах, а не на продакшене.
Разве в С# нет обратной совместимости?
Преимуществ уйма.
Вы можете без опасений пользоватся старыми либами и они будут работать так как надо.
Например ваш проект использует либу А, которая давно не поддерживается и не совместима с новым фреймворком и вы захотели добавить либу Б, которой нужна новая версия фреймворка.Что выбрать?
И еще. Серьезное банковское серверное приложение. Вы обновили фреймворк, потеряв совместимость. Вы должны молить бога чтоб баги всплыли в тестах, а не на продакшене.
Разве в С# нет обратной совместимости?
+3
Я не предлагаю так сделать в Java. Я попытался пояснить, что, вероятно, имелось в виду под «честными дженериками» в данном случае.
Но тем не менее? я хочу заметить, что и в Java и C# дженерики появились уже после релиза языка. Так что проблемы совметимости были не только у авторов Java.
Но тем не менее? я хочу заметить, что и в Java и C# дженерики появились уже после релиза языка. Так что проблемы совметимости были не только у авторов Java.
0
пример в студию!
+1
Дело не только в том, как писать. В Java все эти дженерики при компиляции преобразуются в инстанциированные классы (что-то вроде ArrayListOfInteger). В рантайме инстанциировать новый дженерик нельзя, только путем компиляции в рантайме. И в reflection не очень удобно анализировать дженерики.
В .NET дженерики «честные» (после компиляции так и остаются дженериками), можно инстанциировать в рантайме и reflection гораздо приятнее.
В .NET дженерики «честные» (после компиляции так и остаются дженериками), можно инстанциировать в рантайме и reflection гораздо приятнее.
-6
Если бы в рантайме оно преобразовывалось в ArrayListOfIntegers — это не было бы проблемой как раз, мы бы по прежнему могли понять, что происходит. Проблема как раз в том, что оно преобразуется просто в ArrayList. Все, что в угловых скобках, по сути удаляется после компиляции
+1
В Java генерики работают через erasure, а не так как вы говорите.
+3
UFO just landed and posted this here
Вообще-то, в C# так можно не из-за «нормальных дженериков», а из-за того, что int — это класс, а не примитив
-3
UFO just landed and posted this here
Вы перепутали protected с доступом по умолчанию?
+1
Ну да, а ещё Dynamic Runtime, аналог Async/Await, Extension methods, ну и дальше по списку en.wikipedia.org/wiki/Comparison_of_C_Sharp_and_Java
Такими темпами, работы у ребят из Oracle где-то до 2020-ого.
Такими темпами, работы у ребят из Oracle где-то до 2020-ого.
+3
Такими темпами Java безнадежно отстанет и загнется (платформа JVM никуда не денется, но язык вполне может смениться).
Пока в Java будут реализовывать поддержку фич десятилетней давности, другие языки будут обогащаться новыми фичами.
Пока в Java будут реализовывать поддержку фич десятилетней давности, другие языки будут обогащаться новыми фичами.
-2
Async/await? Уже есть: commons.apache.org/sandbox/commons-javaflow/
Я к этому делу прикрутил ещё и kryo и пишу бинарный образ continuation'а в blob в БД. Можно хоть перезагрузить сервак, пока поток ждёт. Я это использую для того, чтобы программировать workflow на java без всяческих event'ов и listener'ов. Получается прямо как BPEL, только Java вместо XML. А continuation'ы использую, чтобы ожидать ответ от пользователей. Пока пользователь не выполнит назначенную ему задачу, continuation будет мирно лежать себе в БД. Единственный минус javaflow — плохо поддерживается reflection и встроенный механизм proxy. Последний мне был нужен, поэтому я взял в руки ASM и запилил свой Proxy с поддержкой javaflow.
Dynamic Runtime? Я правильно понимаю, что это просто библиотека над стандартным CLR + ключевое слово dynamic? Последнее не знаю, зачем нужно, а библиотеки в Java, думаю, и так подобные имеются. Плюс появившаяся в Java 7 инструкция INVOKEDYNAMIC.
Extension methods не нужны (и порой даже вредны), без LinQ, конечно, тяжело, но есть Querydsl. С появлением лямбд всё будет ещё веселее. Наверняка кто-нибудь сделает querydsl на стероидах. Теоретически, если сюда подключить манипуляцию с байт-кодом, то можно получить вариант, практически не отличимый от LinQ. А вот то, что не сделали нормальный вывод типов — это жаль, конечно.
Зато в .NET нет java.util.concurrent (или уже появился?), нет перекомпиляции методов JIT'ом в более быстрые аналоги на основе статистики выполнения (или тоже уже сделали?) и дальше по списку.
Я к этому делу прикрутил ещё и kryo и пишу бинарный образ continuation'а в blob в БД. Можно хоть перезагрузить сервак, пока поток ждёт. Я это использую для того, чтобы программировать workflow на java без всяческих event'ов и listener'ов. Получается прямо как BPEL, только Java вместо XML. А continuation'ы использую, чтобы ожидать ответ от пользователей. Пока пользователь не выполнит назначенную ему задачу, continuation будет мирно лежать себе в БД. Единственный минус javaflow — плохо поддерживается reflection и встроенный механизм proxy. Последний мне был нужен, поэтому я взял в руки ASM и запилил свой Proxy с поддержкой javaflow.
Dynamic Runtime? Я правильно понимаю, что это просто библиотека над стандартным CLR + ключевое слово dynamic? Последнее не знаю, зачем нужно, а библиотеки в Java, думаю, и так подобные имеются. Плюс появившаяся в Java 7 инструкция INVOKEDYNAMIC.
Extension methods не нужны (и порой даже вредны), без LinQ, конечно, тяжело, но есть Querydsl. С появлением лямбд всё будет ещё веселее. Наверняка кто-нибудь сделает querydsl на стероидах. Теоретически, если сюда подключить манипуляцию с байт-кодом, то можно получить вариант, практически не отличимый от LinQ. А вот то, что не сделали нормальный вывод типов — это жаль, конечно.
Зато в .NET нет java.util.concurrent (или уже появился?), нет перекомпиляции методов JIT'ом в более быстрые аналоги на основе статистики выполнения (или тоже уже сделали?) и дальше по списку.
0
Лямбды всё равно будут кастрированными и с граблями.
+14
Почему то все забывают, что ламбды то нам обещают в 8-ка, а вот полноценных замыканий нет. Сейчас изнутри лямбды (как и безымянного вложенного класса) можно обращаться только к финальным локальным переменным метода в котором они создаются. Как это не поразительно в 8-ке на собираются менять этот ужас. Даже в JavaScript замыкания реализованы, а в Java нет.
-3
Во-первых, там вводится понятие «эффективно финальных переменных», т.е. которые хоть и не помечены final, но присваиваются только один раз, их можно сразу использовать в лямбдах. Во-вторых, возможность модификации любой переменной — это опасно в связи с многопоточностью, об это сразу будут обжигаться много народу. В-третьих, полноценные замыкания это опять генеральная переделка JVM, т.к. придётся вводить какую-то сущность типа «указатель на фрейм стека» или что-то подобное.
+4
Замыкания и лямбды можно реализовать на уровне синтаксиса без добавления новых инструкций в байткод и изменения виртуальной машины. Доказательство: C#, Scala.
0
Можно, только это будет либо
1) неэффективно с точки зрения JVM (плохая HotSpot-компиляция, много временных объектов, туча мелких анонимных классов)
2) это будет другой язык, не только с другим синтаксисом, но и с другой семантикой
Ну вот и пользуйтесь тогда Scala. (только не говорите, что там проблем нет)
1) неэффективно с точки зрения JVM (плохая HotSpot-компиляция, много временных объектов, туча мелких анонимных классов)
2) это будет другой язык, не только с другим синтаксисом, но и с другой семантикой
Ну вот и пользуйтесь тогда Scala. (только не говорите, что там проблем нет)
0
Полноценные замыкания элементарно имитируются через ObjectHolder
+2
Кто бы сомневался. А ведь первоначально вообще планировалось выпустить Лямбду в составе Java 7 ещё несколько лет назад.
+2
Всё, точно пора мигрировать на Groovy или Scala. Они намного динамичнее развиваются.
+7
Марк задаёт вопрос: а какие вообще были варианты у ребят из Oracle?
Варианты больше напоминают отмазки. Почему-то новые версии .NET вместе C# выходят регулярно, синтаксических плюшек там гораздо больше.
Видимо просто у Oracle другие приоритеты. Или большому Oracle просто не до Java.
+4
Я думаю стоит учесть тот факт что .NET идет под Windows платформу только, MONO не рассматриваем. Исходя из этого времени на тестирование .NET релиза нужно заметно меньше, в отличие от Java с таким набором поддерживаемых платформ.
0
Почему не рассматриваем? Рассмотрите. Он уже давно стабильный и полностью поддерживает спецификацию.
+2
Да, не спорю. И Java более старая платформа, поэтому многие новые фичи делаются через костыли ради обратной совместимости.
Но это все больше касается JVM. А синтаксис можно делать сколь угодно разнообразным и красивым, если его можно скомпилировать все в тот же байткод. В этой части затраты одинаковы.
Лямбда-выражения появились в C# 3.0, 6 лет назад. В Java они будут добавлены только в следующем году. Реально 7 лет требовалось, чтобы реализовать лямбда-выражения? Думаю причина тут все-таки не в трудоемкости, а в приоритетах.
Но это все больше касается JVM. А синтаксис можно делать сколь угодно разнообразным и красивым, если его можно скомпилировать все в тот же байткод. В этой части затраты одинаковы.
Лямбда-выражения появились в C# 3.0, 6 лет назад. В Java они будут добавлены только в следующем году. Реально 7 лет требовалось, чтобы реализовать лямбда-выражения? Думаю причина тут все-таки не в трудоемкости, а в приоритетах.
+1
Lambdas это не просто синтаксис, они компилируются в байт-код с использованием таких фич как method handles и invokedynamic, которые появились только в Java 7.
+3
Я в целом про то, что синтаксис Java не улучшается годами. То, что в других языках есть из коробки, здесь реализуется через паттерны.
0
Я в целом про то, что синтаксис Java не улучшается годами.
А нужно оно? Золотое правило: работает — не трожь.
То, что в других языках есть из коробки, здесь реализуется через паттерны.
То что можно сделать библиотеками — не нужно делать на уровне языка. Однородность и простота синтаксиса это плюс а не минус.
0
То, как их сделать — вопрос реализации. Можно было реализовать по-другому, раньше и с замыканиями.
0
ничего подобного, лямбды это синтаксический сахар над интерфейсами с одним методом.
-1
Нет. Прочитайте Translation of Lambda Expressions. Компиляция лямбды создаёт в базовом классе скрытый метод наподобие
static void lambda$1(...) { }
, а при выполнении при помощи некторой «магии» берётся ссылка на этот метод и превращается в экземпляр интерфейса (нечто вроде dynamic proxy).+4
Вообще, я считаю что зря они уходят в функциональное программирование с этими лямбдами (поправьте, если не так).
На данный момент я нашел только одно применение лямбдам: эмуляция C# делегатов.
На данный момент я нашел только одно применение лямбдам: эмуляция C# делегатов.
-6
Код читаться будет проще во многих случаях. Вместо:
так:
Хотя, кому-то такой стиль может показать «неправильным», но я без него жить не могу. Намного быстрее понять, что происходит и в какой последовательности.
void DoSomething()
{
Console.Write("Hello ");
Task.Factory.StartNew(PrintWorldWithDelay);
// тут много кода
Console.ReadLine();
}
// и тут много
void PrintWorldWithDelay()
{
Thread.Sleep(2000);
Console.Write("World! (after 2 sec)");
}
так:
void DoSomething()
{
Console.Write("Hello ");
Task.Factory.StartNew(() =>
{
Thread.Sleep(2000);
Console.Write("World! (after 2 sec)");
});
// много кода
Console.ReadLine();
}
Хотя, кому-то такой стиль может показать «неправильным», но я без него жить не могу. Намного быстрее понять, что происходит и в какой последовательности.
+3
new Thread(new Runnable() { public void run() {
Thread.sleep(2000);
System.out.println("World! (after 2 sec)");
}}).start();
не катит?
Или даже так:
new Thread(
public void run() {
Thread.sleep(2000);
System.out.println("World! (after 2 sec)");
}).start();
+4
Катит, конечно, но многие ругают Java именно за многословность.
+1
В случае с лямбдами public void run() превратится в () =>
экономия не очень существенная. И совсем другое дело, если бы принципиально это было невозможно и пришлось бы всегда писать отдельные методы.
Хотя наверняка найдутся и более удачные примеры. А вот лично мне как раз больше мешает боксинг дженериков, как писали выше.
экономия не очень существенная. И совсем другое дело, если бы принципиально это было невозможно и пришлось бы всегда писать отдельные методы.
Хотя наверняка найдутся и более удачные примеры. А вот лично мне как раз больше мешает боксинг дженериков, как писали выше.
+1
Если точнее, то
new Runnable() { public void run() {
плюс ещё одна закрывающая скобка. И по многим правилам оформления обычно это разбивают на минимум 2 строки.0
Проблема в том, что будет создан анонимный класс. Это довольно дорого (если это делать очень часто). Лямбды — это не только новый синтаксис, это очень полезная вещь. Можно было бы, конечно, просто оптимизировать создание анонимного класса из интерфейса, в котором определен только один метод, но это было бы непрозрачно — в вашем примере вариант с Runnable был бы оптимизирован, а вариант с Thread — нет
+1
Из очевидного — работа с коллекциями. А вообще это еще одна степень свободы, которую можно использовать при проектировании.
0
Лямбды позволяют реализовывать красивую работу с коллекциями (см. LINQ) а в последствии и с событиями (см. Rx).
0
Для баланса комментариев напишу, что лично мне лямбд больше всего в современной Яве не хватает. И, скажу более, пожалуй единственное, что ей не действительно не хватает и что реально важно.
+9
Сейчас вполне реально и возможно даже нужно писать multi-language проекты. Например Java/Scala. Все равно все собирается в байт-код. В Scala вам и лямбды будут)
0
А ничего что из лямбды нельзя поменять локальную переменную?
-5
Через трюк — можно.
int[] result = new int[1];
callSomething(() => { ...; result[0] = x });
А без трюков — будет много сложностей, как у людей, так и у компилятора и JVM, поверьте.0
Это не трюк, а костыль. Когда я в первый раз увидел подобный код (там использовался AtomicInteger), я включил повышенный внутренний уровень опасности, ожидая хитрой работы с потоками, оказалось зря — это был как раз этот «трюк»: использование вещей для этого не предназначенных, чтобы обойти искуственное ограничение. По-моему, сложность для людей очевидна.
+2
Вот допустим, метод callSomething запускает лямбду асинхронно в новом треде, и после этого вызывающий метод сразу завершается. Лямбда посчитала результат — какую она локальную переменную сможет теперь изменить, если уже от вызывающего метода и стека не осталось? Ну вы-то сообразите, может быть, что такого делать нельзя, а как это компилятору объяснить — сможете?
+1
Вы не тот вопрос задаете.
Если java-программист хочет использовать замыкание (изменение локальной переменной из лямбды), то java сообщество не бьёт его палкой, а рекомендует использовать костыль в виде int[] или AtomicInteger. Возникает вопрос, почему это окостылевание не делает компилятор, если оно и так общепринято? Ответ я не знаю.
Если java-программист хочет использовать замыкание (изменение локальной переменной из лямбды), то java сообщество не бьёт его палкой, а рекомендует использовать костыль в виде int[] или AtomicInteger. Возникает вопрос, почему это окостылевание не делает компилятор, если оно и так общепринято? Ответ я не знаю.
0
Это, кстати, Thread Unsafe код и, соответственно, гонка, даже если callSomething корректно передаст вашу Лямбду в другой поток.
0
Как заранее понять, что он thread unsafe (не заглядывая внутрь)? (и как дать это понять компилятору?)
0
Компилятору абсолютно пофигу сейф ваш код или нет. Дать ему понять, с-но никак.
Заранее понять очень просто, если можно доказать, что всегда будет ребро happens-before, значить трейд сейф, иначе не трейд сейф. Тут на момент вызова лямбды не будет таких ребер. Можно переписать например так:
ArrayBlockingQueue result = new ArrayBlockingQueue(1);
callsomething(() => {… result.put(x);});
Заранее понять очень просто, если можно доказать, что всегда будет ребро happens-before, значить трейд сейф, иначе не трейд сейф. Тут на момент вызова лямбды не будет таких ребер. Можно переписать например так:
ArrayBlockingQueue result = new ArrayBlockingQueue(1);
callsomething(() => {… result.put(x);});
0
Я, если честно, вообще полагаю, что зря в Яве локальные переменные не являются final по умолчанию. Так что ничего страшного, их вообще крайне редко приходится менять.
+3
В Intellij IDEA можно поставить декларирование локальных переменных всегда финальными. Советую.
0
Единственное когда это мешает, когда переменная кидает не RuntimeException, при какой то инициализации. Скажем мы хотим вытащить значение какого то обьекта из чего то, а эта операция вызывает эксепшн, с которым ничего вовсе не хочется делать. И выходит что то типо
...
Foo foo = null;
try{
foo = getFromSomewhere();
} catch (IDontCareException e) {
log.info(e, "looks like foo is not there);
}
if (foo != null) {
doSomethingWithFoo(foo);
}
doSomethingElse();
...
0
И правильно. В иммутабельном стиле программирования потенциально меньше ошибок
+1
ничего. ибо не нужно. ибо за такой код надо по рукам бить
+6
Sign up to leave a comment.
Релиз Java 8 передвинут на март 2014 года