Reputation: 485
How to optimize method that returns the first non empty value returned of the checkN()
methods and prevent the rest method calls and isEmpty()
calls:
private String validate() {
String message = check1();
if (message.isEmpty()) {
message = check2();
}
if (message.isEmpty()) {
message = check3();
}
// total 5+ checks been called
return message;
}
#1 I thought of using stream filter and return first that has value, but it requires to call each check:
return Stream.of(check1(), check2(), check3(), ...).filter(message -> !message.isEmpty()).findFirst().orElse("");
SOLVED
as M A suggested, finalized solution for me was:
public static String method(Some a, Other b) {
return Stream.<Supplier<String>>of(
// for the methods without params
myClass::check1,
// for the methods with params
() -> check2(a),
() -> check3(a, b))
.map(Supplier::get)
.filter(StringUtils::isNotBlank)
.findFirst().orElse("");
}
Upvotes: 1
Views: 237
Reputation: 40047
You said you thought of stream filter first but a stream is not really required in this case.
List<Supplier<String>> checkList = List.of(this::check1,
this::check2, this::check3, this::check4, this::check5);
private String validate() {
String message;
for (Supplier<String> nextCheck : checkList) {
if (!(message = nextCheck.get()).isEmpty()) {
return message;
}
}
return "";
}
Note that you could have achieved the same optimization using your initial approach but changing the condition.
public String validiate() {
String message;
if (!(message = check1()).isEmpty()) {
return message;
}
if (!(message = check2()).isEmpty()) {
return message;
}
if (!(message = check3()).isEmpty()) {
return message;
}
// other message checks
return "";
}
Upvotes: 1
Reputation: 72884
Instead of constructing a Stream of Strings, you can do a Stream of Supplier<String>
, which would defer the invocation of the method until the filter needs to be checked in the stream pipeline:
return Stream.<Supplier<String>>of(this::check1, this::check2, this::check3, ...)
.filter(check -> !check.get().isEmpty())
.findFirst()
.map(Supplier::get)
.orElse("");
A better variant is to do the mapping from Supplier
to the result String
before the filter (the advantage is that this won't call the method with the non-empty result twice):
return Stream.<Supplier<String>>of(this::check1, this::check2, this::check3, ...)
.map(Supplier::get)
.filter(message -> !message.isEmpty())
.findFirst()
.orElse("");
Upvotes: 3