- Published on
Kotlin Higher Order Functions
- Authors
- Name
- Yair Mark
- @yairmark
Java 8 made it possible to pass lambdas around. This is really cool but I find it cumbersome when you need to define lambdas other than the ones in the standard function library. For example I had a case where I defined a template for a boiler plate piece of code where the handling of the error can change with different usages of the template. The standard library did not provide an error supplier so I had to roll my own out. This is not too bad as you define a functional interface but then I end up having to create more classes than I feel I need just to define the shape of a function I want as in the following:
package my.test;
@FunctionalInterface
public interface ErrorSupplier {
void handleError(Exception exceptionToHandle);
}
I would then use this in my code for example for something like the below:
package my.test;
import org.springframework.http.ResponseEntity;
import java.util.function.Supplier;
public class RestHandlerTemplate<T> {
public ResponseEntity processRequest(Supplier<T> requestToProcess, ErrorSupplier errorHandler) {
try {
return ResponseEntity.ok(requestToProcess.get());
} catch (Exception e) {
errorHandler.handleError(e);
return ResponseEntity.badRequest().build();
}
}
}
In Kotlin this is significantly easier and less verbose:
package my.test
import org.springframework.http.ResponseEntity
class RestErrorTemplate<T> {
fun processRequest(requestToProcess: () -> T, errorHandler: (error: Exception) -> Unit): ResponseEntity<*> {
return try {
ResponseEntity.ok(requestToProcess())
} catch (e: Exception) {
errorHandler(e)
ResponseEntity.badRequest().build<Any>()
}
}
}
Much better, we defined the errorHandler in the method inline without having to make a separate functional interface for it and it is also far more readable once you wrap your head around the syntax. This decompiles to the following Java code:
package my.test;
import kotlin.Metadata;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.ResponseEntity;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 1,
d1 = {"\u00004\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\u0018\u0000*\u0004\b\u0000\u0010\u00012\u00020\u0002B\u0005¢\u0006\u0002\u0010\u0003J?\u0010\u0004\u001a\u0006\u0012\u0002\b\u00030\u00052\f\u0010\u0006\u001a\b\u0012\u0004\u0012\u00028\u00000\u00072%\u0010\b\u001a!\u0012\u0017\u0012\u00150\nj\u0002`\u000b¢\u0006\f\b\f\u0012\b\b\r\u0012\u0004\b\b(\u000e\u0012\u0004\u0012\u00020\u000f0\t¨\u0006\u0010"},
d2 = {"Lmy/test/RestErrorTemplate;", "T", "", "()V", "processRequest", "Lorg/springframework/http/ResponseEntity;", "requestToProcess", "Lkotlin/Function0;", "errorHandler", "Lkotlin/Function1;", "Ljava/lang/Exception;", "Lkotlin/Exception;", "Lkotlin/ParameterName;", "name", "error", "", "production sources for module scrape_main"}
)
public final class RestErrorTemplate {
@NotNull
public final ResponseEntity processRequest(@NotNull Function0 requestToProcess, @NotNull Function1 errorHandler) {
Intrinsics.checkParameterIsNotNull(requestToProcess, "requestToProcess");
Intrinsics.checkParameterIsNotNull(errorHandler, "errorHandler");
ResponseEntity var10000;
ResponseEntity var3;
try {
var10000 = ResponseEntity.ok(requestToProcess.invoke());
Intrinsics.checkExpressionValueIsNotNull(var10000, "ResponseEntity.ok(requestToProcess())");
var3 = var10000;
} catch (Exception var5) {
errorHandler.invoke(var5);
var10000 = ResponseEntity.badRequest().build();
Intrinsics.checkExpressionValueIsNotNull(var10000, "ResponseEntity.badRequest().build<Any>()");
var3 = var10000;
}
return var3;
}
}