Всем доброго времени суток. В ноябре 2017 в Санкт-Петербурге прошло одно из самых примечательных событий года для отечественных Java-разработчиков: конференция Joker. На конференции было озвучено много тем, такие как GC, Concurrency, Spring Boot, JUnit 5 и другие, презентации по которым вы можете найти в открытом доступе на сайте конференции. Перечислять все смысла нет, так как по каждому топику можно составить отдельную статью с примерами и выдержками. Поэтому остановимся на главном.

Основной темой были нововведения в Java 9: ей посвятили аж две лекции, по модулям, и по всему остальному. Саму девятку Oracle изначально планировали выпустить еще в середине лета 2016, однако релиз был перенесен сначала на полгода, а потом и вовсе на вторую половину 2017. И вот, 21 сентября 2017, выход девятки состоялся.

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

Итак, по порядку. Как говорилось выше, нововведения в девятке можно разделить на два блока: общий и модульный. Придерживаясь хронологии Joker, начнем с первого.

1. Появление литералов в коллекциях


На самом деле литералы в коллекциях можно использовать с 7 версии, никто не запрещает выполнить следующее, если у вас установлен ProjectCoin:

    List<Integer> list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 9];
    Set<Integer> set = { 2, 7, 31, 127, 8191, 131071, 524287 };

В 9 версии вы можете использовать нечто подобное без каких-либо предварительных подготовок:

List<Integer> piDigits = List.of(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 9);
Set<Integer> primes = Set.of(2, 7, 31, 127, 8191, 131071, 524287);

или

import static java.util.Map.*;
platonicSolids = ofEntries(entry(4, "tetrahedron"), entry(6, "cube"), ...);

Так же было сказано несколько слов о generic Pair, а вернее об их отсутствии. Однако в 9 появился усовершенствованный костыль использования мапы в качестве пары:

Map.entry(lowest, highest)

Ждем Project Valhalla.

2. Внедрение оператора Элвиса


На самом деле этот оператор реализован на Groovy на синтаксическом уровне, но если вы попробуете написать на джаве нечто подобное

        Person person = JohnGold ?: DefaultPerson;

компилятор предсказуемо ругнется. В девятке внедрили подобную логику, правда не на уровне синтаксиса. Ниже приведены два эквивалентных выражения на девятке и в уже привычном виде.


        
person = Objects.requireNonNullElse(JohnGold, DefaultPerson) //It will be work on Java 9
Optional<Person> maybePerson = JohnGold; // Familiar resolution
person = maybePerson.orElse(DefaultPerson);

3. Class Optional


Если кратко, этот класс для сбора not-null объектов: вместо того, чтобы проводить null-проверки, можно складывать объекты в данный контейнер, который автоматически будет отсеивать несуществующие объекты. Появился в Java 8 и вполне логично, что в новой версии появились улучшения для данного класса. Метод or интуитивно понятен: будет возвращен вызывающий объект, если он не нулевой, в противном случае вернется аргумент.

 maybePerson = maybePerson.or(() ->
JohnGold); // Another Optional

Следующий метод выполняет заданное действие над значением, если оно присутствует, в противном случае будет выполнено некое дефолтное значение.

maybePerson.ifPresentOrElse(System.out::println, // Consumer
() -> Runtime.exec("rm -rf /home")); // Runnable

Если значение присутствует, возвращает стрим только с этим значением, в противном случае стрим будет пустым.

Stream<T> stream()

Возможность использовать flatMap для удаления нулевых результатов:


Stream<User> users = people.map(Person::name)
.flatMap(Optional::stream);

4. Streams


Появился целый ряд методов API, из которых можно получить стримы: Scanner.tokens, Matcher.results, ServiceLoader.stream, LocalDate.datesUntil,
StackWalker.walk, ClassLoader.resources, Process.children/descendants,
Catalog.catalogs, DriverManager.drivers. В самих стримах тоже появились новые методы takeWhile, dropWhile, а также новые сборщики flatMapping, filtering.

5. IO, Regrexp


Тут все также масштабно. Появилась возможность считывать байты с поступающего потока

byte[] bytes = Files.newInputStream(path).readAllBytes();

Перенаправлять байты с входящего потока на исходящий: InputStream.transferTo(OutputStream).
Появилась возможность разбить принимаемый классом Scanner объект на токены в виде отдельных стримов:

Stream<String> tokens = new Scanner(path).useDelimiter("\\s*,\\s*").tokens();

Matcher.stream и Scanner.findAll выдают поток найденных результатов:

Pattern pattern = Pattern.compile("[^,]");
Stream<String> matches = pattern.match(str).stream().map(MatchResult::group);
matches = new Scanner(path).findAll(pattern).map(MatchResult::group);

Matcher.replaceFirst/replaceAll теперь могут принимать на вход функцию, согласно которой будет произведена перестановка:

String result = Pattern.compile("\\pL{4,}")
.matcher("Mary had a little lamb")
.replaceAll(m -> m.group().toUpperCase());
// Yields "MARY had a LITTLE LAMB"

6. Обработка процессов


Тут появился целый интерфейс ProcessHandle, позволяющий контролировать нативные процессы. С его помощью можно мониторить жив ли процесс, информацию о нем, лист детей и прочие плюшки. Зачем он нужен, когда есть абстрактный класс Process, спросите вы. На самом деле ProcessHandle предоставляет гораздо больше возможностей, нежели Process. Последний в свою очередь также предоставляет доступ к IOE потокам, что сказывается на производительности.

7. Немного синтаксических изменений


Интерфейсы теперь могут иметь методы с модификаторами доступа private, private static и судя по всему в скором времени совсем перестанут быть интерфейсами. Нижнее подчеркивание _ больше не может являться именем переменной — гайки закручиваются. И, наконец, поддержка try-with-resources


        void print (PrintWriter out, String[]lines){
            try (out) { // Effectively final variable
                for (String line : lines)
                    out.println(line.toLowerCase());
            }
        }

8. Старость


Появилось несколько деприкаций, куда же без этого. Классы Observable, Observer с новой версии будут считаться устаревшими, так же как и Object.finalize, Runtime.runFinalizersOnExit. Class.newInstance также теперь относят к Deprecated и аргументируют это тем, что он бросает проверяемые исключения конструктора без объявления их. Под ту же аннотацию попал весь Applet API, a также ряд модулей: java.activation, java.corba, java.transaction, java.xml.bind, java.xml.ws. Здесь были перечислены основные вещи, попавшие под аннотацию Deprecated и в презентацию Хорстмана, полный список всегда можно посмотреть у оракла.

9.Самая главная новость


System.getProperty("java.version")

Теперь этот код вернет значение «9», а не «1.9.0.».

Также в Java 9 появилась модульность, которая вызвала бОльший шум, чем все вышеперечисленное. И это неудивительно, так как статистика показывает, что это модульность была наиболее ожидаемой фичей среди разработчиков

image

Были вопросы что это вообще такое, как это будет взаимодействовать с Maven. Половина доклада ушла на обзор OSGi, вторая половина на обзор Jigsaw и объяснение почему это круто, превосходит по всем параметрам предмет первой половины доклада и то, что Jigsaw незаслуженно скромно принимается обществом. Судить об успешности этого проекта мы действительно можем только от общества, а пока нам остается ждать глобального перехода на Java 9, который, как сказали сами докладчики, будет происходить ближайшие 2-3 года. А пока можно посмотреть на самые ожидаемые изменения в следующей версии джавы и слушать шутки о том, будет ли она называться Java 10 или Java X.

image

Комментарии (68)


  1. beduin01
    11.11.2017 19:19

    Что под модульностью понимать? Сколько будет весить рантайм если я захочу создать приложение и не таскать с собой весь JRE.


    1. CyberSoft
      11.11.2017 20:03

      Под модульностью понимают контейнеры с кодом и ресурсами, причем из таких модулей будут состоять не только приложения, но и сами JRE/JDK. Что это даёт:


      1. Вы можете собрать образ (runtime image) типа приложение+JRE только с теми модулями из JRE, которые использует ваше приложение. Это сильно уменьшает размер пакета с самодостаточным приложением (если конечно не все модули использованы)
      2. Более строгие отношения между модулями. Первое, что бросается в глаза — требование открывать пакеты модулям, так как по умолчанию они не видны (из под полноценной модульной системы). Это значит, что можно делать интернал апи публичным в рамках модуля, раскидать его по разным пакетам и не переживать, что кто-то его начнёт использовать — компилятор рукам за такое даст.
      3. Может что-то ещё упустил..


    1. poxvuibr
      11.11.2017 22:01

      Hello World занял 22 мегабайта. Hello World с Java FX буть больше сорока


  1. AstarothAst
    11.11.2017 19:23

    Лично я так и не получил толкового ответа на то "зачем мне jigsaw". Jar-hell проблему она так и не решает, а вывод докладчик "ваш код станет строже" не убеждает — для этого модули девятки не нужны.


    1. sshikov
      11.11.2017 20:50

      Насколько я понимаю, проект Jigsaw никогда не претендовал решать проблему Jar-hell в вашем проекте. В лучшем случае это еще один инструмент, но не готовое решение — да и с какой бы стати?


      Одним из источников Jar-hell, к примеру, является использование зависимостей, взятых черти где — скачанных с непонятных сайтов, без явно указанных версий, короче — разработка без использования maven/gradle/etc для управления зависимостями. И это лечится только правильной постановкой работы в своем проекте. С другими типами проблем чуть иначе — но вывод примерно тот же.


      1. shishmakov
        11.11.2017 21:48

        Неверно. Именно о решение проблемы Jar hell, версионировании модулей и о разделении rt.jar на самостоятельные части говорили как о планах на Java 7. Это был 2009 год, Sun Tech Days в Питере.
        Maven и Gradle эту проблему не решают. Потому что у вас в проекте может быть явно указана библиотека и она же, но другой версии, попадает через транзитивные зависимости от других библиотек.


        1. sshikov
          11.11.2017 22:10

          Как вы себе сегодня представляете решение проблемы в своем проекте при помощи модуляризации JRE и разбиения rt.jar? Ну т.е. у вас две версии одной библиотеки, которые притащил maven (или вы их притащили вручную, как я выше описывал). Зато у вас rt.jar модульный. И какая связь?


          1. shishmakov
            11.11.2017 22:42

            ошибка компиляции, в проекте не должно быть библиотек разных версий.


            1. sshikov
              11.11.2017 23:00

              А можно показать пальцем, с какой стати и где 9-ка выдаст вам такую ошибку компиляции? Насколько я помню, версионирование и контроль версий поддерживаются для модулей, а не для jar, а во-вторых, возможность контроля на предмет только одной поддерживаемой версии одного модуля обсуждалась, и однозначного ответа, как оно в итоге будет, я лично не видел (ну т.е. были разговоры, что можно успешно получить module hell вместо jar hell).


              Ну и если у вас существующий проект — то модулей в нем само собой нет, а чтобы они были — надо рефакторить. Так что в итоге все равно получается, что это не решение, а лишь инструмент, еще один.


              У меня допустим в OSGI никакого jar hell в обычном смысле и не было никогда. В проекте не только можно, но и реально имеется несколько версий одного и того же, и все это работает, при одном простом условии — что вы пропишете у себя, какие именно версии зависимостей где нужны. А попросту говоря — наведете в зависимостях порядок. И да, OSGI контейнер ругнется в определенный момент, если не сможет однозначно разрешить зависимости какого-то бандла. Но опять же — это не решение, это инструмент. Оно само ничего не сделает. Оно только помогает порядок наводить.


              1. shishmakov
                12.11.2017 00:01

                А можно показать пальцем, с какой стати и где 9-ка выдаст вам такую ошибку компиляции?

                Перечитайте свой вопрос выше, вы спрашивали не о том как есть в java 9, а как на мой взгляд должна решаться проблема с одной и той же библиотекой в classpath разных версий.


                Вы же сами писали ранее:


                Насколько я понимаю, проект Jigsaw никогда не претендовал решать проблему Jar-hell

                именно на это я высказал возражение, что нет, такая задача стаяла. Я лично присутствовал на докладе где об этом говорили (на обычной конференции). Jigsaw ставил несколько задач и Jar hell, и разбиение rt.jar были одними из пунктов. Jar hell вычеркнули.


                1. sshikov
                  12.11.2017 11:23

                  А, да, сорри. Я понял. Да, возможно, совершенно не буду спорить, наверное планы такие были.


              1. CyberSoft
                12.11.2017 15:12

                А можно показать пальцем, с какой стати и где 9-ка выдаст вам такую ошибку компиляции?

                Будет ошибка компиляции об использовании пакета, открытого в двух модулях.


                И да, OSGI контейнер ругнется в определенный момент

                Определённый момент это в рантайме? А 9-ка может ругнуться во время компиляции.


                1. sshikov
                  12.11.2017 15:45

                  Пардон, откуда у вас в существующем проекте возьмутся модули?


                  9-ка может ругнуться во время компиляции.

                  Я это понимаю. И в общем-то, это пожалуй единственная серьезная разница между подходами. Но дело в том, что проблема может возникнуть и в райнтайме, ничего этому не мешает по большому счету.


                  Кроме того, я лично не знаю ответа на вопрос, что будет, если два модуля захотят две разные версии зависимости. На мой взгляд, это вполне возможная ситуация (модули могут быть написаны разными людьми или командами).


                  Ну т.е. ругнется, при компиляции, это хорошо, тут вряд ли стоит спорить. Но решение-то в чем будет состоять? Все равно кто-то должен будет понять, зачем и кому нужны две разные версии, и как их свести к одной. Это будет чисто человеческое, и возможно нетривиальное решение.


                  1. CyberSoft
                    12.11.2017 15:59

                    Пардон, откуда у вас в существующем проекте возьмутся модули?

                    В 9-ке теперь всё в модулях как ни крути, даже ваш class-path.


                    Кроме того, я лично не знаю ответа на вопрос, что будет, если два модуля захотят две разные версии зависимости

                    Подробно описал эту проблему в своей единственной статье, можете почитать :)


                    Но решение-то в чем будет состоять?

                    Если проект с нуля — правильно строим иерархию модулей, если существующий — автоматические модули в руки с доступом в class-path и постепенный рефакторинг в полноценные модули.


                    1. sshikov
                      12.11.2017 16:46

                      Так об этом и речь. Если нужен рефакторинг, то это инструмент, а не решение.


                      Ну и кстати, судя по вашей статье, вы не видели нормального OSGI. Felix и Equinox — это низкий уровень, на самом деле надо начинать скажем с Karaf. Тогда никаких проблем входа возможно не будет, а решение вы получите просто и штатно.


                      1. CyberSoft
                        12.11.2017 16:55

                        Так ведь это и есть решение — использовать инструмент, инструкция прилагается. Оракл считает это именно решением.

                        Про OSGi я теперь думаю только «упаси боже связаться», как и с такой проблемой в принципе.


                        1. sshikov
                          12.11.2017 17:01

                          Ну и зря. Вот прикиньте — система из порядка 100 модулей, сделанных разными людьми. Зависимости — какие попало, т.е. никто об этом не думает. Все это устанавливается в Karaf (в виде Jboss Fuse, но это не важно), и работает. Так что то что Оракл считает решением, уже много лет существует, и успешно используется, именно в виде OSGI.


                          Лично у меня ушло где-то с месяц на то, чтобы начать полноценно работать, и это совсем немного. При этом в сравнении например со Spring, то что есть в OSGI (Spring DM либо Blueprint) — это по сути тоже самое, когда поймешь простую вещь — что зависимости, которые в Spring статические, тут могут быть динамическими, появляться и пропадать, и работать с этим надо немного иначе.


                          1. CyberSoft
                            12.11.2017 17:18

                            По моему, вполне оправдано решили сделать такую фичу и для джавы. И теперь такую же систему из 100 модулей можно поднять и на девятке. При этом OSGi может жить дальше.

                            К тому же, целью не было убийство OSGi. Все его юзают и получают профит, а в джаве до сих пор правят монолитный код? Разработчикам тоже хочется упростить себе разработку и поддержку самой платформы.


                            1. sshikov
                              12.11.2017 17:22

                              Поймите меня правильно, я вовсе не против Jigsaw. Я лишь говорил о том, что другими средствами это же самое давно делается. И скажем так — примерно также, т.е. по сути, что такое бандл в терминах OSGI? Это обычный jar, у которого а) прописана версия, обязательно б) прописаны импорты и экспорты, и возможно тоже с версиями. Ну т.е. это все — так или иначе модули, с версионированием.


                              1. CyberSoft
                                12.11.2017 17:46

                                Я лишь говорил о том, что другими средствами это же самое давно делается

                                Вы снова упускаете модуляризацию платформы из виду. Вы говорите о средствах для приложений, а что предложите для самой платформы?


                                Если поставить модуляризацию платформы во главу, то тоже самое неизбежно произойдёт и с рантаймом как следствие. Да, возможно это reinvent the wheel, но, имхо, это не должно быть поводом бить на модули только саму платформу (да и как бы это выглядело).


                                1. sshikov
                                  12.11.2017 18:03

                                  Не, мы просто в этой ветке говорили о приложениях. То что там с платформой сделали — лично мне как-то не очень интересно.


            1. vsapronov
              12.11.2017 00:34

              И gradle и maven умеют решать проблему jar-hell ошибкой сборки. Согласны?


              1. sshikov
                12.11.2017 11:20

                Суть моих возражений в том, что это не называется "решать". Это не более чем инструмент диагностики ее наличия. И если это вынести на этам компиляции — то в сущности мало что изменится.


                Вот смотрите, есть apache commons lang, и она живет в версиях 2 и 3. И никаких ровным счетом проблем при этом не доставляет — потому что авторы это отработали, и назвали пакеты lang и lang3. Даже в одном классе можете использовать, удобств не будет, но работать работает.


                А теперь представим, что у вас наоборот, есть две версии jar, где пакеты, классы и сигнатуры методов одинаковые, а логика методов например разная. И тут-то у нас проблема в полный рост...


                1. vsapronov
                  12.11.2017 16:18
                  +1

                  В общем случае это не решение. Разрешать использовать разные версии библиотек в одном процессе — это приведёт к проблеме разрастания количества библиотек и общему непониманию какая конкретно и где конкретно используется. Кроме этого, иногда все равно нужно исправлять баги в существующих библиотеках, а это значит, что менять версию при каждом релизе нельзя — автор библиотеки должен думать, что он делает: исправление или конкретно новую разработку. Т.е. завязка на дисциплину конкретных разработчиков библиотек и тот же hell если они лажают.


                  1. sshikov
                    12.11.2017 16:40

                    Вы никогда не видели системы, которую делают скажем 50 человек? Да, разрастается, и да непонимание. Это нормальное состояние для работы, где задействованы несколько разных команд.


                    И тем не менее, изоляция каждого из модулей (что бы под этим не понимали) в отдельном класслоадере, и возможность для каждого модуля использовать свой набор зависимостей — это вполне себе решение.


                    Я бы даже сказал, что это проверенное промышленное решение — потому что мы это можем, уже давно. В JavaEE так можно, в OSGI все примерно так же. Если бы это было не так, вы вряд ли смогли бы например задеплоить в один JavaEE коннейнер два сервлета, один 2.x, а второй 3.x — и тем не менее, это не только можно, но и вполне себе используется налево и направо.


                    Единственное обязательное ограничение — чтобы эти разные версии зависимостей не торчали наружу из модулей.


                    1. vsapronov
                      12.11.2017 17:08

                      А теперь я лучше понимаю, что вы предлагаете. Т. е. на уровне модуля все равно jar hell и можно использовать только одну версию каждой библиотеки, но в приложении модули изолированны и что использует каждый модуль — его личное дело?


                      1. sshikov
                        12.11.2017 17:19

                        Ну да. На уровне модуля с этим вполне справляется gradle/maven.


                        1. vsapronov
                          12.11.2017 23:07

                          Тогда я понимаю вашу фрустрацию. Действительно, такой способ мог бы ослабить боль от управления зависимостями. Тем более если они обещали в 2009. Хотя это же Java, все нормально: нужно подождать до 2029 пока там сделают обещанное. Так вроде было всегда.

                          Вообще подход интересный. Ни в одном из известных мне языков или менеджеров пакетов такого решения нет.


                    1. imanushin
                      12.11.2017 17:20

                      Вы никогда не видели системы, которую делают скажем 50 человек?

                      На этом сайте немало людей работают и в бОльших компаниях/проектах. Для обоснования своей позиции не стоит использовать подобные пассажи.


                      По теме: если система доросла до того, что разные её части начали строго требовать разных зависимостей, то это знак того, что давно пора решать уже архитектурные проблемы. Как вариант: используйте микросервисы.


                      Про проблемы OSGi очень доходчиво было рассказано Никитой Липских. Он, кстати, есть на хабре — pjBooms


                      Не зря современные тенденции — использовать разные процессы (причем, иногда и с разными нативными зависимостями, как в docker) и объединять всё уже на уровне локального Nginx сервера. Ведь подобного рода разделение по процессам работает на уровне ОС без каких-то хаках в Java/.Net/и т.д.


                      1. sshikov
                        12.11.2017 17:31

                        По теме: если система доросла до того, что разные её части начали строго требовать разных зависимостей, то это знак того, что давно пора решать уже архитектурные проблемы. Как вариант: используйте микросервисы.

                        А вот прикиньте — нет у нас этих архитектурных проблем. От слова совсем. Порядка сотни модулей, в четырех OSGI контейнерах. В кластере. И наличие разных зависимостей при этом не создает вообще никаких проблем. Совсем никаких.


                        Не зря современные тенденции

                        Ну да, ну да. Хаков на уровне ОС не меньше, а значительно больше, чем в Java.


          1. vsb
            12.11.2017 08:36

            Было бы неплохо сделать возможность одновременного использования разных версий библиотеки в одном проекте.


            1. fzn7
              12.11.2017 11:12

              Загружайте куски разными ClassLoader`ами


            1. sshikov
              12.11.2017 11:15

              А вам никто не мешает это делать практически в любой версии Java. Заводите два classloader, в одном используете одну версию, в другом — другую. Даже если пакеты и классы идентичны по названиям — это все равно работает. Вопрос немножко в другом — чтобы сделать это контроллируемо и удобно. Впрочем, OSGI это вполне удобно позволяет делать тоже.


              P.S. Сорри, вон там ниже уже ответили ровно это же.


              1. vsb
                12.11.2017 16:50

                Мешает то, что на практике это не используется (для одного приложеия). На практике maven оставляет одну версию (даже если транзитивная зависимость от другой версии) и порой всё ломается, если совместимость между этими версиями плохая. Когда оно начнёт работать из коробки, тогда никто не будет мешать. А сейчас оно пригодно только чтобы независимые war-ки запускать в одном инстансе JVM.


                1. sshikov
                  12.11.2017 17:17

                  По большому счету, если это compile зависимость — то извините, но вы не можете скомпилировать с двумя ее версиями. Поэтому вторую версию и выкинут. А класслоадер — это рантайм, и сейчас проблема решается только там. Технически два толстых war в одной JVM — это и есть ровно то, чего вы хотите, потому что вы не указали сразу, что JavaEE вам не хочется :)


                  И что значит не используется? Это везде в JavaEE и OSGI. Этого полно. Это и есть из коробки — но это не значит, что это дается даром. Нужно уметь, но технических проблем тут нет никаких.


            1. CyberSoft
              12.11.2017 14:45
              +1

              Берёте и запихиваете библиотеки в разные слои из 9-ки. Под капотом тот же ClassLoader


              1. pjBooms
                13.11.2017 08:36

                Глядя на это обсуждения понял, что вероятно стоит сделать доклад про Jigsaw Layers с live coding и прочим.


      1. AstarothAst
        12.11.2017 22:31
        -1

        Насколько я понимаю, проект Jigsaw никогда не претендовал решать проблему Jar-hell в вашем проекте.

        Jigsaw постоянно сравнивают с OSGi, которая тоже претендует на решение именно этой проблемы (но не решает ее).

        Одним из источников Jar-hell, к примеру, является использование зависимостей, взятых черти где — скачанных с непонятных сайтов, без явно указанных версий, короче — разработка без использования maven/gradle/etc для управления зависимостями.

        Нет, вы не правы. Jar-hell возникает, когда две вполне легальные библиотеки, взятые из maven-central, используют разные версии третьей библиотеки, не поддерживающей обратную совместимость, что встречается сплошь и рядом.


        1. sshikov
          12.11.2017 23:01

          Нет, вы не правы.

          Это вам кажется. Сходите в гугль, например, и убедитесь, что в первых же пяти ссылках на эти ключевые слова будет пять разных формулировок проблемы jar hell.


          Суть на самом деле очень проста: если у вас нет нормального управления зависимостями, в вашем classpath могут появиться две разные версии одного и того же класса, и класслоадер загрузит ту из них, которая попадется ему первой, а не ту, которую вы ожидали. И транзитивные зависимости — лишь одна из многих причин, почему это бывает.


          1. AstarothAst
            13.11.2017 01:20

            Ок, и? Вы сами только что сказали, что jar-hell в одном из случаев возникает из-за транзитивных зависимостей — и эту проблему jigsaw не решает. Точно так же jigsaw не решает проблему «черте где взятых либ», но тут претензий никаких нет, к этому он никакого отношения не имеет и решать, соответственно, не должен. Но транзитивные зависимости — это то, с чем приходится жить ежедневно.


        1. sshikov
          12.11.2017 23:06

          И кстати, OSGI ее таки решает. В моей практике (3.5 года немаленького проекта) я не могу вспомнить симптомов jar hell на ровном месте.


          И даже если допустить, что они бывают — то во всяком случае, инструменты для решения имеются вполне адекватные. Во-первых, в classpath не попадает ничего из неизвестных источников, источник классов — только экспорт из бандлов, а экспорт из бандлов — это то, что прописано как экспортируемое.


          Во-вторых, если контейнер не смог однозначно заресолвить какие-то пакеты — то он по крайней мере это четко диагностирует. До того, как мы словим ClassCastException.


          1. AstarothAst
            13.11.2017 01:25

            И кстати, OSGI ее таки решает. В моей практике (3.5 года немаленького проекта) я не могу вспомнить симптомов jar hell на ровном месте.

            Уверен, вы найдете тут массу народа, который и без всякого OSGi в не маленьких проектах jar-hell не встречает :) Потому что бороться с ним и его симптомами можно многими средствами, от усиленного контроля того, что используется в проекте и до распиливания проекта на микросервисы.

            О том, что OSGi проблему не решает четко сказано в том самом докладе о котором речь идет в сабже, если мне не изменяет склероз, то примерно такими словами: «проблему не решает, просто переносит ее на другой уровень». Возможно докладчик не прав, тут сказать ничего не могу.


            1. pjBooms
              13.11.2017 09:05

              Я говорю про то, что две версии одной библиотеки все еще может приводить к проблемам в OSGi. Проблемы возникают когда эти две версии проползли в сигнатуры других бандлов и теперь вам эти бандлы надо подружить (заиспользовать одновременно, или заиспользовать саму библиотеку, когда она проползла в сигнатуры другого бандла). Если бандлы ваши, то придется серьезно порефакторить, если чужие заниматься оборачиваниям их или еще чем-то. Диагностика этой проблемы может быть уже не простым делом, решение еще более не простым. Почитайте статью одного из авторов OSGi на эту тему (я ссылку на нее давал в слайдах) — njbartlett.name/2011/09/02/uses-constraints.html


              1. sshikov
                13.11.2017 20:53

                Классы из зависимости в сигнатуре своего модуля — это вообще моветон. Хотя я могу допустить, что бывают разные ситуации. Подозреваю что без OSGI все будет еще хуже.


            1. sshikov
              13.11.2017 20:52

              Не, тут все проще. Да, переносит, на такой уровень, где с ней удобнее бороться. По-большому счету это все что нужно.


              А решить… ну я вот с удовольствием послушаю, как предлагается радикально раз и навсегда решить проблему, КРОМЕ КАК порезав приложение на части.


      1. acmnu
        13.11.2017 10:06

        Одним из источников Jar-hell, к примеру, является использование зависимостей, взятых черти где — скачанных с непонятных сайтов, без явно указанных версий, короче — разработка без использования maven/gradle/etc для управления зависимостями.

        Чего? С каких это пор внедрение maven магически избавляет от jar-hell. Обычно наоборот.


        1. sshikov
          13.11.2017 20:46

          Вы невнимательно прочитали. Тут написано, что работа без средств управления зависимостями это плохо. И моя практика показывает, что это почти всегда так — в руках джуниора такой проект скатывается в говно даже при одной зависмости, когда о конфликтах еще и речи нет.


          А вывод который вы делаете, что со средствами управлнения все шоколадно, тут не подразумевался. maven как и gradle не обещали, а тем более магически, полностью избавить от проблем управления зависимостями.


          Обычно наоборот.

          Опять же — maven или gradle это лишь инструмент. И в неумелых руках они могут творить любые чудеса, отформатировать диск, развязать мировую войну, и так далее. Может у вас они усиливают jar hell на порядок, я не знаю, вполне могу поверить.


          Но лично в моей практике, maven с включенным enforcer plugin, в режиме dependency convergence, плюс пара отчетов dependency:tree и dependency:analyze практически на 100% диагностирует проблему дублирования транзитивных зависимостей. А дальше, пардон, в большинстве случаев требуется только применение головы, потому что никакой инструмент за вас не сможет корректно выбрать между двумя разными версиями одной транзитивной зависимости.


          Если вы такой инструмент можете назвать — я с удовольствием послушаю.


          1. acmnu
            14.11.2017 10:36

            И в неумелых руках они могут творить любые чудеса, отформатировать диск, развязать мировую войну, и так далее. Может у вас они усиливают jar hell на порядок, я не знаю, вполне могу поверить.

            Пример такого усиления любой проект на apache.org. Это просто помойка с кодом, но помойка популярная, ибо BigData. Фактически любой антипатерн, который можно вообразить там есть.


            Фактически беда не в самом Maven, а в привычке скачивать полинтернета, чтоб написать Hello World. И в таких условиях maven пасует, не помогая толком работать с действительно большими и сложными проектами.


            1. sshikov
              14.11.2017 20:42

              Хм. Я не работаю на apache.org. Но по опыту знаю, что сегодня у меня 300-500 зависимостей в проекте — норма жизни. Не в смысле, что так надо, а в смысле, что это никаких проблем не вызывает. Подозреваю, что до 1000 можно довести без проблем. И опять же — мавен не решает этой проблемы. Его задача — именно скачать то, что попросили, и проверить, что зависимость А не встречается в двух версиях. Этого вполне достаточно.


              Я не знаю, о каких по размеру вы проектах говорите, но реально бОльшие просто надо однозначно дробить, чтобы не иметь дела с тысячами зависимостей вообще. И тут уже как-бы дело уже не столько в мавене — все равно инструмент это за вас не сделает.


  1. CyberSoft
    11.11.2017 20:19

    В час всё не уложишь, поэтому цель только зацепить, чтобы слушатель пошёл дальше и изучил тему подробнее в сети.


    Про "зачем" можно см. комментарий выше, по поводу jar-hell: его частично решили модулями, но чтобы всё это заработало, нужно потанцевать с бубном


    1. CyberSoft
      11.11.2017 20:28

      PS. Хабр, у тебя маловато времени для редактирования :(


  1. CyberSoft
    11.11.2017 20:25
    +2

    Над оператором Элвиса в девятке конечно поиздевались.



    1. vedenin1980
      11.11.2017 21:36

      Да уж, кто угодно мог написать ту же функцию, разве что теперь она в Objects (и со страшно длинным именем). Ну и смысл? Иметь как бы элвис оператор, хотя по сути обычная функция (if x != null? x: default_value), которую с первой Java не писал только ленивый.


      1. ZyXI
        11.11.2017 21:54

        Оператор от подобной функции будет отличаться тем, что если default_value — на самом деле какое?то вычисляемое выражение, то оно вычисляться не будет. Судя по картинке выше, называть новые функции «оператором Элвиса» неверно (иначе зачем существует Get версия?), но когда я прочитал про это в статье, то очень удивился: оператор, выглядящий как функция — разработчики Java совсем с ума сошли?


        1. sshikov
          11.11.2017 22:13

          Ну, на самом деле начиная с 8-ки уже можно (да и раньше в общем можно было, просто неудобно). Просто default_value — это должна быть лямбда, или функция.


  1. shishmakov
    11.11.2017 22:10

    литералы в коллекциях можно использовать с 7 версии

        List<Integer> list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 9];
        Set<Integer> set = { 2, 7, 31, 127, 8191, 131071, 524287 };

    Я не могу так сделать даже в Java 8, откуда вы это взяли?


    1. vlanko
      12.11.2017 00:19

      если у вас установлен ProjectCoin

      Частично вошло в 7ку, частично отменили


      1. poxvuibr
        12.11.2017 01:40

        если у вас установлен ProjectCoin

        Можно поставить ProjectCoin и использовать его плюшки? Как в случае с Lombok?


  1. vedenin1980
    12.11.2017 01:47
    +1

    1. Появление литералов в коллекциях — фигня, во всяких гуавах давно было,
    2. Внедрение оператора Элвиса — вообще обман, вместо оператора Элвиса с ленивыми вычислениями, дали ту функцию, что любой написать может, лучше уж ничего, теперь будут говорить что мы дали вам почти оператор Элвиса,
    9. Самая главная новость — ерунда :),
    6. Обработка процессов — специфично, но возможно полезно,
    5. IO, Regrexp — readAllBytes и transferTo? Полезно, конечно, но чтож очевидные вещи так долго до продакшена доходят?
    3. Class Optional + 4. Streams — самый полезные из всех фич в статье и толком не описанные (особенно Streams)
    7. Немного синтаксических изменений — НОООО! За что?! Приватные методы в интерфейсах? Вы серьезно? Завтра вы еще поля с конструктором туда добавите и возможность создавать инстанс интерфейса? Это называется изуродовали ООП в Java как бог черепаху. Золотую малину за такую фичу надо выдавать.


    1. TheKnight
      12.11.2017 05:57

      «Вначале они пришли за коммунистами». Надо было ругаться при введении default методов в интерфейсах.


      1. Myxach
        12.11.2017 08:58

        На самом деле, у опытных людей ругаться не было времени, а у начинающих были только лишь сомнение в правильности такого поступка, ну и тоже понимание неправильности этого, только неуверенные были, что бы ругаться


    1. Zoolander
      12.11.2017 07:11

      // Приватные методы в интерфейсах?… создавать инстанс интерфейса?

      Следите за моими руками — как можно это реализовать даже на версии до 8

      public interface SomeInterface {
          void exe();
      
          class Default implements SomeInterface {
              private Default(){}
              @Override
              public void exe() {
                  System.out.println("Default interface implementation");
              }
      
              public static SomeInterface getInstance() {
                  return new Default();
              }
          }
      }
      
      // ... где-то в другом месте
      SomeInterface someInterfaceImpl = SomeInterface.Default.getInstance();
      someInterfaceImpl.exe();
      
      


      1. vedenin1980
        12.11.2017 10:34

        Да это нормально, тут просто создается просто класс, который вызывается через интерфейс. Его можно и просто рядом положить. А дефолтные методы и приватные методы делают интерфейс почти неотличтмым от абстрактного класса.


        1. wlbm_onizuka
          12.11.2017 11:29

          Нет, не делают. Суть абстрактного класса в поддержке полиморфизма.
          Полиморфизм создает проблему при множественном наследовании, поэтому можно наследоваться только от одного класса, но реализовывать множество интерфейсов.
          Вы зря переживаете :)


          1. vedenin1980
            12.11.2017 17:30

            Интерфейс это контракт, на кой ему реализация? Это же логически неверно, интерфейс описывает API, если у него все методы дефолтные, то это уже не описание API, а его реализация.

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

            Ну как решается проблема множественного наследования дефолтных методов? Явным указанием какие методы будут использоваться, это очень похоже на то как решается эта проблема для классов других языков.

            Объясните какую проблему решают дефолтные методы и приватные методы в интерфейсах, которые невозможно было решить способами 1-7 Java? Очень похоже на попытку протащить множественное наследование в Java.


    1. sshikov
      12.11.2017 11:27

      Ну да. Все что нужно для Элвиса — это ленивость. Ленивость в виде лямбд сделали в прошлом релизе, а без них — можно было всегда, только очень многословно. Мораль — 2. синтаксическая плюшка, даже меньше, потому что синтаксиса как раз и не сделали.


    1. reforms
      14.11.2017 13:22

      9. Самая главная новость — ерунда :)

      А это как посмотреть. Я вот чувствую сколько прод решений отъедет из-за этого :)


  1. kovserg
    12.11.2017 11:21

    Java начала портиться. Интересно будет посмотреть на динамику размера дистрибутива при планируемых частых релизах.