Home

Awesome

JKScope

Maven Central Javadoc License Mentioned in Awesome Java

GitHub Actions Workflow Status Lines Code lines Hits of Code

Java scope functions inspired by Kotlin

Table of Contents

Motivation

Inspired by the Kotlin scope function I want to make my Java code more structured and readable.

How to use

Java 8+ version required. The library has no dependencies. All you need is this (get the latest version here).

Maven:


<dependency>
  <groupId>com.plugatar.jkscope</groupId>
  <artifactId>jkscope</artifactId>
  <version>2.3</version>
  <scope>compile</scope>
</dependency>

Gradle:

dependencies {
  implementation 'com.plugatar.jkscope:jkscope:2.3'
}

Docs

JKScope interface methods

You need to implement JKScope interface to use these methods.

class MyObject implements JKScope<MyObject> { }

letIt and also

Both methods are the same and differ in the name only. Methods perform the function block on this object and return this object.

MyDTO myDTO = new MyDTO().letIt(it -> {
  it.setProperty("value");
  it.setAnother("another value");
});

MyResource myResource = new MyResource().also(it -> it.init());

takeIf and takeUnless

takeIf method performs the function block on this object and returns Opt monad of this object if the condition is met, or it returns empty Opt instance if the condition is not met. And takeUnless method has reverse logic.

new MyObject().takeIf(it -> it.getInt() > 10).takeUnless(it -> it.getInt() > 20).letIt(it -> System.out.println(it));

letOut

letOut method performs given function block on this object and returns result.

Integer value = new MyObject().letOut(it -> it.getInt());

letOpt

letOpt method performs given function block on this object and returns Opt monad of result.

new MyObject().letOpt(it -> it.getInt()).takeIf(it -> it > 10).letIt(it -> System.out.println(it));

JKScope static methods

Import static methods you need or import them all at once.

import static com.plugatar.jkscope.JKScope.*;

run, runCatching and runRec

run just runs given function block, runCatching runs ignore any Throwable, runRec runs function block allowing yourself to be called recursively.

run method simply runs given function block, runCatching runs ignore any thrown Throwable, runRec runs function block, allowing itself to be called recursively.

run(() -> {
  System.out.println("Hi");
});

runCatching(() -> {
  System.out.println("Hi");
});

runRec(func -> {
  if (new Random().nextInt(0, 100) == 50) {
    func.run();
  }
});

with, withInt, withLong, withDouble and withResource

These methods perform given function block on given values.

with(value, it -> {
  System.out.println(value);
});

with(value1, value2, (v1, v2) -> {
  System.out.println(v1);
  System.out.println(v2);
});

withResource method does the same thing, but with a AutoCloseable resource and closes this resource.

let variations

let, letInt, letLong and letDouble returns result of function block.

String value = let(() -> {
  //...
  return "val";
});

let, letInt, letLong and letDouble methods can also receive a value, process it using a function block, and return that value.

String value = let("val", it -> {
  System.out.println(it);
});

letRec, letIntRec, letLongRec and letDoubleRec accept initial value and allow you to process it recursively returning the result.

int value = letIntRec(10, (n, func) -> {
  if (n <= 1) {
    return 1;
  } else {
    return n * func.apply(n - 1);
  }
});

letWith, letIntWith, letLongWith, letDoubleWith methods accept values and returning the result of function block.

int value = letWith("42", it -> Integer.valueOf(it));

letWithResource method does the same thing, but with a AutoCloseable resource and closes this resource.

opt and optNonNull

opt returns Opt instance of given value, optNonNull returns Opt instance of given value of given value or empty Opt instance if given value is null.

opt(value).takeNonNull().takeUnless(it -> it.isEmpty()).takeIf(it -> it.length() < 100).letIt(it -> System.out.println(it));

optNonNull(value).takeUnless(it -> it.isEmpty()).takeIf(it -> it.length() < 100).letIt(it -> System.out.println(it));

lazy and lazyOfValue

lazy returns Lazy instance with given initializer. lazyOfValue returns Lazy instance of given value.

Lazy<String> lazy = lazy(() -> {
  //...
  return "value";
});

Lazy<String> lazyOfValue = lazyOfValue("value");

Opt object

The Opt monad is similar in meaning to Java Optional, but allows the null value.

Opt monad contains some Optional methods and scope functions methods.

String result = Opt.of(value).takeIf(it -> it.length() > 10).orElse("");

String result = Opt.of(value).takeNonNull().orElseGet(() -> "");

String result = Opt.of(value).takeIf(it -> it.length() > 10).orElseThrow(() -> new IllegalArgumentException());

Lazy object

Lazy represents a value with lazy initialization.

Lazy<String> lazy = lazy(() -> {
  //...
  return "value";
});

Lazy<String> lazyOfValue = lazyOfValue("value");

Unchecked functions

All presented functions allow you to not process checked exceptions.

public static void main(String[] args) {
  URI uri = let(() -> new URI("abc"));
}

Examples

Collection initialization

Map<String, Integer> map = let(new HashMap<>(), it -> {
  it.put("val1", 1);
  it.put("val2", 2);
});

List<String> list = let(new ArrayList<>(), it -> {
  it.add("val1");
  it.add("val2");
});

Argument in a method chain

new MyBuilder()
  .setFirst("first")
  .setSecond("second")
  .setThird(let(() -> {
    //...
    return "third";
  }))
  .setFourth("fourth")
  .build()

Nth Fibonacci number

int value = letIntRec(10, (n, func) -> {
  if (n <= 1) {
    return 1;
  } else {
    return n * func.apply(n - 1);
  }
});

Method argument processing

public static String checkNonNullNonEmptyStr(String value) {
  return opt(value)
    .takeNonNull().throwIfEmpty(NullPointerException::new)
    .takeUnless(String::isEmpty).throwIfEmpty(IllegalArgumentException::new)
    .get();
}

Safe resources

class MyResource implements AutoCloseable {
  //...
}

withResource(new MyResource(), it -> {
  //...
});