Java 8+

powered by   JΛVΛ

LΛNG

@arekjurasz

arkadiusz.jurasz@gmail.com

"Javaslang core is a functional library for Java 8+. It helps to reduce the amount of code and to increase the robustness. A first step towards functional programming is to start thinking in immutable values. Javaslang provides immutable collections and the necessary functions and control structures to operate on these values. The results are beautiful and just work."

Show me some

CODE!

Tuple

Tuple3<String, Long, Double> newTuple3 = tuple3.map((first, second, third) ->
        Tuple.of(first.toUpperCase(), second * 10, third - 0.5)
);

assertThat(newTuple3._1).isEqualTo("STRING");
assertThat(newTuple3._2).isEqualTo(100L);
assertThat(newTuple3._3).isEqualTo(5.0);
assertThat(tuple3._1).isEqualTo("String");
assertThat(tuple3._2()).isEqualTo(10L);
Tuple3<String, Long, Double> tuple3 = Tuple.of("String", 10L, 5.5);
Function1<String, String> mapFirstFunc = String::toLowerCase;
Function1<Long, Long> mapSecondFunc = l -> l + 1;
Function1<Double, Double> mapThirdFunc = d -> 0.0;


Tuple3<String, Long, Double> newTuple3 = tuple3.map(mapFirstFunc, 
                                                mapSecondFunc, mapThirdFunc);

assertThat(newTuple3._1).isEqualTo("string");
assertThat(newTuple3._2).isEqualTo(11L);
assertThat(newTuple3._3).isEqualTo(0.0);
String transformed = tuple3.transform((first, second, third) -> 
                                            first + second + third);

assertThat(transformed).isEqualTo("String105.5");
Tuple3<String, Long, Double> newTuple3 = tuple3.map2(second -> 0L);

assertThat(newTuple3._2).isEqualTo(0L);

Functions

@FunctionalInterface
public interface TriFunction<A, B, C, R> {
    R apply(A a, B b, C c);
}
Function<Integer, Function<Integer, Function<Integer, Integer>>> addTri = 
                                               a -> (b -> (c -> a + b + c));

assertThat(addTri.apply(1).apply(2).apply(3)).isEqualTo(6);
@FunctionalInterface
public interface TriFunctionChecked<A, B, C, R> {
    R apply(A a, B b, C c) throws Exception;
}
CheckedFunction2<Integer, Integer, Integer> divide = (a, b) -> a / b;

assertThat(catchThrowable(() -> divide.apply(3, 0)))
                .isInstanceOf(ArithmeticException.class);
public static Integer add(Integer a, Integer b) {
    return a + b;
}

Function2<Integer, Integer, Integer> addMethodReference = 
                                    Function2.of(Functions::add);

assertThat(addMethodReference.apply(5, 5)).isEqualTo(10);
Function1<Integer, Integer> plusOne = a -> a + 1;
Function1<Integer, Integer> multiplyByTwo = a -> a * 2;
Function1<Integer, Integer> add1AndMultiplyBy2 = plusOne.andThen(multiplyByTwo);

assertThat(add1AndMultiplyBy2.apply(1)).isEqualTo(4);
Function1<Integer, Integer> add1AndMultiplyBy2 = multiplyByTwo.compose(plusOne);

then(add1AndMultiplyBy2.apply(1)).isEqualTo(4);
Function2<Integer, Integer, Integer> divide = (a, b) -> a / b;
Function2<Integer, Integer, Option<Integer>> safeDivide = Function2.lift(divide);

Option<Integer> i1 = safeDivide.apply(1, 0);
Option<Integer> i2 = safeDivide.apply(4, 2);

assertThat(i1).isEqualTo(Option.none());
assertThat(i2).isEqualTo(Option.of(2));
Function2<Integer, Integer, Integer> func = (a, b) -> (2 * a) + b;
Function1<Integer, Integer> func2 = func.curried().apply(2);
// func2 = (b) -> (2*2) + b;

assertThat(func2.apply(4)).isEqualTo(8);
Function0<Double> hashCache =
        Function0.of(Math::random).memoized();

double randomValue1 = hashCache.apply();
double randomValue2 = hashCache.apply();

assertThat(randomValue1).isEqualTo(randomValue2);

Values

Option<Integer> op1 = Option.of(1);     // Some(1)
Option<Integer> op2 = Option.of(null);  // None

Option<Integer> op3 = Option.some(2);   // Some(2)
Option<Integer> op4 = Option.none();    // None

assertThat(op1).isInstanceOf(Option.Some.class);
assertThat(op2).isInstanceOf(Option.None.class);
String result = Try.of(() -> "Try this function")
                   .getOrElseGet(throwable -> "Ups");

assertThat(result).isEqualTo("Try this function");
String result = Try.of(Values::throwException)
                   .recover(throwable -> "Recovered")
                   .getOrElseGet(throwable -> "Ups");

assertThat(result).isEqualTo("Recovered");
Lazy<Double> lazy = Lazy.of(Math::random);

assertThat(lazy.isEvaluated()).isFalse();

lazy.get();

assertThat(lazy.isEvaluated()).isTrue();
assertThat(lazy.get()).isEqualTo(lazy.get());
CharSequence chars = Lazy.val(() -> "Yay!", CharSequence.class);
public interface MyInterface {
    DtoObject compute();
}

public class DtoObject {
    private final Integer x;
    private final Integer y;
    (...)
}

MyInterface lazy = Lazy.val(() -> {
            MyInterface dtoInterface = () -> new DtoObject(1, 2);
            return dtoInterface;
        }, MyInterface.class);
public static Either<String,Integer> computeL() {
    return Either.left("Error");
}

public static Either<String,Integer> computeR() {
    return Either.right(1);
}

//--

Function0<Either<String,Integer>> compute = Function0.of(Values::computeL);

Either<String,Integer> value = compute.apply().right()
                                .map(i -> i * 2)
                                .toEither();

assertThat(value).isInstanceOf(Either.Left.class);
assertThat(value.getLeft()).isEqualTo("Error");

//--

Function0<Either<String,Integer>> compute = Function0.of(Values::computeR);

Either<String,Integer> value = compute.apply().right()
                                .map(i -> i * 2)
                                .toEither();

assertThat(value).isInstanceOf(Either.Right.class);
assertThat(value.get()).isEqualTo(2);
Future<Integer> future = Future.of(() -> {
    Thread.sleep(1000L);
    return 10;
});

System.out.println("First");
future.onSuccess(System.out::println);
future.await();

Collections

assertThat(Arrays.asList(1, 2, 3).stream().mapToInt(i -> i).sum()).isEqualTo(6);
assertThat(List.of(1, 2, 3).sum()).isEqualTo(6);


assertThat(List.of(1, 2, 3).head()).isEqualTo(1);
assertThat(List.of(1, 2, 3).tail()).isEqualTo(List.of(2, 3));

//--

java.util.List java8 = Arrays.asList(1, 2, 3).stream()
                                             .map(i -> i * 2)
                                             .collect(toList());
List javaslang = List.of(1, 2, 3).map(i -> i * 2);

assertThat(java8).isEqualTo(Arrays.asList(2, 4, 6));
assertThat(javaslang.toJavaList()).isEqualTo(Arrays.asList(2, 4, 6));

//--

String java8 = Arrays.asList("a", "b", "c").stream().collect(Collectors.joining(", "));
String javaslang = List.of("a", "b", "c").mkString(", ");

assertThat(java8).isEqualTo("a, b, c");
assertThat(javaslang).isEqualTo("a, b, c");

Pattern matching

$() - wildcard pattern
$(value) - equals pattern
$(predicate) - conditional pattern
Integer i = 1;
String s = Match(i).of(
        Case($(1), "one"),
        Case($(2), "two"),
        Case($(), "?")
);

assertThat(s).isEqualTo("one");
Option<String> s = Match(i).option(
    Case($(0), "zero")
);

assertThat(s).isEqualTo(Option.none());
//import static javaslang.Patterns.*;

Match(_try).of(
    Case(Patterns.Success($()), value -> ...),
    Case(Patterns.Failure($()), x -> ...)
);
import static javaslang.Predicates.*;

Integer i = 1;
String s = Match(i).of(
    Case(is(1), "Yes"),
    Case(noneOf(is(2), is(3)), "No"),
    Case($(), "?")
);

assertThat(s).isEqualTo("Yes");
Tuple2<Integer, Integer> tuple = Tuple.of(10, 20);
String s = Match(tuple).of(
        Case(Patterns.Tuple2($(x -> x == 10), $()), "_1 == 10"),
        Case($(), "?")
);

assertThat(s).isEqualTo("_1 == 10");
class Person {  
    String name;
    Address address;
}

class Address {  
    String street;
    int number;
}

Tuple3<Integer, String, Double> tuple3 = Tuple.of(1, "two", 2.5);

String result = Match(tuple3).of(
        Case(Patterns.Tuple3($(), $("two"), $()), (_1, _2, _3) -> 
                                            "elements " + _1 + _2 + _3),
        Case($(), "default")
);

assertThat(result).isEqualTo("elements 1two2.5");
Option<Integer> op1 = Option.none();

Integer result = Match(op1).of(
        Case(Patterns.Some($()), v -> v * 10),
        Case(Patterns.None(), -1)
);

assertThat(result).isEqualTo(-1);
if (person != null && "Carl".equals(person.getName())) {  
        Address address = person.getAddress();
        if (address != null) {
            String street = address.getStreet();
            int number = address.getNumber();
            ...
        }
    }
}
Match(person).of(  
    Case(Person($("Carl"), Address($(), $())), (p, a) -> ...)
)
@Patterns
class Starter {

    @Unapply
    static Tuple2<String, Address> Person(Person person) {
        return Tuple.of(person.getName(), person.getAddress());
    }

    @Unapply
    static Tuple2<String, Integer> Address(Address address) {
        return Tuple.of(address.getStreet(), address.getNumber());
    }
}

Resources

Blog Bartka Kuczyńskiego:
http://koziolekweb.pl/2016/06/17/pattern-matching-w-javie-z-javaslang-i/
http://koziolekweb.pl/2016/06/18/pattern-matching-w-javie-z-javaslang-ii/
http://koziolekweb.pl/2016/06/19/pattern-matching-w-javie-z-javaslang-iii/
http://koziolekweb.pl/2016/06/20/pattern-matching-w-javie-z-javaslang-iv/

Dokumentacja javaslang:
http://www.javaslang.io/javaslang-docs/
Blog javaslang (outdated)
http://blog.javaslang.io/pattern-matching-starter/
http://blog.javaslang.io/pattern-matching-essentials/
Repozytorium z przykładami
http://github.com/ajurasz/bbjug-javaslang

Java 8+ powered by javaslang

By Arkadiusz Jurasz

Java 8+ powered by javaslang

  • 890