Существует ли более элегантный способ представления следующего алгоритма с использованием Java API ядра?
Optional<Float> input = Optional.of(A);
Optional<Float> output = input.map(function1).map(function2);
if (!output.isPresent())
{
output = input.map(function1).map(function2);
if (!output.isPresent())
{
output = input.map(function3).map(function4);
if (!output.isPresent())
output = input.map(function5).map(function6);
}
}
То есть вместо вложенности нескольких вызовов isPresent()
я хотел бы вызвать метод, подобный map()
но это будет вызвано только в том случае, если значение отсутствует.
В идеальном мире я хочу вызывать что-то вроде:
Optional<Float> output = input.or(input.map(function1).map(function2), input.map(function2).map(function3), input.map(function4).map(function5));
Это то, что у меня есть до сих пор, но можем ли мы сделать лучше?
public class Optionals
{
/**
* @param <T> the type of value returned by the Optionals
* @param suppliers one or more suppliers that return a supplier
* @return the first Optional that {@link Optional#isPresent() isPresent()}
*/
public static <T> Optional<T> or(Supplier<Optional<T>>... suppliers)
{
for (Supplier<Optional<T>> supplier: suppliers)
{
Optional<T> candidate = supplier.get();
if (candidate.isPresent())
return candidate;
}
return Optional.empty();
}
/**
* Prevent construction.
*/
private Optionals()
{
}
}
Мне не нравится схема Supplier
в этом случае и, вероятно, предпочла бы такой подход:
public static void main(String[] args) {
Float x = 1.0f;
final Optional<Float> input = Optional.of(x);
Optional<Float> output = firstPresent(input, (a) -> a.map(FUNCTION1).map(FUNCTION2),
(a) -> a.map(FUNCTION3).map(FUNCTION4),
(a) -> a.map(FUNCTION5).map(FUNCTION6));
}
@SafeVarargs
public static <I,O> Optional<O> firstPresent(Optional<I> input, Function<Optional<I>, Optional<O>>... functions) {
for (Function<Optional<I>, Optional<O>> function : functions) {
final Optional<O> output = function.apply(input);
if(output.isPresent()) {
return output;
}
}
return Optional.empty();
}
Supplier
захватывает input
из внешнего блока кода, но да, это более явно.
Optional
имеет метод orElse
; если вы вызовете это, он вернет значение в Optional
если оно не пустое, или значение, которое вы передаете orElse
если оно пустое.
Таким образом, вы можете использовать вложенные вызовы orElse
, например:
Float output = input.map(function1).map(function2)
.orElse(input.map(function3).map(function4)
.orElse(input.map(function5).map(function6)
.orElse(0.0f)));
Обратите внимание, что конечный результат в этом случае не является Optional<Float>
а Float
. Если вы не хотите, чтобы возвращаемое значение по умолчанию, например, 0.0f
когда ни одно из сопоставлений не возвращало значение, вы могли бы, например, сделать это исключение:
Float output = input.map(function1).map(function2)
.orElse(input.map(function3).map(function4)
.orElse(input.map(function5).map(function6)
.orElseThrow(() -> new IllegalStateException("No result"))));
return Arrays.stream(suppliers).filter(supplier -> supplier.get().isPresent()).toArray();
Способ реализации "множественного условия" логического И с помощью предикатов Java8 (Йоси Лев):
public static void main(String[] args) {
Optional<String> stringOptional = Optional.of( "this is a string" );
Predicate<String> isNotNull = s-> s != null;
Predicate<String> isSizeGT0 = s-> s.length() > 0 ;
Predicate<String> isSizeGT20 = s-> s.length() > 20 ;
// calling isOk() with all required Predicates to be approved:
System.out.println(isOk(stringOptional, isNotNull, isSizeGT0, isSizeGT20));
}//main()
@SafeVarargs
private static <I> boolean isOk(Optional<I> inp, Predicate<I>... predicates){
// Enforce all predicates on input..
boolean b = Arrays.stream( predicates ).allMatch( pr->pr.test( inp.get()));
return b;
}
or
функцию вfirstOf
и просто использовал ее. Сдается мне как хорошее решение.