2017-01-09 2 views
0

В функциональных языках является общим для использования сопоставления с образцом на дополнительных типах:Есть ли() на Java?

let result = match myOptional with 
      | Some x -> x * 2 
      | None -> 0 

Это очень полезно для программиста, так как компилятор проверяет, что шаблон спичка завершена.

Однако в примерах для Java-х Optional, что я видел, isPresent и get используются вместо:

Integer result; 
if (myOptional.isPresent()) { 
    result = myOptional.get() * 2; 
} else { 
    result = 0; 
} 

Для меня это поражения цели Optional. Компилятор не проверяет, чтобы обе ветви if были правильно реализованы, и полученный код не имеет дополнительных гарантий, чем эквивалент, используя null.

Этот вариант дизайна не рекомендует безопасность, поэтому почему стандартная библиотека предоставляет функцию get вместо match?

+0

Какую «правильность» вы хотите, чтобы компилятор проверял? Определенное назначение гарантирует, что вы назначили 'результат', прежде чем использовать его; Я не могу думать, что еще ты хочешь. (Возможно, я просто не могу вообразить здесь ...) –

+0

Да, это помогает программисту избежать NPE. – sdgfsdh

+0

«Это помогает программисту избежать NPE». Но какие NPE вы бы получили в этом случае? –

ответ

4

Фрагмент F # выше безопаснее, потому что он гарантирует, что результат всегда инициализируется. Оставляя один из двух случаев, возникает ошибка времени компиляции.

Это также было бы на Java: Java использует definite assignment для обеспечения инициализации локальных и конечных переменных.

Обратите внимание, что это не имеет никакого отношения к Optional, в частности: в любое время, когда компилятор может определить, что такая переменная не была инициализирована до ее использования, она вызовет ошибку.

Например:

int result; 
if (someCondition) { 
    result = 0; 
} 
System.out.println(result); // result might not have been initialized. 

Ideone demo

Ideone demo, using OP's code

Так что есть на самом деле не что-нибудь "небезопасно" об этой конструкции (в отношении присвоения локальных или конечных переменных).

+1

Хорошая работа, пытаясь понять, что означает OP! – assylias

+0

Не согласен. Инициализация - это только часть изображения. Компилятор не может убедиться, что программист не случайно перепутал ветки 'if'. Автор мог бы написать 'if (! Opt.isPresent()) {result = opt.get() * 2; } ', и это закончилось бы во время выполнения. – ZhekaKozlov

7

Это делается с помощью the Optional::map method. Ваш пример может быть написано:

Integer result = myOptional.map(i -> i * 2).orElse(0); 

Что касается методы get, был a discussion к принизить его - я не уверен, если решение еще не принято.

1

Да, обычно вам следует избегать звонка get(). Однако иногда это единственное удовлетворительное решение, поскольку возможности лямбда-выражений весьма ограничены.Вот список вещей, которые лямбды не может сделать:

  • Throw проверяемые исключения, если метод не имеет соответствующего throws декларацию
  • Изменить изменяемые переменные во внешней области видимости
  • Перерыв из цикла (или продолжить)
  • Возвращение из метода

Рассмотрим следующий пример:

if (opt.isPresent()) { 
    int value = opt.get(); 
    if (value == 0) { 
     throw new Exception("Catastrophical error!"); 
    } else { 
     // ... 
    } 
} 

С Consumer не поддерживает проверенные исключения, вы не можете переписать этот фрагмент кода с помощью lambdas простым способом.

Другие недостатки лямбды:

  • Longer трассировки стека
  • Harder для отладки
  • Требовать выделения памяти (важно для производительности критически важных приложений)

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