Subhomoy Sikdar
Subhomoy Sikdar

Reputation: 674

Java lambda not working with full definition

I am trying to wrap methods which throws checked exceptions.. I am following steps told in this url: https://www.rainerhahnekamp.com/en/ignoring-exceptions-in-java/

Interestingly when I write the code like this:

IntStream.range(1, locales.length)
            .mapToObj(i -> locales[i].toString())
            .forEach(wrap(this::testLocale));

it is working fine but when I write like this:

IntStream.range(1, locales.length)
            .mapToObj(i -> locales[i].toString())
            .forEach(s -> wrap(testLocale(s)));

Intellij is complaining "Unhandled Exception: java.lang.Exception"

here testLocale looks like this:

void testLocale(String s) throws Exception

The wrap function looks like this:

public static <T> Consumer<T> wrap(WrapConsumer<T> wrapper) {
    return t -> {
        try {
            wrapper.accept(t);
        } catch(Exception exception) {
            throw new RuntimeException(exception);
        }
    };
}

and WrapConsumer is a function interface with Consumer signature:

@FunctionalInterface
public interface WrapConsumer<T> {
   void accept(T t) throws Exception;
}

I am banging my head trying to understand why Intellij is complaining based on how I write the lambda

Upvotes: 3

Views: 172

Answers (3)

Eugene
Eugene

Reputation: 120848

You are supposed to provide a wrapped consumer to forEach via:

.forEach(wrap(this::testLocale));

what you are doing via s -> wrap(testLocale(s)) is provide a new consumer that still can't handle the checked Exception.

Probably simpler to understand would be that forEach accepts a Consumer that has a method definition of:

void accept(T t); // does not define to throw the checked Exception

When you do forEach(s -> ...), it is this Consumer::accept that you are using.

On the other hand that forEach(wrap(this::testLocale)); will return a Consumer still, but by accepting as input a WrapConsumer<T> wrapper that does declare to throw that Exception via:

void accept(T t) throws Exception;

Upvotes: 3

Brother
Brother

Reputation: 2210

Just complementing what Eugene answered, you are expecting with the method wrap() a consumer as param, not a invocation method returning void.

You can prove this by removing the throws Exception from the testLocale method.

The IDE will them give you the error:

"reason: no instance(s) of type variable(s) T exist so that void conforms to WrapConsumer<T>"

The similar code for the one you wrote (right consumer):

IntStream.range(1, locales.length)
        .mapToObj(i -> locales[i].toString())
        .forEach(wrap(this::testLocale));

Would be:

IntStream.range(1, locales.length)
        .mapToObj(i -> locales[i].toString())
        .forEach(wrap(l-> testLocale(l)));

Upvotes: 2

ernest_k
ernest_k

Reputation: 45309

You're just missing the correct lambda syntax. Your current code is calling wrap with a void argument: wrap(testLocale(s)) - (testLocale(s) has a void return type)

The correct lambda expression that you need is:

.forEach(wrap(s -> testLocale(s)));

wrap returns a function, so you don't need delayed execution for it (i.e., no need for a function that calls wrap).

Upvotes: 2

Related Questions