David David - 1 month ago 6
Java Question

My method returning an Optional cannot be used in a functional-like way

I am writing a method, that is intended to search a nested collection recursively for a value and return the collection, which contains that value:

@SuppressWarnings("unchecked")
public static <C extends Collection<?>,
E,
R extends Collection<E>> Optional<R> findRecursively(C collection, E element) {
if (collection.isEmpty())
return Optional.ofNullable(null);

boolean nested = collection.stream()
.allMatch(e -> isSubclass(e.getClass(), Collection.class));
for (Object c : collection) {
R result;

if (nested) {
Optional<R> recursiveResult = findRecursively((Collection<?>) c, element);
result = recursiveResult.orElse(null);
} else {
result = c.equals(element) ? (R) collection : null;
}

if (result != null)
return Optional.of(result);
}
return Optional.ofNullable(null);
}


This works fine, but when I use that method I cannot work with the returned Optional direktly without giving it to a variable first like this:

Collection<String> collection = null;
Set<String> set = Util.findRecursively(collection, "")
.orElseThrow(RuntimeException::new);


In that case the compiler cannot know the return-type of the method.
I don't know any good possibility to make it work.

I figured out 2 other ways, that are not very nice either:


  1. I add a parameter with type of the return-type that should be returned like:

    public static <C extends Collection<?>,
    E,
    R extends Collection<E>> Optional<R> findRecursively(C collection,
    E element,
    Class<R> returnType) {...


    But I don't like this, because the additional parameter is (actually) unnecessary and makes the method less easily understandable.

  2. Instead of an Optional I return just the collection-object. But in that case I cannot create an Optional directly with calling it either like:

    Collection<String> collection = null;
    Set<String> set = Optional.of(Util.findRecursively(collection, ""))
    .orElseThrow(RuntimeException::new);


    Because here again the compiler doesn't know the return-type and cannot infer the type-arguments to the
    of()
    method.



Does anybody have any idea of a nice solution for this issue? Or an advise which way to go here?

Answer

you can state the concrete types in the same line without declaring a var:

Util.<Collection, String, Set<String>>findRecursively(collection, "")...
Comments