Развертывание необязательного гуавы в одном выражении

Как разработчик Scala, который также работает в GWT, я приветствую добавление Optional в Guava.

Один из наших наиболее распространенных случаев использования Optional — это возврат необязательных значений из методов (как предлагается в ответе на В чем смысл необязательного класса Guava.

В scala я часто пишу такой код:

def someExpensiveOperation(params: Type): Option[ResultType] = ...
someExpensiveOperation(params).foreach({ val =>
  doSomethingWithVal (val)
})

Вариант Guava, похоже, не допускает ничего более элегантного, чем что-то вроде этого:

Optional<MyType> optionalResponse = someExpensiveOperation(params);
if (optionalResponse.isPresent()) {
    doSomethingWithVal(optionalResponse.get())
}

Локальная переменная является избыточной и требует повторения шаблона, который можно абстрагировать (if (optional.isPresent()) { doSomethingWith(optional.get()) }).

Другой вариант — вызвать метод, который дважды возвращает Optional:

if (someExpensiveOperation(params).isPresent()) {
    doSomethingWithVal(someExpensiveOperation(params).get())
}

Но это явно нежелательно, так как многократно вызывается дорогостоящая операция без необходимости.

Мне любопытно, как другие люди справились с этим очень распространенным случаем (возможно, написав статический служебный метод, такой как <T>useIfPresent(Optional<T> val, Closure<? super T> closure)?), или нашел ли кто-нибудь более элегантные решения.

Кроме того, если кто-нибудь знает, почему такой метод, как Optional.foreach(Closure<? super T> closure) (но, надеюсь, с более подходящим названием) был опущен, мне было бы любопытно услышать его обоснование.


person Yona Appletree    schedule 08.12.2012    source источник


Ответы (1)


Его там нет, потому что мы считаем, что неловкость анонимного класса при написании замыкания более неудобна и менее читабельна — по крайней мере, в Java, не обязательно в Scala, — чем локальная переменная и оператор if, которые вы уже написали.

Тем не менее, другой альтернативой является

for (Foo x : someExpensiveOperation().asSet()) {
  // do stuff with x
}

Обратите внимание, что здесь необходим asSet -- Optional сам по себе сознательно не реализует Iterable.

person Louis Wasserman    schedule 08.12.2012
comment
Немного OT, но мне интересно, почему Optional.asSet() возвращает Set вместо ImmutableSet, поскольку задокументировано, что он возвращает неизменяемую единицу. Это потому, что Optional поставляется в c.g.c.base, а не в c.g.c.collect? - person Xaerxess; 08.12.2012
comment
Это точно. (Система сборки Google более или менее запрещает циклические зависимости пакетов.) - person Louis Wasserman; 08.12.2012
comment
Это совершенно разумно. Я часто борюсь с врожденным конфликтом между тем, что кажется чистым функциональным способом, и отсутствием замыканий в Java. При этом я использую IntelliJ, который автоматически сворачивает анонимные внутренние классы в синтаксис закрытия в стиле JDK 8. В связи с этим, есть ли планы пересмотреть проектные решения, основанные на анонимных классах, когда Java 8 будет ближе к выпуску? - person Yona Appletree; 11.12.2012
comment
Пересмотреть? Возможно. Google все еще находится в процессе перехода на JDK7, не говоря уже о 8; у нас есть много пользователей, которые будут использовать JDK 5 в обозримом будущем. Посмотрим, что произойдет. - person Louis Wasserman; 11.12.2012
comment
ЖДК 5? Это очень плохо. Слоган Guava — Guava: основные библиотеки Google для Java 1.6+ :) - person Piotr Findeisen; 17.12.2012
comment
В настоящее время мы поддерживаем отдельный бэкпорт для пользователей JDK5. (Но, например, многие из наших пользователей являются приложениями для Android, которым нужна совместимость с Froyo, что сопоставимо с JDK5.) - person Louis Wasserman; 17.12.2012