В эту среду, 30 августа, в офисе компании Oracle состоялась встреча JUG.ru с Олегом Шелаевым, Developer Advocate в компании ZeroTurnaround, которая делает JRebel и XRebel. Тема встречи — инструменты создания многопоточных программ на Java (от конструирования велосипедов и запуска потоков ручками, до ForkJoinPool-ов, зеленых потоков и транзакционной памяти).


Конечно, мы поинтересовались, какие фишки Java 9 считают в ZeroTurnaround наиболее полезными. В результате, разжились статьей, которую вы сейчас читаете. Оригинал статьи Олег опубликовал в блоге RebelLabs, там есть еще много интересного.


Итак, начали.


Мы долго ждали Java 9, и вот, релиз уже не за горами. Ура! Это был не самый простой путь, но тем не менее, даже самые жаркие споры о системе модулей потихоньку продвигаются вперед, и большинство участников приходят к согласию. Скорей всего, релиз состоится совсем скоро, например, 21 сентября 2017 года.


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


Дальше будет список наших любимых новшеств в Java 9 API. В принципе, чтобы понять суть, достаточно взглянуть на примеры кода. Но можно запустить JShell и самостоятельно все эти примеры, своими глазами взглянуть на результаты.


Запускай JShell, я подожду… готов? Нет еще? Окей… сделал? Все еще нет? Да, на разгорев нужно время… ок, запустилось, отлично! Начинаем.


Фабричные методы для коллекций


Одна из наиболее ожидаемых фишек Java 9 — возможность делать литералы коллекций, чтобы удобней записывать самые простые случаи. Шутка, конечно, мы же говорим о Java, литералов у нас нет, есть только статические фабричные методы. Тем не менее, теперь мы можем легко создавать List, Map и Set, используя готовые методы:


jshell> List.of(1, 2, 3)
$1 ==> [1, 2, 3]

jshell> Set.of(1, 2)
$2 ==> [2, 1]

jshell> Map.of("hello", "world")
$3 ==> {hello=world}

Это стало возможным благодаря появлению статических методов в интерфейсах (Java 8), использовать которые научились List, Map и Set.


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


jshell> List.of(1).getClass()
$4 ==> class java.util.ImmutableCollections$List1

Стримы


В Stream API добавили парочку очень полезных возможностей. В частности, методы dropWhile и takeWhile. Как можно предположить по названию, dropWhile выбрасывает элементы с начала и до тех пор, пока не будет выполнено условие, а takeWhile — забирает элементы вплоть до выполнения условия.


jshell> IntStream.range(1, 10).dropWhile(x -> x < 5).forEach(System.out::println)
5
6
7
8
9

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


jshell> IntStream.iterate(0, x -> x < 3, x -> x + 1).forEach(System.out::println)
0
1
2

Если вам вдруг хотелось делать вычисления с фиксированной точкой на стримах, эта мечта может исполниться в Java 9.


Optional


Если вдруг кто не помнит, как их использовать, у нас есть отличная шпаргалка. В Java 9 наконец-то добавили метод or(), позволяющий в одну строчку связывать разные Optional’ы, не опускаясь до постоянных проверок на isPresent().


public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)

jshell> Optional.empty().or(() -> Optional.of("RebelLabs"))
$5 ==> Optional[RebelLabs]

Следующее хорошее дополнение — возможность преобразовывать Optional в стрим, содержащий не более одного элемента. Это реально полезно, если хочется использовать ленивые стримы. В примере ниже можно увидеть разницу своими глазами. Если вызвать map() на Optional, маппинг произойдет мгновенно, а вот на стриме — нет.


jshell> Optional.of(1).map(x -> x * 3)
$10 ==> Optional[3]

jshell> Optional.of(1).stream().map(x -> x * 3)
$11 ==> java.util.stream.ReferencePipeline$3@67b92f0a

И наконец, у нас появился метод ifPresentOrElse. В Java 8, можно было определить поведение только для случая, когда значение Optional существует. В Java 9 стало возможно указать два разных Runnable, определяющих что делать, если значение существует, и если не существует.


jshell> Optional.empty().ifPresentOrElse(x -> System.out.println(x), () -> System.out.println("empty"));
empty

Completable future


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


Один из самых крутых методов — это copy(), который возвращает немутабельную копию этого CompletableFuture. В следующем примере, мы создаем CompletableFuture, делаем его копию и проверяем, что завершение копии не влияет на исходный объект. Это очень-очень полезно, когда создается асинхронный API, возвращающий CompletableFuture. Раньше нужно было знатно помучиться, обруливая ситуации, когда клиент может сам завершить CompletableFuture, возвращенное из такого API. Сейчас достаточно просто взывать метод copy().


jshell> CompletableFuture<String> future = new CompletableFuture<>()
future ==> java.util.concurrent.CompletableFuture@35d176f7[Not completed]

jshell> future.copy()
$15 ==> java.util.concurrent.CompletableFuture@4973813a[Not completed]

jshell> future.isDone()
$17 ==> false

jshell> $15.isDone()
$18 ==> false

jshell> $15.complete("JRebel")
$19 ==> true

jshell> $15.isDone()
$20 ==> true

jshell> future.isDone()
$21 ==> false

Но самое крутое в том, что остановка родителя распространяется на все копии!


jshell> CompletableFuture<String> future = new CompletableFuture<>()
future ==> java.util.concurrent.CompletableFuture@4bbfb90a[Not completed]

jshell> future.copy()
$24 ==> java.util.concurrent.CompletableFuture@5a8806ef[Not completed]

jshell> future.complete("XRebel")
$25 ==> true

jshell> $24.isDone()
$26 ==> true

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


jshell> CompletableFuture<String> future = new CompletableFuture<>()
future ==> java.util.concurrent.CompletableFuture@67205a84[Not completed]

jshell> future.completeOnTimeout("Isn't this amazing", 1, TimeUnit.SECONDS)
$28 ==> java.util.concurrent.CompletableFuture@67205a84[Not completed, 1 dependents]

jshell> future.isDone()
$29 ==> true

API управления процессами


До Java 9, управление процессами было совершено не таким кроссплатформенным, как хотелось бы верить. Работа с подпроцессами раньше была несколько кривой, и вот в Java 9 её наконец выпрямили. Java 9 добавляет класс ProcessHandle, который предоставляет API для анализа текущего процесса, других процессов, найденных по пиду, их дочерних процессов, и так далее. Просто посмотрите на пример:


jshell> ProcessHandle current = ProcessHandle.current();
current ==> 6349

jshell> current.pid()
$33 ==> 6349

jshell> current.info().\TAB
arguments()          command()            commandLine()        equals(              getClass()
hashCode()           notify()             notifyAll()          startInstant()       toString()
totalCpuDuration()   user()               wait(

jshell> current.info().command()
$34 ==> Optional[/Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home/bin/java]

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


Еще одна популярная задача, которую будет куда удобней делать в Java 9 — запуск кода сразу после того, как процесс завершился. Java 9 предлагает для этого воспользоваться новым методом:


CompletableFuture<Process> onExit()

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


StackWalker


Возрадуйтесь, ненавистники исключений! Теперь можно работать со стектрейсами, не создавая объектов Exception. Добро пожаловать в StackWalker!


StackWalker дает возможность бродить по стеку, фильтровать его, и эффективно делать разные другие вещи. Этот пример выдернет верхние 5 элементов из стектрейса:


jshell> StackWalker.getInstance().walk(s -> s.limit(5).collect(Collectors.toList()));
$36 ==> [do_it$(java:36), jdk.jshell/jdk.jshell.execution.DirectExecutionControl.invoke(DirectExecutionControl.java:209), jdk.jshell/jdk.jshell.execution.RemoteExecutionControl.invoke(RemoteExecutionControl.java:116), jdk.jshell/jdk.jshell.execution.DirectExecutionControl.invoke(DirectExecutionControl.java:119), jdk.jshell/jdk.jshell.execution.ExecutionControlForwarder.processCommand(ExecutionControlForwarder.java:134)]

Улучшения в языке Java


Улучшаются не только API, но и сам язык. Во-первых, символ _(подчёркивание) больше не является корректным идентификатором. Если вы зачем-то его используете, придется перейти на двойное подчеркивание! (Подсказка: не делайте этого).


jshell> int _ = 1
|  Error:
|  as of release 9, '_' is a keyword, and may not be used as an identifier
|  int _ = 1
|      ^
|  Error:
|  reached end of file while parsing
|  int _ = 1
|           ^

jshell> int __ = 1;
__ ==> 1

Это для того, чтобы в будущем можно было заменять на подчеркивание ненужные (опциональные) параметры при вызове функции.


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


Вот вам небольшой синтетический пример:


jshell> interface A { private int zero() { return 0;} default int one() { return zero() + 1;}}
|  created interface A

Ну и наконец, последнее новшество. Теперь можно использовать effectively final переменные в блоках try-with-resources. Это упрощает код, не нужно больше объявлять переменные внутри try. Просто работаете с ними в блоке try, и это компилируется.


boolean a() throws Exception { 
  Socket s = new Socket(); 
  try (s) { } 
  return s.isClosed();
}

После выполнения блока try, все упомянутые там AutoClosable закономерно закроются.


Заключение


Ура! Мы рассмотрели кучу всего, и это далеко не все новшества, появившиеся в Java 9. Тем не менее, перечисленные выше вещи кажутся нам наиболее полезными, и пользоваться ими будут при первой возможности.


Выпуск Java 9 готовится уже довольно давно, и всем нам пора хорошенько разобраться, как она на нас повлияет. Сейчас это уместно как никогда, учитывая, что режим работы с clasthpath останется неизменным, и переход на Java 9 может оказаться простым и безболезненным. Можно прямо сейчас скачать готовую сборку Java 9, разобраться с новыми API, распробовать их, и приготовиться к наступающему светлому будущему!


Авторы


Олег Шелаев — Java-разработчик и Developer Advocate в ZeroTurnaround. Когда не занимается написанием java agent-ов или тестов, пишет в блог RebelLabs или выступает на конференциях. В свободное время пытается продвигать науку в Тартуском университете, изучая проблемы динамических обновлений программ.

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


  1. olegchir Автор
    31.08.2017 15:29
    -16

    Друзья, внесу немного оффтопика сейчас, т.к. завтра будет поздно. Сегодня (31 августа) — последний день, когда на Joker 2017 всё еще можно купить билеты по вкусной летней стоимости. До конца дня остались считаные часы. Кто хотел определиться — определяйтесь сейчас.


  1. Tyrr
    31.08.2017 16:22
    +3

    Хорошая статья! на некоторых моментах прям выдохнул) но выбор между интерфейсом и абстрактным классом теперь кажется сложнее, есть ли однозначный ответ, когда что выбирать?


    1. ferasinka
      31.08.2017 16:27
      +1

      У интерфейса нет и не может быть состояния.


      1. olegchir Автор
        31.08.2017 16:33
        +7

        public interface Отрывать {
            AtomicInteger руки = new AtomicInteger(10);
            private static void заТакое() {
                руки.set(11);
            }
        }
        


        1. Beholder
          31.08.2017 17:25
          +2

          Ну и это поле будет public static final, то есть состояния у интерфейса всё равно нет.


          1. igorperciuleac
            31.08.2017 18:29

            оно ведь mutable


            1. Beholder
              31.08.2017 18:32
              +3

              Ну состояние будет одно на весь classloader, а не на каждый объект, который реализует этот интерфейс.


              1. gamerforEA
                01.09.2017 18:07
                +4

                public interface StateInterface
                {
                	Map<StateInterface, Integer> states = new IdentityHashMap<>();
                
                	default int getState()
                	{
                		return states.getOrDefault(this, 0);
                	}
                
                	default void setState(int state)
                	{
                		states.put(this, state);
                	}
                }


                1. vlanko
                  02.09.2017 13:27
                  +1

                  Да, работает. Netbeans думает, что states статический финальный, но реально просто финальный.


                  1. dougrinch
                    02.09.2017 16:45

                    Он на самом деле статический.


                1. fogone
                  02.09.2017 21:44
                  +1

                  так и в ногу можно попасть. Даже не особо целясь


  1. AstarothAst
    31.08.2017 17:02
    +1

    CompletableFuture<Process> onExit()

    Я правильно понимаю, что с помощью этой штуки можно сделать процесс-маклауд? :)


    1. izzholtik
      31.08.2017 17:33

      Множественное наследование всё ближе? >:D

      А если серьёзно, то какого чёрта класс интерфейса содержит метод, возвращающий какую-то «избранную» реализацию?

      — не туда написал. Интерфейс у хабра всё ещё не тотр.


      1. olegchir Автор
        04.09.2017 13:00
        +1

        в таких случаях принято комментарий целиком заменять на слово «del», и потом писать в правильное место. Их обычно не минусуют, потому что всем и так ясно, откуда пошла такая фигня


    1. olegchir Автор
      31.08.2017 17:45
      +5

      Борис Бритва, или Борис-Хрен-Попадешь, резкий, как удар серпом по яйцам, и жесткий, как удар молотом. Живой советский герб. Говорят, эту сволочь вообще невозможно убить.

      www.youtube.com/watch?v=n7itx7O3b_k


  1. Beholder
    31.08.2017 17:33
    -2

    Половина или больше этих фич уже есть в Kotlin.

    Вот почему-то ничего не пишут, закрыли ли они кучу багов и реквестов по JavaFx.


    1. Optik
      01.09.2017 07:11
      +7

      При чем здесь вообще котлин? Все его фичи тоже уже были в других языках.


      1. werewolfspb
        01.09.2017 14:00
        -3

        При том, что, выходит, изменения в языке / stdlib уже почти не нужны при 100% Java <-> Kotlin interop — если кому нужен сахар, но возьмёт Котлин и будет использовать его. Или любой другой JVM-based язык и компилятор.
        Можно было бы сосредоточиться на платформе и hardcore фичах, типа modularity, а не на языке. Тогда бы и апдейты, глядишь, быстрее выходили.


        1. Optik
          01.09.2017 14:44
          +1

          В одном из предыдущих срачей топиков путем докапывания до котлин-адепта выяснилось, что интероп все же совсем не 100%. Также как и у других jvm языков.

          Тем кто пишет core-либы смириться и жить на старых возможностях языка? Стоит забить на тех, кому нравится java?


          1. werewolfspb
            01.09.2017 15:15
            -1

            Пришлите ссылку на топик, пожалуйста, если не лень, я бы с удовольствием почитал. Есть, конечно, нюансы, но они достаточно в крайних случаях мешают жить.

            Нет, на тех, кому нравится Java, не забить, претензии только к срокам выхода обновлений. Так-то это всё полезные безусловно вещи. Надеюсь, Гёц сотоварищи таки будут продвигать апдейты пошустрее.
            Просто те, кому нравится ТОЛЬКО Java, должны понимать, что они вот с такой скоростью будут получать обновления и плюшки. Это, кроме всего прочего, означает, что молодёжь будет изучать другие языки тоже и с бОльшим удовольствием придёт туда, где пишут не только на чистой Java.


            1. dzugaru
              02.09.2017 00:29
              +2

              >Это, кроме всего прочего, означает, что молодёжь будет изучать другие языки тоже и с бОльшим удовольствием придёт туда, где пишут не только на чистой Java.

              Слава богу, хипстеров нам в джаве только еще и не хватало. Пусть на джаваскрипте пишут.


        1. guai
          01.09.2017 14:44
          +3

          100% Java <-> Kotlin

          cool story, bro


          1. werewolfspb
            01.09.2017 15:16
            -2

            :) Киньте ссылок на доказательства обратного, пожалуйста, если есть :)


            1. guai
              01.09.2017 17:53

              ссылок нет. опыт есть. рекурсивные дженерики с котлином не пробовали поженить?
              да и не рекурсивные, бывает, глючат. Comparable с дженериком ему чота не нравится.
              «Добавьте мне override». Добавил. «Я не понимаю, зачем тут override» :)
              Приходилось делать странные финты ушами, типа сделать интерфейс на котлине, от него занаследовать явавский класс, от него опять котлин, чтоб только удовлетворить компилятор.


              1. werewolfspb
                01.09.2017 18:09

                Понятно, спасибо. Пока не пробовал с generics, попробую. Это какая версия была у вас?


                1. guai
                  01.09.2017 20:41

                  последний релиз


        1. vlanko
          01.09.2017 15:44
          +2

          фигню говорите.
          Оракл хотел ввести модульность. Но им не дали говнокодеры, не желающие переписывать свои программы. //Red Hat и IBM


          1. olegchir Автор
            04.09.2017 12:57

            Имхо там слегка сложней.
            Есть договоренность, что если спека всеми принята, то ее делают.
            А тут получилось, что люди прямо перед выпуском напрямую отказались от своих слов, посчитав их глупостью.
            И дело там не только в «переписывать программы», а в том, что изначальную спеку нужно делать куда масштабней и умней.
            Обычная мелкая гражданская война, в которой все правы и неправы одновременно, а страдают вообще другие люди :)


    1. DigitalSmile
      01.09.2017 09:26

      Вот почему-то ничего не пишут, закрыли ли они кучу багов и реквестов по JavaFx

      По состоянию на 2016 год (если не читали):
      static.rainfocus.com/oracle/oow16/sess/1462485593256001c2xn/ppt/JavaFX%209%20-%20New%20and%20Noteworthy.pdf


    1. olegchir Автор
      01.09.2017 19:08
      +2

      Java нужна потому, что это Java. Язык с невероятно долгой совместимостью и неформальными гарантиями что новые фичи будут хорошо работать очень долго (может быть, те же фичи будут использовать наши внуки), с хорошо подогнанными друг другу фичами (проходят годы обсуждений, прежде чем какая-то фича попадает на публику), с поддержкой Oracle, ну и в конце концов — это язык, на котором говорит большинство разработчиков в мире. Котлин — хороший язык, но он не об этом. Тем, кому нужна Java, нужна именно Java.


  1. Crandel
    31.08.2017 17:59

    -> IntStream.range(1, 10).dropWhile(x -> x < 5).forEach(System.out::println)
    |  Error:
    |  cannot find symbol
    |    symbol:   variable IntStream
    |  IntStream.range(1, 10).dropWhile(x -> x < 5).forEach(System.out::println)
    |  ^-------^
    

    Ubuntu 16.04


    jshell 9-internal
    
    java -version
    java version "9"
    Java(TM) SE Runtime Environment (build 9+181)
    Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)


    1. olegchir Автор
      31.08.2017 18:29
      +1

      java.util.stream.IntStream.range(1, 10).dropWhile(x -> x < 5).forEach(System.out::println)


      1. Crandel
        31.08.2017 22:30

        Спасибо, буду дальше изучать java


  1. k0ldbl00d
    31.08.2017 18:12
    -1

    JRE станет еще более параноидальным?


    1. Lure_of_Chaos
      01.09.2017 09:02
      +1

      Если Вы о системе модулей, то ДА.


      1. k0ldbl00d
        01.09.2017 10:23
        -1

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


        1. Lure_of_Chaos
          01.09.2017 10:35
          +2

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

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


        1. Inine
          01.09.2017 13:57

          Что, если специально для старого железа держать под рукой старый браузер и старую яву для него?


          1. k0ldbl00d
            01.09.2017 17:32

            Со старой и дурак сможет.


  1. b0tanic
    31.08.2017 18:27

    эт божественно


  1. snuk182
    31.08.2017 18:31
    +4

    jshell> Map.of("hello", "world")
    $3 ==> {hello=world}
    

    Полна боли и страдания жизнь без кортежей и/или классов данных.


    1. olegchir Автор
      31.08.2017 18:52
      +3

      Да, поэтому:
      1) в конпеляторе есть исследование литералов: http://openjdk.java.net/jeps/186 (это именно исследование, а не финальная спека). Она прям напрямую связана, с обсуждаемой здесь фичей convenience methods (http://openjdk.java.net/jeps/269). Фичу курирует Гёц.
      2) уже есть проротипы type values, я писал о них недавно, и буду еще. Фичу курирует Гёц же, и Роуз.


      Короче, всё будет, но не мгновенно. Возможно, ускорение релизного цикла, о котором недавно писал Рейнхольт, позволит выкатить подобные mast-have фичи поперед других, более масштабных, изменений, и мы увидим их в ближайшем будущем.


  1. Nakosika
    31.08.2017 18:57

    Почему они просто в библиотеку не добавили методы Optional? Зачем ждать новой версии языка?


    1. cypok
      01.09.2017 06:56
      +1

      Это не новая версия языка, это новая версия платформы Java, куда входит и язык, и стандартная библиотека, и тулинг (jshell, например).


    1. AndreyRubankov
      05.09.2017 09:57

      К счастью, в Java мире нету апгрейдов стандартной библиотеке в отрыве от выпуска новой версии платформы.
      Любое изменение SDK должно быть только в мажорных релизах, иначе будет хаос и про существование стабильности можно будет забыть.

      И да, ускорение релизного цикла – это было бы очень круто!
      Но с планами по развитию платформы, ускорение релизного цикла, это не такой простой шаг. Зарелизить те же Панаму или Валхаллу – это не так просто будет и скорее всего повлечет откладывания релизов на полгода-год.


  1. FCron
    31.08.2017 20:09
    +6

    Я один прочитал как JS hell?


    1. Lure_of_Chaos
      01.09.2017 09:01
      +1

      осталось только впилить шугара а ля json и плавающий контекст this


  1. AlexTheLost
    01.09.2017 00:02
    +7

    Выглядит и звучит так же, как когда чиновники говорят о прорывах которые в других странах появились уже 10 лет назад.)
    Что например мешало добавить удобные методы для создания и манипуляции коллекциями раньше, мне не понятно.


    1. Lure_of_Chaos
      01.09.2017 08:55
      +3

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


  1. Mercury13
    01.09.2017 08:19

    Что за приватные методы в интерфейсах?
    P.S. Понял: вероятно, общие куски кода для default-методов.


    1. olegchir Автор
      01.09.2017 11:12
      +1

      просто делаешь приватный метод, и он работает. private static тоже.


  1. Landgraph
    01.09.2017 08:40
    +1

    как скоро мы увидим что-то вроде for(x -> 0; x -> x < 10; x -> x+1).forEach(System.out::println)?


    1. Lure_of_Chaos
      01.09.2017 08:55

      когда носители ФГМ набигут


    1. olegchir Автор
      01.09.2017 12:46
      +1

      уже работает. IntStream.iterate(0, x -> x < 10, x -> x + 1).forEach(System.out::println)


  1. Lure_of_Chaos
    01.09.2017 08:52
    +5

    приватные методы в интерфейсах

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


  1. Lure_of_Chaos
    01.09.2017 08:58

    кстати, поправьте меня, если я неправ, но запилить некоторые примочки Optional и .of() можно собственными руками уже в java8


  1. fzn7
    01.09.2017 09:10

    Раз пошла такая пьянка, предлагаю выпилить for


    1. netch80
      01.09.2017 10:04

      Почему не while?


      1. fzn7
        01.09.2017 10:42

        Раз в год не грех выпилить одного барашка. While тоже хорош, но пускай еще подрастет


        1. Lure_of_Chaos
          01.09.2017 10:46
          +1

          Until убили сразу, куда While расти?


    1. Lure_of_Chaos
      01.09.2017 10:15

      Выпиливать — не наш метод.
      А вот без Properties, как в C#, до сих пор грустно. Как хорошо, что есть Lombok, правда, IDE его все так же не понимают…


      1. maddness
        01.09.2017 11:15
        +1

        Idea отлично его понимает через свой плагин


      1. olegchir Автор
        01.09.2017 11:19

        Гёц когда-то об этом говорил. Проблема в том, что проперти можно реализовать по-разному, и никакая из реализаций не подойдет всем желающим (включая желающих совместимости для легаси двадцатилетней давности). А маркетинговый эффект этой фичи будет минимальный, по сравнению с приложенными усилиями (т.е. если запилить что-то важное типа лямбд — это скорей будет стимулом поменять $languagename на Java, а вот введение пропертей — не особо)


      1. Nakosika
        01.09.2017 13:37
        +2

        Зачем они? Только баги провоцируют. Читаешь код и хз что происходит пока все поля не прощелкаешь и не убедишься что это не функции на самом деле.


      1. AstarothAst
        01.09.2017 13:43
        +1

        Idea + lombok plugin = Счастье!


      1. Urgen
        01.09.2017 13:57

        Eclipse тоже понимает, но только после плясок с бубном)


  1. Nagg
    01.09.2017 12:24
    +1

    Java, ну когда в тебе уже появится автовывод типов, ну невозможно смотреть на портянки.


    1. olegchir Автор
      01.09.2017 12:44

      В смысле, JEP-286? :) Когда-нибудь относительно скоро


    1. Beholder
      01.09.2017 17:44
      +1

      Kotlin вас ждёт


  1. blaketsk
    01.09.2017 12:59

    Это стало возможным благодаря появлению статических методов в интерфейсах (Java 8)

    Дефолтных?


    1. olegchir Автор
      01.09.2017 13:00

      public interface HelloWordable {
          public static void hello() {
              System.out.println("Hello World!");
          }
      }


      1. hazard2
        01.09.2017 15:34
        +2

        С удивлением понял, что можно написать вот так:

        public interface Main {
        
            public static void main(String[] args) {
                System.out.println("Hello World!");
            }
        
        }


        Или даже вот так:
        @SpringBootApplication
        @Configuration
        public interface TestApplication {
            public static void main(String[] args) {
                ApplicationContext ctx = SpringApplication.run(TestApplication.class, args);
            }
        }


        1. AstarothAst
          04.09.2017 10:30

          Было немного неожиданно…


      1. blaketsk
        01.09.2017 20:22

        оу, прикольно) не знал про такое


  1. SirEdvin
    01.09.2017 14:38

    А как там дело с модулями?


  1. elegorod
    04.09.2017 12:27

    List.of(1, 2, 3)

    Неожиданно, что это возвращает неизменяемый List. Типичная ситуация в моём коде — создать List или Map с парой элементов, а потом добавить туда ещё несколько. Через List.of это сфейлится в рантайме с Exception-ом. Думаю, многие проограммисты на этом обожгутся.

    Как теперь лучше создавать изменяемые списки, вот так?
    new ArrayList(List.of(1, 2, 3))

    Лучше бы сделали ArrayList.of(1, 2, 3)


    1. olegchir Автор
      04.09.2017 12:47
      +1

      Вопрос в том, что стратегический план должен корректировать не только саму форму API, но и способ того, как люди пользуются Java. Направлять мир в правильное русло. Это один из смыслов существования архитектурных советов и выпуска ими рекомендаций. Если бы нужен был просто вспомогательный метод, сделать его не проблема, или уже стащить готовый из Гуавы.

      С точки зрения всеобщей схемы всего, верной практикой считается использование иммутабельных конструкций. Нужно всячески поощрять разработчиков к иммутабельности, а стиль программирования — к функциональной чистоте.

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

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

      Я не чтобы оракул оракла, это чуть ли не открытым текстом сказано в JEP-269 Convenience Factories.

      В дальнейшем эти идеи могут быть развиты с помощью JEP-186 Collection Literals. Предлагается не мусорить с помощью List.of, а сразу писать List list = #[ 1, 2, 3 ];. Но это совершенно отдельный (тоже стратегический) вопрос.