В Data Geekery мы любим Java. И так как мы действительно входим в свободный API jOOQ и запросы DSL , мы абсолютно взволнованы тем, что Java 8 принесет в нашу экосистему. Мы пару раз писали о приятных вкусностях Java 8 , и теперь мы чувствуем, что пришло время начать новую серию блогов,…
Ява 8 Пятница
Каждую пятницу мы показываем вам пару замечательных новых функций Java 8 в виде учебника, в которых используются лямбда-выражения, методы расширения и другие замечательные вещи. Вы найдете исходный код на GitHub .
Java 8 Goodie: простое как пирог локальное кэширование
 Теперь приготовьтесь к одному из самых удивительных открытий в этой серии.  Мы покажем вам простой способ реализовать локальный кеш, используя старые добрые выражения ConcurrentHashMap и лямбда-выражения.  Потому что в Map теперь есть новый способ атомарного вычисления нового значения в случае отсутствия ключа .  Идеально подходит для кэшей.  Давайте углубимся в код: 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | publicstaticvoidmain(String[] args) {    for(inti = 0; i < 10; i++)        System.out.println(            "f("+ i + ") = "+ fibonacci(i));}staticintfibonacci(inti) {    if(i == 0)        returni;    if(i == 1)        return1;    System.out.println("Calculating f("+ i + ")");    returnfibonacci(i - 2) + fibonacci(i - 1);} | 
  Да.  Это наивный способ делать вещи.  Даже для небольших чисел, таких как fibonacci(5) , вышеприведенный алгоритм выведет огромное количество строк, поскольку мы повторяем те же вычисления в геометрической прогрессии: 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 | Calculating f(6)Calculating f(4)Calculating f(2)Calculating f(3)Calculating f(2)Calculating f(5)Calculating f(3)Calculating f(2)Calculating f(4)Calculating f(2)Calculating f(3)Calculating f(2)f(6) = 8 | 
То, что мы хотим сделать, это создать кеш из предварительно рассчитанных чисел Фибоначчи. Самый простой способ — запоминать все значения в кэше . Вот как мы строим кеш:
| 1 2 | static Map<Integer, Integer> cache     = new ConcurrentHashMap<>(); | 
  Готово!  Как упоминалось ранее, мы используем недавно добавленный Map.computeIfAbsent() для вычисления нового значения из source функции, только если у нас еще нет значения для данного ключа.  Кэширование!  И поскольку этот метод гарантированно выполняется атомарно, и поскольку мы используем ConcurrentHashMap , этот кеш даже является поточно-ориентированным, не прибегая к ручному применению synchronized любом месте.  И это может быть использовано для других целей, кроме вычисления числа Фибоначчи.  Но давайте сначала применим этот кеш к нашей функции fibonacci() . 
| 01 02 03 04 05 06 07 08 09 10 11 | staticintfibonacci(inti) {    if(i == 0)        returni;    if(i == 1)        return1;    returncache.computeIfAbsent(i, (key) ->                 fibonacci(i - 2)               + fibonacci(i - 1));} | 
Вот и все. Это не может быть проще, чем это! Хотите доказательства? Мы будем регистрировать сообщение на консоли каждый раз, когда мы на самом деле оцениваем новое значение:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 | staticintfibonacci(inti) {    if(i == 0)        returni;    if(i == 1)        return1;    returncache.computeIfAbsent(i, (key) -> {        System.out.println(            "Slow calculation of "+ key);        returnfibonacci(i - 2) + fibonacci(i - 1);    });} | 
Вышеуказанная программа напечатает
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | f(0) = 0f(1) = 1Slow calculation of 2f(2) = 1Slow calculation of 3f(3) = 2Slow calculation of 4f(4) = 3Slow calculation of 5f(5) = 5Slow calculation of 6f(6) = 8Slow calculation of 7f(7) = 13Slow calculation of 8f(8) = 21Slow calculation of 9f(9) = 34 | 
Как бы мы сделали это в Java 7?
Хороший вопрос. С большим количеством кода. Мы, вероятно, напишем что-то подобное, используя двойную проверку блокировки :
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | staticintfibonacciJava7(inti) {    if(i == 0)        returni;    if(i == 1)        return1;    Integer result = cache.get(i);    if(result == null) {        synchronized(cache) {            result = cache.get(i);            if(result == null) {                System.out.println(                    "Slow calculation of "+ i);                result = fibonacci(i - 2)                        + fibonacci(i - 1);                cache.put(i, result);            }        }    }    returnresult;} | 
Будучи убеждена?
Обратите внимание, что ваше реальное решение, вероятно, будет использовать кэши Guava .
Вывод
Лямбды — это только одна часть Java 8. Важная часть, но давайте не будем забывать обо всех новых функциях, которые были добавлены в библиотеки и которые теперь можно использовать с лямбдами!
Это действительно захватывающе и …
Мы можем значительно улучшить наши кодовые базы, не прибегая к новым библиотекам. Все вышеперечисленное может быть запущено только с библиотеками JDK.
На следующей неделе в этой серии блогов мы рассмотрим, как Java 8 улучшит существующие и новые API параллелизма, так что следите за обновлениями!
Подробнее о Java 8
А пока взгляните на удивительную страницу ресурсов Java 8 от Eugen Paraschiv.