Loading...

Function Extensions Techniques 1: Business logic to be throwables

View: 119    Dowload: 0   Comment: 0   Post by: admin   Category: Javascript   Fields: Other

This serial of articles explains some techniques to relieve Lambda Expressions from the boiler plate codes of try/catch that required by the original functional interfaces, thus making lambda expressions to be real first-class members in JAVA 8.

Introduction

The introduction of Functional Interface and Lambda Expression open the gate to treat business logic as first class members in JAVA 8.
 
However, the contract of checked Exception handling of almost all Java Functional Interface methods declaration (any codes throwing any Java Exceptions need to be wrapped by try{}catch{}) makes it is extremely hard to define the concerned business logic as Lambda Expressions without Exception Handling of boilerplate codes.
 
This article introduces some techniques, used in my open source project com.easyworks.functionExtensions, to enable JAVA developers focuing on the business logic and leave the exception handling to a more generic means.

Background

In Java exceptions under Error and RuntimeException classes are unchecked exceptions, everything else under throwable is checked. If a method has any checked Exception, then it must either handle the exception explicitly or specify the exception using throws keyword.

There is no exemption with Functional Interface in Java 8: if the single abstract method defined doesn't throws some Exception, as those defined in java.util.function package, then the Lambda Expressions must handle any potential exceptions properly before being assigned to any Functional Interface instance.

For example, since Function<T,R> is defined with apply as below:

R apply(T t);

Suppose I want to keep the business logic of converting a String to a Class to getClass variable of Function<String, Class> type, a succinct Lambda Expression as below would always get error of "Unhandled exception: ClassNotFoundException":

Function<String, Class> getClass = className -> <s>Class.forName(className)</s>;

The Signature of Class.forName doesn't match the Function<T,R>.apply(T t) that demands you handle any Exceptions acompanied with the concerned business logic.

static Class<?> forName(String className) throws ClassNotFoundException 

Make Functions Throwable

To cope with this inconvenience, changing the corresponding Functional Interface method with "throws Exception" would delay the Exception Handling to some later stage, and make them much more friendly with Lambda Expressions.

@FunctionalInterface
interface FunctionThrowable<T, R> extends AbstractThrowable {
    R apply(T t) throws Exception;

To keep the expected operations reuseable, I would advise you to append "throws Exception" to the single abstract method signature and immediately, you can see Functional Interfaces to be much more friendly. Now assigning Class.forName to a FunctionalThrowable variable works.

FunctionThrowable<String, Class> getClass = Class::forName;

Such simple changes with Functional Interfaces makes Java method much more maintainable and flexible by treating business logic as variables.

I encountered this issue when trying to develop some generic OJDBC based Prepared/CallableStatement execution functions with signature like:

int call(Supplier<Connection> connectionSupplier, String procSignature, Object... args)

Given different types of args, the callableStatement generated from procSignature that has many "?" as placeholders would call different setXXX or registerXXX methods to call the statement and retrieve returned values properly.

The piling of dozens of if-elses presents not only a awkward , but also a rigid code structure that is hard to exend. My first attempt was to define a Functional Interface 

TriConsumer<PreparedStatement, Integer, Object> { void accept(T t, U u, S s) throws Exception;}

then a map

public static final Map<Class<?>, TriConsumer<PreparedStatement, Integer, Object>> setters = new HashMap<>()
setters.put(LocalDateTime.class, (statement, position, argument) -> statement.setTimestamp(position, Timestamp.valueOf((LocalDateTime) argument)));
setters.put(LocalDate.class, (statement, position, argument) -> statement.setDate(position, Date.valueOf((LocalDate) argument)));
setters.put(boolean.class, (statement, position, argument) -> statement.setBoolean(position, (boolean) argument));
setters.put...;

Enables following method to handle all kinds of arguments:

private static void setArgument(PreparedStatement ps, int position, Object argument) throws Exception {

    Class clazz = argument.getClass();
    if(argument == null || !setters.containsKey(clazz)){
        defaultSetter.accept(ps, position, argument);
    } else {
        setters.get(clazz).accept(ps, position, argument);
    }
}

Instead of using dozens of if else()..., the main processing flow is quite straight: choose the right business logic for a specific type of argument from a Map, or a default one if it is not defined, then applying it with the relative argument. Although I have delayed the Exception Handling by "throws Exception" with above method, it is fully possible to use a single try{}catch{} to handle any Exceptions thrown by setTimestamp()/setDate()/setBoolean().

More importantly, without a single line of code changes, it is possible to override the default Lambda for a specific class, or add new methods to handle any other customer classes would change the overall setArgument() behaviours gracefully. 

Conversions of Functional Interfaces

To identify functions without handling Exceptions, I have defined two sets of functional intefaces based on if they return something or not: RunnableThrowable and SupplierThrowable<T>. Both of them implement the empty AbstractThrowable, that is an marker-interface like Java Cloneable interface.

Most of the java.util.function counterparts, like FunctionThrowable<T,R>, PredicateThrowable<T>, BiFunctionThrowable<T,U,R>... HeptaFunctionThrowable<T,U,V,W,X,Y,Z,R> are defined as inner interfaces of SupplierThrowable<T>, while ConsumerThrowable<T>...HeptaThrowable<T,U,V,W,X,Y,Z> are defined as inner interfaces of RunnableThrowable.

The reason for me, is that they can always be converted to either SupplierThrowable<R> or RunnableThrowable. For example:

@FunctionalInterface
interface TriFunctionThrowable<T,U,V,R> extends AbstractThrowable {
    R apply(T t, U u, V v) throws Exception;

    default SupplierThrowable<R> asSupplier(T t, U u, V v){
        return () -> apply(t, u, v);
    }
}

By defining a default method with the functional interface with all necessary arguments, the TriFunctionThrowable (with 3 arguments) could be converted to another SupplierThrowable<R> instance (with no argument) with the given 3 arguments embedded. Or, for a method with n arguments, it is fully possible to create a partial function by applying n-1, n-2... arguments. This leads to some interesting use cases as illustrated in #Lambda with data.

On the other side, the nature of input data being captured by the lambda makes it less favorable: when you get the converted SupplierThrowable<R>, the supplied arguments "t, u, v" are fixed within the returned lambda expression, and you lose the chance to provide different set of t/u/v to the SupplierThrowable<R> to evaluate. For this reason, I would recommend execute the apply(t, u, v) logics in the way discussed in next section.

Split of Concerns with Exception Handling

Keeping the business logic as Lambda Expression of XxxxThrowable means the potential Exceptions still need to be handled at executing time.

Used with C# that doesn't require checked Exception handling, I don't think handling Exceptions within all the caller methods brings any benefit. At least for me, most of time, when forced to handle Exceptions within the method bodies with boilerplate codes is meaningless, and letting some generic utility to execute the business logics defined in #Make Functions Throwable and handle any exceptions would leave the business logic code free of such repeative try{}catch{} codes.

ExceptionHandler to cope with Exceptions

Such generic utility is implemented as Functions<R> class, when coping with any thrown Exceptions, a single business logic defined as a Functional Interface was defined as below to fulfill the job to handle Exceptions:

@FunctionalInterface
public interface ExceptionHandler<R>
        extends BiFunction<Exception, AbstractThrowable, R> {
}

The ExceptionHandler<R> extends BiFunction<Exception, AbstractThrowable, T> of java.util.function, so the only abstract method would be:

R apply(Exception t, AbstractThrowable u);

The signature without "throws Exception" means the corresponding lambda need to swallow the thrown exception, and return an Object of type R that could be returned by any of AbstractThrowable like BiFunctionThrowable, RunnableThrowable, TriConsumerThrowable and etc..

Functions<R> execute methods and handle Exceptions with ExceptionHandler

Then comes the generic AbstractThrowable executor Functions<R> that use the given ExceptionHandler<R>. Its only field and constructors are below:

private ExceptionHandler<R> handler;
private Functions(){
    this.handler = null;
}
public Functions(ExceptionHandler<R> handler){
    Objects.requireNonNull(handler);
    this.handler = handler;
}

Whenever the lambda or functions with arguments need to be executed. Depending on if the functional interface return value, actually only two methods need to be defined:

public void run(RunnableThrowable runnableThrowable){
    try {
        runnableThrowable.run();
    } catch (Exception ex){
        if(handler != null)
            handler.apply(ex, runnableThrowable);
        else
            throw new RuntimeException(ex);
    }
}

public <T> T apply(SupplierThrowable<T> supplierThrowable){
    return apply(supplierThrowable, supplierThrowable);
}

private <T> T apply(AbstractThrowable originalLambda, SupplierThrowable<T> supplierThrowable){
    try {
        return supplierThrowable.get();
    } catch (Exception ex){
        if(handler != null)
            return (T) handler.apply(ex, originalLambda);
        else
            throw new RuntimeException(ex);
    }
}

Taken T apply(SupplierThrowable<T> supplierThrowable) for example, if the lambda run smoothly to get the desired value of type T, it would be returned as usual.

When Exception ex is caught, and ExceptionHandler handler does exist, then it would get the chance to return something of type T based on the supplierThrowable, with a machenism to be introduced later.

Otherwise, when Exception is thrown and there is no ExceptionHandler<R> associated with Functions<R> instance, as the static Functions instance ThrowsRuntimeException, which is defined as:

public static final Functions ThrowsRuntimeException = new Functions();

It would simply throw a RuntimeException, which is unchecked, to terminate the application immediately

Functions<R> to execute methods with multiple parameters

Executing methods without any arguments is rare, usually our methods need to take one or multiple arguments. Although they can be converted to either SupplierThrowable<R> or RunnableThrowable as discussed in #Conversions of Functional Interfaces, their arguments would be captured and can not be fresh ones when executed by the Functions.

Instead, a set of methods are defined in the Functions<R> class to help evaluating methods with up to 7 arguments with fresh data, based on run(RunnableThrowable runnableThrowable) or T apply(AbstractThrowable originalLambda, SupplierThrowable<T> supplierThrowable).

For instance, with a function accept two arguments and return something differently as 

public static R someMethod(T t, U u) throws Exception;

The following generic method can evaluate with fresh arguments with the the unique T apply(SupplierThrowable<T> supplierThrowable) as below:

public <T,U,R> R apply(
        SupplierThrowable.BiFunctionThrowable<T,U,R> function,
        T t, U u){
    return apply(function, () -> function.apply(t,u));
}

The reason of including the original BiFunctionThrowable<T,U,R> function as the first argument is to make it possible to retrieve the return type information that has been erased in the second lambd expression () -> function.apply(t,u).

Consequently, following statement would execute the someMethod() and offload the Exception handling to the functions instance.

Functions.ThrowsRuntimeException.app(SomeClass::someMethod, t, u)

In this case, it would throw RuntimeException whenever an Exception is thrown by calling someMethod(t, u), but would return the result if nothing is wrong.

Throwing RuntimeExceptions is actually a anti-pattern discussed in Unchecked Exceptions — The Controversy. However, it is quite easy to change the manner of excetion handling with other Functions implmentations

Handling Exceptions Decently

To revisit T apply(AbstractThrowable originalLambda, SupplierThrowable<T> supplierThrowable): it is clear the supplierThrowable would be called and return an instance of type T if nothing is wrong.

private <T> T apply(AbstractThrowable originalLambda, SupplierThrowable<T> supplierThrowable){
    try {
        return supplierThrowable.get();
    } catch (Exception ex){
        if(handler != null)
            return (T) handler.apply(ex, originalLambda);
        else
            throw new RuntimeException(ex);
    }
}

However, if some exception is thrown, then the apply(Exception, SupplierThrowable) of the handler need to get some default value that is of type T to hide the exception. In many cases, that is what we can do within the routine catch{} modules.

Thanks to Java Type Erasure, although the signature of this generic class is Functions<R> where R is the return type that is not used, its actual implementation would be registered as Functions<Object>, an extra casting of (T)makes it possible to support any methods returning value of type T, only if the ExceptionHandler could get value of that type T.

To get the return type, following method is used to extract return type of any generic XXXThrowables before caching them to somewhere.

Notice: Please correct me if I am wrong. the Lambda Expression aThrowable cannot be a Lambda created by another Lambda that would get its return type erased. 

public static Class getReturnType(AbstractThrowable aThrowable){
    Objects.requireNonNull(aThrowable);
    Class instanceClass = aThrowable.getClass();

    ConstantPool constantPool = TypeHelper.getConstantPoolOfClass(instanceClass);
    Method functionInterfaceMethod = null;
    int index = constantPool.getSize();
    while(--index >=0) {
        functionInterfaceMethod = (Method) constantPool.getMethodAt(index);
        if(functionInterfaceMethod != null && functionInterfaceMethod.isSynthetic()){
            break;
        }
    }
    Class returnType = functionInterfaceMethod.getReturnType();
    return returnType;
}

Then another method of the Defaults.java would returned default values of specific types as outlined in Default Values.

Consequently, a static Functions variable is defined as below:

public static final Functions ReturnsDefaultValue = new Functions((ex, supplier) ->
        Defaults.defaultOfType(lambdaReturnTypes.get((AbstractThrowable) supplier, null)));

Basically, it retrieve and cache the default value of given Lambda expression as either primitive types of zero values, or null for any other objects. Such Exception Handling could be validated with following code.

Integer r = (Integer) Functions.ReturnsDefaultValue.apply(s -> Integer.valueOf((String)s), "33.3");
Assert.assertEquals(Integer.valueOf(0), r);

Moreover, the factory method below could be used to create more practical Functions instance.

public static <R> Functions<R> buildFunctions(RunnableThrowable.ConsumerThrowable<Exception> exeptionConsumer, SupplierThrowable.FunctionThrowable<AbstractThrowable, Object> defaultValueFactory){
    Objects.requireNonNull(exeptionConsumer);
    Objects.requireNonNull(defaultValueFactory);
    ExceptionHandler <R> handler = (Exception ex, AbstractThrowable supplier) -> {
        try{
            exeptionConsumer.accept(ex);
            return (R) defaultValueFactory.apply(supplier);
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    };
    return new Functions(handler);
};

Suppose I want to handle Exceptions differently: ignore some, log some and throw RuntimeException for others. In addition, for methods returning int value, the defualt value would be -1 instead of 0. Then a custom Functions could be created with following code snippet:

Class<? extends Exception>[] negligibles = new Class[]{
        NullPointerException.class, IllegalArgumentException.class
};
Class<? extends Exception>[] noticeables = new Class[]{
        SQLException.class, NumberFormatException.class
};
List<String> logs = new ArrayList();
RunnableThrowable.ConsumerThrowable<Exception> exHandler = ex -> {
    final Class<? extends Exception> exceptionType = ex.getClass();
    if(IntStream.range(0, noticeables.length).anyMatch(i -> noticeables[i].isAssignableFrom(exceptionType))){
        String msg = ex.getMessage();
        msg = ex.getClass().getSimpleName() + (msg == null?"":":"+msg);
        logs.add(msg);
    }else if(IntStream.range(0, negligibles.length).allMatch(i -> !negligibles[i].isAssignableFrom(exceptionType))){
        throw new RuntimeException(ex);
    }
};
SupplierThrowable.FunctionThrowable<AbstractThrowable, Object> defualtFactory = supplier -> {
    final Class returnType = Functions.getReturnType(supplier);
    if(returnType == Integer.class || returnType == int.class)
        return -1;
    return Defaults.defaultOfType(returnType);
};

Functions customFunctions = Functions.buildFunctions(exHandler, defualtFactory);

To validate its behaviour:

SupplierThrowable.BiFunctionThrowable<String[], Integer, Integer> ff = (sArray, index) -> sArray[index].length();
Integer result = (Integer)customFunctions.apply(ff, new String[]{"a", "ab"}, 1);
assertEquals(Integer.valueOf(2), result);

result = (Integer)customFunctions.apply(ff, new String[]{null, null}, 1);
assertEquals(Integer.valueOf(-1), result);

//Following statement would throw RuntimeException caused by ArrayIndexOutOfBoundsException
//result = (Integer)customFunctions.apply(new String[]{"a", "ab"}, 2, ff);

The NullPointerException or IllegalArgumentExceptions would be neglected, while NumberFormatException would be logged and both cases would return -1 when Exception caught. Other unexpected Exceptions like ArrayIndexOutOfBoundsException would be re-thrown as RuntimeException and terminate the application.

Change Exception Handlings Globally

Letting static Functions instances to handle Exceptions also enable the processing flows changed gracefully. Suppose there are many places execute business logic with the Functions.Default as below, then depending on if the app is switched to RELEASE mode by  setting a system property of "isRelease", the following sample method would return default value '0' in RELEASE mode, but throws RuntimeException in DEBUG.

@Test
public void switchingFunctions(){
    String inReleaseMode = (String)Functions.ReturnsDefaultValue.apply(s -> System.getProperty((String) s), "isRelease");
    Functions.Default = (inReleaseMode != null) ? Functions.ReturnsDefaultValue : Functions.ThrowsRuntimeException;
    SupplierThrowable.BiFunctionThrowable<String[], Integer, Integer> ff = (sArray, index) -> sArray[index].length();
    Integer result = (Integer) Functions.Default.apply(ff, new String[]{"a", "ab"}, 1);
    assertEquals(Integer.valueOf(2), result);

    result = (Integer)Functions.Default.apply(ff, new String[]{null, null}, 1);
    assertEquals(Integer.valueOf(0), result);
}

Lambda with data

I have come across a quite crooked framework: Calller classes need to invoke business logic of Callee classes that needs multiple input parameters. However, the Caller Class instance can only call TestResult execute(Class<?> testClass, String methodName) of Arquillian JUnitTestRunner that accepts only Class of the Callee and name of the called method, no place for extra arguments at all.

First, I managed to keep the input parameters as static variables of Caller classes or Callee classes to allow the Callee instances created by JunitTestRunner to access them to trigger the business logic accordingly. However, if there are multiple Caller classes are created to interact with multiple Callee classes, then invoking business logic that refers multiple static variables scattered in Caller/Callee classes is a nightmare for codes reuse.

Thanks to the data captuable nature of Lambda created by higher-order functions, this issue could be solved with following simplified pseudo codes. First, a Functional Interface is created as below:

@FunctionalInterface
public interface InvokableStep {
    void execute(Callee callee) throws Exception;
}

In the Callee classes, codes like below are created:

private static Stack<InvokableStep> stepStack = new Stack<>();
@Test
public void dontCallMeDirectly() throws Exception {
    InvokableStep step = stepStack.pop();
    Objects.requireNonNull(step);
    step.execute(this);
}

public static void doSomething(JUnitTestRunner junitTestRunner, String param1, String param2)
        throws Throwable {
    Objects.requireNonNull(junitTestRunner);
    InvokableStep step = calleeObj -> {
        Callee callee = (Callee)calleeObj;
        callee.privateMethod(param1);
        callee.privateField = param2;...
    };
    stepStack.push(step);
    junitTestRunner.execute(Callee.class, "dontCallMeDirectly");
}

In the Caller class, now it is possible to invoke something by calling doSomething directly:

  1. The input parameters (param1, param2) are provided directly, in addition to the junitTestRunner directly or indirectly;
  2. the InvokableStep instance step is created, accepting one instance of Callee only, consume the input parameters (param1, param2) directly with the given Callee instance that need to be casted to callee.
  3. the newly created instance step is pushed to the static stack.
  4. Then junitTestRunner trigger the only public instance method dontCallMeDirectly() would get the step instance created in 2), and applied with the Callee instance itself immediately.
  5. Since there is no contention in my case, and everything except Callee instance has been captured by the Lambda instance step, the business logic would be triggered with everything needed.

Well, the process is still quite twisted: the Caller class instance calls the static method of Callee class, which makes the junitTestRunner to create a new Callee instance, and make it executing the expected processes with its own private/public instance resources.

However, you can see it is quite clear that a Lambda Expression could be created with fresh data, thus eliminate many unnecessary variables used to convey the information to execute the business logic.

Summary

Time to conclude the techniques disucssed in this post:

  • Functional Interface without "throws Exception" forces the business logic to handle Exceptions, that hinder the Functional Programming with Lambda in Java 8.
  • A set of XxxxThrowable Functional Interfaces makes it possible to define only concerned business logic as Lambda variables, that can make the codes more modular, reuseable and concise.
  • All Funcitonal Interfaces could be converted to either RunnableThrowable or SupplierThrowable depending on if the business logic need to return something. Or, at least executing methods with 1 or multiple input arguments could happen just as execting RunnableThrowable or SupplierThrowable.
  • To split the concern of Exception Handling from the business logic defined by the XxxThrowable instances, generic class Functions could be used to execute common methods (with 0 to 7 input arguments) with an unique ExceptionHandler instance globally.
  • In addition to the default ReturnsDefaultValue and ThrowsRuntimeException static Functions instances, it is easy to create such global function executioner to meet specific requirements.
  • The overall behaviours of Exception Handling could be switched gracefully with Functions.Defaultinstance for those business logic being executed by it.
  • Finally, a interesting case to use Lambda expression to capture and carry any numbers of input parameters.

Using the code

This article means to introduce the techniques used in my open source project that would be published in early March, hopefully that would be helpful to create more Functional codes.

Points of Interest

In following 3 to 4 posts, I would discuss following topics/techniques developed in my project:

  • Tuple<> to manage multiple data variables as strong typed, immutable object easily.
  • Lazy<> and Repository<>/TupleRepository<> to bind business logic with data.
  • ROP (Railway Oriented Programming) with Result<>/ResultFunction.

Function Extensions Techniques 1: Business logic to be throwables

This serial of articles explains some techniques to relieve Lambda Expressions from the boiler plate codes of try/catch that required by the original functional interfaces, thus making lambda expressions to be real first-class members in JAVA 8.

Posted on 28-02-2018 

Comment:

To comment you must be logged in members.

Files with category

  • Mini Youtube Using ReactJS

    Mini Youtube Using ReactJS

    View: 25    Download: 2   Comment: 0

    Category: Javascript     Fields: none

    This is one the best starter for ReactJS. MiniYoutube as the name suggests is a youtube like website developed using reactJS and youtube API. This project actually let's you search , play and list youtube videos. Do check it out and start learning...

  • Angular 6 Starter with Laravel 5.6 API Service

    Angular 6 Starter with Laravel 5.6 API Service

    View: 62    Download: 0   Comment: 0

    Category: Javascript     Fields: none

    Angular 6 and Laravel 5.6 This project is a starter for creating interface with Angular using bootstrap && css && sass and using Laravel 5.6 for api requests. Demo Installation This project is divided in two parts (projects) and before use them you...

  • Simple Richtext Editor Based on pellJS

    Simple Richtext Editor Based on pellJS

    View: 26    Download: 0   Comment: 0

    Category: Javascript     Fields: none

    A simple visual editor for websites using the pell javascipt. It also has the option to switch between visual editor mode and source code mode. I will upload an update for new functionality soon. Source Code Editor Visual Editor

  • Data Visualization for BI: How to Design Layouts for .NET Financial Reports

    Data Visualization for BI: How to Design Layouts for .NET Financial Reports

    View: 37    Download: 0   Comment: 0

    Category: Javascript     Fields: Other

    With the Active Reports Server, you can have a multi-tenant environment where users from various departments, companies, or other specifications can log in, view their reports (and only their reports), export the data, or set up a distribution...

  • AngularJS and REST API

    AngularJS and REST API

    View: 204    Download: 0   Comment: 0

    Category: Javascript     Fields: Other

    This is a tutorial for those interested in a quick introduction to AngularJS and REST API. We will build the familiar Periodic Table of the Elements found in every chemistry textbook, and allow the user to select a Chemical Element by clicking on...

  • Collective Intelligence, Recommending Items Based on Similar Users' Taste

    Collective Intelligence, Recommending Items Based on Similar Users' Taste

    View: 168    Download: 0   Comment: 0

    Category: Javascript     Fields: Other

    Using Collaborative Filtering to find people who share tastes, and for making automatic recommendations based on things that other people like.

  • Think Like a Bird for Better Parallel Programming

    Think Like a Bird for Better Parallel Programming

    View: 157    Download: 0   Comment: 0

    Category: Javascript     Fields: Other

    Coding an application to run in parallel is hard, right? I mean, it must be hard or we’d see parallel programs everywhere. All we'd see are slick parallel apps that use every available core effortlessly. Instead multi-threaded apps are the exception...

  • Getting Started with the Bing Search APIs

    Getting Started with the Bing Search APIs

    View: 169    Download: 0   Comment: 0

    Category: Javascript     Fields: Other

    Bing Search API is a set of REST interfaces that find web pages, news, images, videos, entities, related searches, spelling corrections, and more in response to queries from any programming language that can generate a web request. Applications that...

 
File suggestion for you
Loading...
File top downloads
Loading...
Loading...
Codetitle - library source code to share, download the file to the community
Copyright © 2018. All rights reserved. codetitle Develope by Vinagon .Ltd