Generated from Example_Builders_Test.java at 3.0.0 2020-08-11T17:36:18Z

Builders

Abstract

Basic introduction (by example) to builders.

Please note that examples are conceptual just to show some possibilities.

In case you want to define function little more decoratively or you just have methods ready to be referenced, depending on the context, you might want to use Builder. Builders are available for each functional interface in library and also those in JRE (java.lang.function.*). Basically each builder gathers separates cases that consist of predicate and function implementation.

Final (build) function will go through those cases in a order and execute predicate on input arguments and if predicate evaluate to true then its paired function implementation will be called. For obvious reasons functions build this way are good candidate to be cached instead of being build each time they are used.

Examples

Lets define function that tries to convert any object of specific type to a integer:


@Test public void testBuild() { LToIntFunction<Object> function = LToIntFunctionBuilder .toIntFunction() .aCase(Number.class, Number::intValue) .inCase(String.class::isInstance).evaluate(o -> Integer.parseInt((String) o)) .otherwise(o -> throwThe(new IllegalArgumentException())) .build(); THEN.attestToIntFunc(function) .doesApplyAsInt(0).to(a -> a.isEqualTo(0)) .doesApplyAsInt(5).to(a -> a.isEqualTo(5)) .doesApplyAsInt(44f).to(a -> a.isEqualTo(44)) .doesApplyAsInt(3_000_000_000L).to(a -> a.isEqualTo(-1294967296)) .doesApplyAsInt("-4").to(a -> a.isEqualTo(-4)) .doesApplyAsInt("non number").withException(a -> a.isInstanceOf(NumberFormatException.class)) .doesApplyAsInt(new Object()).withException(a -> a.isInstanceOf(IllegalArgumentException.class)); }

LToIntBiFunction<Object, Object> function = LToIntBiFunctionBuilder .toIntBiFunction() .casesOf(Long.class, null, pcp -> pcp .inCase(test1st(l -> isInIntRange((long) l))).evaluate(apply1stAsInt(Long::intValue)) .otherwise((l, o) -> throwThe(new IllegalArgumentException("To large for int.")))) .aCase(test1st(s -> s instanceof Short), apply1stAsInt(s -> ((Short) s).intValue())) .aCase(Number.class, null, apply1stAsInt((Number::intValue))) .inCase(test1st(s -> s instanceof String)).evaluate(apply1stAsInt(s -> Integer.parseInt((String) s))) .otherwise(apply1stAsInt(s -> throwThe(new IllegalArgumentException()))) .build();

Just in case you wonder test1st is static method in LBiPredicate

### Examples with Generics and type arguments.

Previous examples actually avoid one ot the issues a Java compiler might have (all the generic types are compiled as Object). There is a limitation to what Java compiler can guess. This example would not actually compile without repeating the argument type <T>:


@Test public <T> void testGeneric1() { LToIntFunction<T> function = LToIntFunctionBuilder.<T>toIntFunction() .inCase(String.class::isInstance).evaluate(o -> Integer.parseInt((String) o)) .otherwise(o -> throwThe(new IllegalArgumentException())) .build(); }

That is not the issue if there is only one generic argument and if it has such short name. But here is an example with a better way to do it:


@Test public <T, V> void testGeneric2() { LToIntTriFunction<T, String, V> function = LToIntTriFunctionBuilder.toIntTriFunctionFrom(b -> b .inCase(LTriPredicate.test2nd(String.class::isInstance)).evaluate((t, s, v) -> Integer.parseInt(s)) .otherwise((t, s, v) -> throwThe(new IllegalArgumentException())) ); }

Function builder for JRE interfaces.

Just in case it would matter there are builders that just build function implementing only JRE interface. Even for Runnable. Premise behind the builder for a function that does not take arguments is that it might depend on the external state.


@Test public void testBuildPrimitive() { Runnable function = RunnableBuilder.actionFrom(b -> b .aCase(() -> GLOBAL_STATE.get(), () -> GLOBAL_STATE.set(false)) ); assertThat(function) .isInstanceOf(Runnable.class) .isNotInstanceOf(LAction.class); }

Generated from Example_Builders_Test.java at 3.0.0 2020-08-11T17:36:18Z