Я усвоил сложный способ, которым scala внутренне использует запоминание в Streams.
Это была моя первая попытка решить проблему Эйлера 5
|
01
02
03
04
05
06
07
08
09
10
11
12
|
def from(n: Int): Stream[Int] = n #:: from(n + 1)def isDivisibleByRange(n: Int, r: Range) = { r.forall(n % _ == 0)}val a = from(21)val o = a.find(isDivisibleByRange(_, Range(2, 21)))o match { case Some(i) => println(i) case None => println("Nothing found!")} |
Я был немного озадачен тем, почему этот код генерировал ошибку OutOfMemoryError, благодаря Stackoverflow понял, что, поскольку ответ на эту проблему довольно высок 232792560, все целые числа в этом диапазоне будут запоминаться в разных узлах потока и, следовательно, проблема ,
Это на самом деле легко увидеть, позвольте мне сначала изменить функцию генератора потоков с побочным эффектом:
|
1
2
3
4
|
def from(n: Int): Stream[Int] = {println(s"Gen $n"); n #:: from(n + 1)}val s = from(1)s.take(10).toList s.take(10).toList |
Второе утверждение не напечатало бы ничего.
При таком поведении запоминания существует несколько возможных исправлений, самое простое — нигде не хранить ссылку на начало потока и использовать вместо него метод find итератора:
|
1
|
from(1).iterator.find(isDivisibleByRange(_, Range(1, 21))) |
В связи с этим примечание, потоки Java 8 не запоминаются, и решение с использованием потоков Java 8 (по общему признанию, может быть значительно улучшено) заключается в следующем:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
@Testpublic void testStreamOfInts() { Stream<Integer> intStream = Stream.generate(from(1)); List<Integer> upto20 = IntStream.rangeClosed(1, 20).boxed().collect(Collectors.toList()); Predicate<Integer> p = (i -> isDivisibleOverRange(i, upto20)); Optional<Integer> o = intStream.filter(p).findFirst(); o.ifPresent(i -> System.out.println("Found: " + i));}private Supplier<Integer> from(Integer i) { AtomicInteger counter = new AtomicInteger(0); return () -> counter.incrementAndGet();}private boolean isDivisibleOverRange(Integer n, List<Integer> l) { return l.stream().allMatch(i -> n % i == 0);} |
| Ссылка: | Мемориализация Scala Streams от нашего партнера JCG Биджу Кунджуммена в блоге all and sundry. |