Terry BRUNIER Terry BRUNIER - 4 months ago 23
Java Question

How can I replace an Observable anonymous inner class by lambda, including a logger, for multiple Couchbase access?

I started to use java 8 some days ago and I want to refactor some method using lambda.

The following method is used to get many documents from Couchbase :

public List<JsonDocument> bulkGet(final Collection<Long> ids) {
return Observable
.from(ids)
.flatMap(new Func1<Long, Observable<JsonDocument>>() {
@Override
public Observable<JsonDocument> call(final Long id) {
return bucket().async().get(docId(id)).doOnError(new Action1<Throwable>(){
@Override
public void call(Throwable throwable) {
logger.error("Error while bulk fetching SenderEmailAddress with id [" + docId(id) + "] from Couchbase.");
}
}).onErrorResumeNext(new Func1<Throwable, Observable<JsonDocument>>(){
@Override
public Observable<JsonDocument> call(Throwable throwable) {
return Observable.empty();
}
} );
}
})
.toList()
.toBlocking()
.single();
}


And this is the context :

private static final Logger logger = LoggerFactory.getLogger(SenderNameRepositoryCouchbase.class);

public String docId(Long entityId) {
return CouchbaseBucketFactory.APPLI_PREFIX + DOC_PREFIX + entityId;
}


Now, this is my refactored method with lambdas :

public List<JsonDocument> bulkGet(final Collection<Long> ids) {
return Observable
.from(ids)
.flatMap((Long id) -> {
return bucket().async().get(docId(id))
.doOnError(
(Throwable throwable) -> { logger.error("Error while bulk fetching SenderEmailAddress with id [" + docId(id) + "] from Couchbase."); }
).onErrorResumeNext(
(Throwable throwable) -> { return Observable.empty(); }
);
})
.toList()
.toBlocking()
.single();
}


But I'm told by SonarLint I should replace this by a method reference. But it's impossible to use a method reference like Class::method with an argument, isn't it ?

By the way, I should not be allowed to use my logger in a lambda, right ?
How can I do that ?
Is it really possible to refactor this class with lambda like Sonar suggests ?

Answer

Method references do match functional types that accept parameters. The compiler will find a method with the specified name whose parameters and return types are compatible with the functional interface called for. For example for a static method,

 Function<In,Out> op = in -> MyClass.doSomething(in);

which takes one parameter, is equivalent to

 Function<In,Out> op = MyClass::doSomething;

When it sees MyClass::doSomething, the compiler will see that it needs a Function<In,Out> and look for a static method in MyClass called doSomething that takes a parameter that can accept an In, and a return type that can be assigned to an Out.