Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to write lambda expression for the abstract class

I have abstract class which have two methods as follows:

public abstract class SessionExecutionBody {
   public Object execute() {
     executeWithoutResult();
     return null;
   }

   public void executeWithoutResult() {}
} 

and I implement the class as follows:

final HTTPDestination destination = sessionService.executeInLocalView(new SessionExecutionBody() {
            @Override
            public Object execute() {
                userService.setCurrentUser(userService.getAdminUser());
                final String destinationName = getConfigurationService().getConfiguration().getString(DESTINATION_PROPERTY);
                return getHttpDestinationService().getHTTPDestination(destinationName);

When I run sonarLint its showing major issue convert this anonymous class to lambda expression but I am unable to find the way to right the same , Can I convert that expression into a lambda?

like image 474
Devendra Avatar asked Sep 26 '16 09:09

Devendra


2 Answers

I'm afraid you can't. That is not a functional interface with one abstract method to implement it in the lambda style.

Can I convert that expression into a lambda?

You could if you make the following changes:

@FunctionalInterface // to guarantee the next rule
interface SessionExecutionBody {
    Object execute(); // has exactly one abstract method

    default void executeWithoutResult() {} // other methods should be default/static
}
...
sessionService.executeInLocalView(() -> { /* a body */ return ...; })
like image 64
Andrew Tobilko Avatar answered Nov 01 '22 15:11

Andrew Tobilko


You can’t convert the subclass of an abstract class into a lambda expression and an audit tool saying otherwise can be considered to have a bug. As Andrew Tobilko showed, one solution to use a lambda expression here, would be converting the abstract class into an interface.

If that’s not an option, e.g. due to compatibility with other code using that class, you may offer factory methods for implementations simple enough to benefit from lambda expressions, while still allowing subclassing:

public abstract class SessionExecutionBody {

    public static SessionExecutionBody withResult(Supplier<?> s) {
        Objects.requireNonNull(s);
        return new SessionExecutionBody() {
            @Override public Object execute() { return s.get(); }
        };
    }
    public static SessionExecutionBody withoutResult(Runnable r) {
        Objects.requireNonNull(r);
        return new SessionExecutionBody() {
            @Override public void executeWithoutResult() { r.run(); }
        };
    }

    public Object execute() {
        executeWithoutResult();
        return null;
    }

   public void executeWithoutResult() {}
}

which you can use as

final HTTPDestination destination = sessionService.executeInLocalView(
    SessionExecutionBody.withResult(() -> {
        userService.setCurrentUser(userService.getAdminUser());
        final String destinationName = 
            getConfigurationService().getConfiguration().getString(DESTINATION_PROPERTY);
        return getHttpDestinationService().getHTTPDestination(destinationName);
    }));
like image 24
Holger Avatar answered Nov 01 '22 15:11

Holger