автордың кітабынан сөз тіркестері Современный язык Java. Лямбда-выражения, потоки и функциональное программирование
Интерфейс ExecutorService отделяет отправку задачи на выполнение от непосредственно самого выполнения. По сравнению с использованием потоков и интерфейсом Runnable удобно то, что с помощью
1 Ұнайды
Эта модель носит название «модель стирания полиморфизма обобщенных типов» (erasure model of generic polymorphism). Подобный выбор требует определенных небольших затрат ресурсов во время выполнения, но главное для программистов — то, что параметрами обобщенных типов могут быть только объекты, а не простые типы данных.
Java 9, к сожалению, нанес больший ущерб обратной совместимости Java, чем любой другой выпуск (попробуйте, например, скомпилировать большую базу кода Java 8 с помощью компилятора Java 9). Но преимущества должной модульной организации оправдывают эту цену. Во-первых, она гарантирует лучшую и более строгую инкапсуляцию на уровне пакетов. На самом деле модификаторы видимости Java предназначены для задания инкапсуляции методов и классов, но на уровне пакетов возможен только один тип видимости: public.
Во-вторых, из слабости инкапсуляции на уровне пакетов непосредственно следует вывод, что без должной системы модулей неизбежно становятся видимыми элементы функциональности, относящиеся к обеспечению безопасности всего работающего в данной среде кода. Вредоносный код может получить доступ к критически важным частям модуля в обход всех мер безопасности.
В Java 8 были внесены колоссальные изменения как в смысле новых возможностей (лямбда-выражения и методы с реализацией по умолчанию в интерфейсах, например), так и новых полезных классов в нативном API, например Stream и CompletableFuture. В Java 9 не появилось никаких новых языковых возможностей, а просто доведено до ума начатое в Java 8
В функциональном программировании часто можно встретить функцию высшего порядка (скажем, в виде метода), принимающую, допустим, две функции и возвращающую третью функцию, каким-либо образом сочетающую две первых. Для описания такой концепции обычно используют термин «комбинатор» (combinator).
Наверное, главный вывод, который можно сделать из всего этого, — то, что смешивать изменяемое состояние с конкурентностью небезопасно. При функциональном программировании такой практики избегают, за исключением низкоуровневых трюков вроде кэширования. Второй вывод: при программировании в функциональном стиле никогда не нужно заботиться о том, синхронизирован ли другой функциональный метод, если только не считать трюков вроде кэширования, поскольку точно известно, что у него нет разделяемого изменяемого состояния.
В случае функциональной прозрачности можно легко избежать этих дополнительных накладных расходов. Одно из стандартных решений — мемоизация (memoization) — добавление к методу адаптера для кэширования (например, в структуре HashMap). Во-первых, этот адаптер будет обращаться к кэшу и проверять, не содержится ли там уже пара «аргумент, результат». Если да, он сразу возвращает сохраненный результат. В противном случае вызывается метод computeNumberOfNodes, но перед возвратом из адаптера новая пара «аргумент, результат» сохраняется в кэше.
еобходим просто способ отложенного вычисления вызовов метода primes из второго аргумента concat (на более формальном языке эту концепцию называют отложенным вычислением (lazy evaluation), нестрогим вычислением (nonstrict evaluation) или даже вызовом по имени (call by name)).
В идеале поток данных должен отфильтровывать числа, которые делятся на простые числа, генерируемые потоком данных.
