Pull to refresh

Comments 44

UFO just landed and posted this here
В 9 сильно поменяли работу с памятью и многопоточность. Не работает даже на Висте.
UFO just landed and posted this here
Хм, Oracle Open JDK 9 пашет на висте. Похоже, Zulu еще больше обленились.
Это очень актуально, особенно после новости, что прекращена поддержка Windows 7:)
Или это был троллинг?
Ага, вот прекратили поддержку, и мы все дружно бежим выбрасывать старые компы и покупать новые, чтобы на них новая ОС завелась…

Я вот не вижу никаких принципиальных причин, почему невозможно продолжать писать ПО (и не только Java, а вообще), не используя добавившиеся в новых версиях ОС API (вроде бы, их не так уж много? и там нет ничего мега-необходимого? или я чего-то не знаю?). Ну, кроме стандартного программистского «ой, я тут фреймворк зачем-то обновил, а он старую ОС не поддерживает — ну и фиг с ней!»
Ага, вот прекратили поддержку, и мы все дружно бежим выбрасывать старые компы и покупать новые, чтобы на них новая ОС завелась…

Так M$ и на это рассчитывает...


Я вот не вижу никаких принципиальных причин, почему невозможно продолжать писать ПО

Весь этот груз под названием "легаси" всё труднее и труднее поддерживать так, чтобы при этом ещё новые плюшки завести. Желательно без костылей

Вот если бы речь шла о выкидывании поддержки IE6 из какого-нибудь веб-фреймворка, то тут можно было бы говорить про тяжёлый груз поддержки «легаси». А в случае винды, когда старое API не меняется, а только добавляется немножко новых функций, это не так.
UFO just landed and posted this here
И какую проблему это решит? А что после peek будет?

Решит скорее не проблему, а правильное использование стримов + избыточный код, за что вы ратуете в этой статье. +нет необходимости создавать коллекцию.
после peek будет то же самое, что и в for

API Note: This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline

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


Но для замены обычного цикла лучше всего Files.list(srcDir).forEach(src-> { ... });, если хочется заменить, конечно.

peek работает не на всех терминальных операциях (например count)
API Note:
This method exists mainly to support debugging… In cases where the stream implementation is able to optimize away the production of some or all the elements (such as with short-circuiting operations like findFirst, or in the example described in count), the action will not be invoked for those elements.
(Кстати, когда уже наконец Stream отнаследуют от Iterable? Хочется просто писать for (Path file: Files.list(dir)), а не возиться с промежуточными списками.)

Батюшка, да куда же Вам обновляться с java 8, коль вы основную фичу java 8 ещё не поняли? :)

Думаю, речь про отказ от for в пользу стримов в данном конкретном примере

Если переписать на Stream, то придётся ловить IOException. В этом то и проблема.
Если переписать на Stream, то придётся ловить IOException. В этом то и проблема.

Вас смущает, что не получится просто добавить в метод throws IOException, а придётся обрабатывать его внутри forEach? Но ведь вы всё равно не будете использовать проверяемые исключения в своём коде, если это не тестовый метод или учебный пример. Исключение же всё равно надо будет завернуть в какой-нибудь RuntimeException внутри метода. Тем более, что try блок у вас там уже есть.

Для случаев, когда есть только один is*, можно использовать Predicate.not вместо отрицания:


long emptyCount = stream
    .filter(not(Optional::isPresent))
    .count();

Как отсюда вытащить цифру 8? Наверное, надо взять java.specification.version, отбросить 1., потом сконвертировать строку в число… Но не торопитесь, потому что на Java 9 это всё сломается:

Однако не печальтесь, потому что в Java 9 появилось нормальное API для получения версий

Поэтому на восьмёрке продолжаем строить велосипед.

Поэтому на восьмёрке продолжаем строить велосипед.

А можно использовать чужой велосипед, например JavaVersion из org.apache.commons:commons-lang3.

Кому-то не захочется/не понравится тащить ещё одну зависимость в проект. Тем более если велосипед в пару строк, а может быть даже и тестом покрыт.

Predicate.not и Optional.isEmpty появились одновременно в Java 11, поэтому в данном случае not не даёт погоды. Но в других случаях, да, он может быть полезен, например: not(Collection::isEmpty).
(Кстати, когда уже наконец Stream отнаследуют от Iterable? Хочется просто писать for (Path file: Files.list(dir)), а не возиться с промежуточными списками.)

Вообще стоит понимать что Stream, возвращаемый из java.nio.file.Files#list(Path), рекомендуется оборачивать в try-with-resources так как он потребляет ресурсы:


This method must be used within a try-with-resources statement or similar control structure to ensure that the stream's open directory is closed promptly after the stream's operations have completed.
Спасибо, это важное замечание. Исправил.
в сигнатуре write() есть throws IOException

Интересно, что мешало в BAOS переопределить write(byte[]) так, чтобы он не мог кидать исключение.

Потому что это сломало бы код у тех, кто пишет так:

class MyBAOS extends ByteArrayOutputStream {
    @Override
    public void write(byte[] b) throws IOException {
        // код, который может кинуть IOException
    }
}

О, точно, можно же так делать. Да, получилось бы плохо.
Ох уж эти промахи прошлого.

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

ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
    baos.write(bytes);
} catch (IOException ex) {
}


Если у write убрать IOException, то catch больше не будет компилироваться.
Кстати, когда уже наконец Stream отнаследуют от Iterable?

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


Но в принципе, можно так:


Stream<String> s = Stream.of("GNU", "is not", "Unix");

Iterable<String> iterableStream = s::iterator;
for(String : iterableStream) {
   ...
}

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

Поддержка for:each для Stream — это всё-таки не то же самое, что "унаследовать Stream от Itrable". Кроме того, даже по ссылке как раз ничего не говорится про прямое наследование, потому что прямое наследование не сработает — они пытаются выделить отдельный подтип, который уже можно применить и внутри конструкции, и может быть даже утащить под неё же DirectoryStream.

Какая разница, прямое наследование или нет? Да, хотят сделать IterableOnce, но это общей картины не меняет: Stream<T> <: IterableOnce<T> <: Iterable<T>. И почему прямое наследование не сработает? Аргументы предоставьте.

Я ведь уже говорил, почему не сработает (и не только я, даже в вашей ссылке есть). Iterable — это фабрика независимых друг от друга итераторов. В отличии от Stream. Введение IterableOnce extends Iterable сломает ожидания в немалом количестве кода — компилироваться не прекратит, но работать без исключений уже не сможет.
Например, образцово показательно окажется сломанным com.google.common.collect.Iterables.cycle — а библиотека вовсе не маленькая и не редкая. По второй ссылке видно, что нависнет проблема с библиотекой AssertJ. Подобная же проблема будет с Hamcrest. И так далее и тому подобное.
И вся эта возня костылями по песку чтобы получить break и continue? Что такого они могут чего не сумеют .filter() и .takeWhile().count()? Пример из пропозала вообще решается через teeingCollector — и, прошу заметить, без введения неопределённости в поведение интерфейса из единственного метода.

По второй ссылке видно, что нависнет проблема с библиотекой AssertJ

Какой второй ссылке? Какая проблема?
Какой второй ссылке?

Да вот этой самой, которая IterableOnce. В части Analysis.


Есть немалая категория кода, которая ожидает, что из Iterable можно получить сколько угодно итераторов. Сам пропозал называет один, я назвал ещё один. Пока все реализации ограничены сравнительно редким DirectoryStream, проблема небольшая. Если сюда же внезапно добавить крайне распространённые BaseStream сотоварищи, частота вырастет многократно, причём, будет нарушен principle of least astonishment (мало вам Collection::add и Collections.unmodifiable*, черти?). С Iterable, к сожалению, сложилась такая ситуация, когда параллельно официально закреплённым гарантиям есть неформальное соглашение, и именно с неформальной частью люди сталкиваются намного чаще.

Есть немалая категория кода, которая ожидает, что из Iterable можно получить сколько угодно итераторов.

Не вижу проблемы. Значит, такому коду не надо передавать Stream и всё.
В любом случае, наследование Stream от Iterable принесёт во много раз больше пользы, чем вреда.
Кстати, если вы почитаете javadoc к Iterable, то увидите, что там нигде не написано, что iterator() можно вызывать сколько угодно раз. Так что те, кто завязался на то, что обойти Iterable можно много раз – сами себе злобные Буратины.
наследование Stream от Iterable принесёт во много раз больше пользы, чем вреда.

Всё-таки, основное назначение Stream — это внутренняя обработка данных в лямбдах, которая из-за этого хорошо параллелится, и ленивость обработки в целом, когда не надо материализовывать больше, чем запросили. И если ленивость ещё как-то ложится на этот forEach, то вот способности параллелиться и прочему наследование от Iterable строго ортогонально. Иными словами — я в этом пользы не вижу, только увеличение семантической нагрузки, звоночком о чём является наше с вами копание в javadoc, к примеру. Значительно больше пользы погут принести остальные JEP. Вот к примеру разработка человеческого лица для Panama принесёт куда больше пользы. Вдвойне больше пользы принесёт возможность JIT рекомпилировать блоки кода так, чтобы они использовали Panama для ускорения числодробилок, даже если явных вызовов изначально в коде нет. И так далее, и тому подобное.

Sign up to leave a comment.

Articles