5

I have a following production ready java 8 method; which

  • iterates over a list
  • filters based on predicate
  • if finds 0 method based on filter, throw RuntimeException with message 1.
  • if finds more than 1 method based on filter, throw RuntimeException with message 2.
  • else return the found method itself

I achieved what I wanted using some lambda magic with 90s if else...

private Method getEventHandler(Class listener, Class<? extends Event> event) {
    List<Method> methods = asList(listener.getMethods())
            .stream()
            .filter(method -> shouldHandleEvent(method, event))
            .collect(Collectors.toList());

    if ( methods.size() == 0 ) {
        throw new RuntimeException("No event handlers");
    } else if ( methods.size() > 1 ) {
        throw new RuntimeException("More than one handler.");
    }

    return methods.get(0);
}

private boolean shouldHandleEvent(Method method, Class<? extends Event> event) {
    return method.getParameterCount() ==1 && 
           method.getParameterTypes()[0].isAssignableFrom(event);
}

If I had only two conditions, where I would be checking for exact 1 or more/less than 1, I could have written code as below,

private Method getEventHandler(Class listener, Class<? extends Event> event) {
         return asList(listener.getMethods())
            .stream()
            .filter(method -> shouldHandleEvent(method, event))
            .findFirst()
            .orElseThrow(() -> new RuntimeException("No event handlers"));
}

But, I've three conditions to check and I'm trying to act as if I live in 2016, so trying to use lambda to replace the if else in the first method, so that it is even more cleaner.

My guess is something as below,

private Method getEventHandlerProposed(Class listener, Class<? extends Event> event) {
      return asList(listener.getMethods())
            .stream()
            .filter(method -> shouldHandleEvent(method, event))
            .collect(Collectors.toList())
            .stream()
            .count() == 0 -> throw new RuntimeException("No event handlers");
            .or
            .count() > 1 -> throw new RuntimeException("More than one handler.");
            .orElse()
            .findFirst()
            .get();
}

I am sure it's not possible as I am suggesting but looking for some neat lambda that could make it look better and make me happy.

Chris Martin
  • 30,334
  • 10
  • 78
  • 137
prayagupa
  • 30,204
  • 14
  • 155
  • 192
  • .NET (speficially, LINQ 2 Objects) has a function .Single which does pretty much exactly what you want to do (throw if count !=1). https://msdn.microsoft.com/library/bb155325(v=vs.100).aspx Not sure if there's an equivalent in Java, but should be easy to implement. – Max Jan 16 '16 at 00:32
  • 1
    Well, I think you are trying to say something as `.findFirst()` - https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#findFirst-- in java that returns the first element of the `sequence` or an empty `Optional` is `sequence` is empty. – prayagupa Jan 16 '16 at 00:43

0 Answers0