diff --git a/README.md b/README.md index 1a03777..9e232f3 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,19 @@ Mon === -TypeAlias for Java +TypeAlias, Maybe and Result for Java -[![GitHub release](https://img.shields.io/github/release/kemitix/mon.svg)]() -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/d57096b0639d496aba9a7e43e7cf5b4c)](https://www.codacy.com/app/kemitix/mon?utm_source=github.com&utm_medium=referral&utm_content=kemitix/mon&utm_campaign=Badge_Grade) -[![Build Status](https://travis-ci.org/kemitix/mon.svg?branch=master)](https://travis-ci.org/kemitix/mon) -[![Coverage Status](https://coveralls.io/repos/github/kemitix/mon/badge.svg?branch=master)](https://coveralls.io/github/kemitix/mon?branch=master) -[![codecov](https://codecov.io/gh/kemitix/mon/branch/master/graph/badge.svg)](https://codecov.io/gh/kemitix/mon) +[![Sonatype Nexus (Releases)](https://img.shields.io/nexus/r/https/oss.sonatype.org/net.kemitix/mon.svg?style=for-the-badge)](https://oss.sonatype.org/content/repositories/releases/net/kemitix/mon/) +[![Maven Central](https://img.shields.io/maven-central/v/net.kemitix/mon.svg?style=for-the-badge)](https://search.maven.org/#search|ga|1|g%3A"net.kemitix"%20AND%20a%3A"mon") + +[![SonarQube Coverage](https://img.shields.io/sonar/https/sonarcloud.io/net.kemitix%3Amon/coverage.svg?style=for-the-badge)](https://sonarcloud.io/dashboard?id=net.kemitix%3Amon) +[![SonarQube Tech Debt](https://img.shields.io/sonar/https/sonarcloud.io/net.kemitix%3Amon/tech_debt.svg?style=for-the-badge)](https://sonarcloud.io/dashboard?id=net.kemitix%3Amon) + +[![Jenkins](https://img.shields.io/jenkins/s/https/jenkins.kemitix.net/job/GitLab/job/kemitix%252Fmon.svg?style=for-the-badge)](https://jenkins.kemitix.net/job/GitLab/job/kemitix%252Fmon/) +[![Jenkins tests](https://img.shields.io/jenkins/t/https/jenkins.kemitix.net/job/GitLab/job/kemitix%252Fmon.svg?style=for-the-badge)](https://jenkins.kemitix.net/job/GitLab/job/kemitix%252Fmon/) +[![Jenkins coverage](https://img.shields.io/jenkins/c/https/jenkins.kemitix.net/job/GitLab/job/kemitix%252Fmon.svg?style=for-the-badge)](https://jenkins.kemitix.net/job/GitLab/job/kemitix%252Fmon/) + +[![Codacy grade](https://img.shields.io/codacy/grade/d57096b0639d496aba9a7e43e7cf5b4c.svg?style=for-the-badge)](https://app.codacy.com/project/kemitix/mon/dashboard) ## Maven @@ -15,7 +21,7 @@ TypeAlias for Java net.kemitix mon - 0.4.0 + 0.6.0 ``` @@ -23,6 +29,8 @@ TypeAlias for Java ### TypeAlias +More of a type-wrapper really. It's as close as I could get to a Haskell type alias in Java. + ```java class Goal extends TypeAlias { private Goal(final String goal) { @@ -35,43 +43,147 @@ class Goal extends TypeAlias { ``` ```java -Goal goal = Goal.of("goal"); - -void foo(final Goal goal) { - System.out.println("The goal is " + goal.getValue()); +class Example {} + Goal goal = Goal.of("goal"); + void foo(final Goal goal) { + System.out.println("The goal is " + goal.getValue()); + } } ``` -### Maybe (Just & Nothing) +### Maybe + +A non-final substitute for Optional with `peek()` and `stream()` methods. ```java -assertThat(Maybe.maybe(null)).isEqualTo(Maybe.nothing()); -assertThat(Maybe.maybe(1)).isEqualTo(Maybe.just(1)); -assertThat(Maybe.nothing() - .orElseGet(() -> 1)).isEqualTo(1); -assertThat(Maybe.just(1) - .orElseGet(() -> 2)).isEqualTo(1); -assertThat(Maybe.nothing() - .orElse(1)).isEqualTo(1); -assertThat(Maybe.just(1) - .orElse(2)).isEqualTo(1); -assertThat(Maybe.just(1) - .filter(v -> v > 2)).isEqualTo(Maybe.nothing()); -assertThat(Maybe.just(3) - .filter(v -> v > 2)).isEqualTo(Maybe.just(3)); -assertThat(Maybe.just(1) - .toOptional()).isEqualTo(Optional.of(1)); -assertThat(Maybe.nothing() - .toOptional()).isEqualTo(Optional.empty()); -assertThat(Maybe.fromOptional(Optional.of(1))).isEqualTo(Maybe.just(1)); -assertThat(Maybe.fromOptional(Optional.empty())).isEqualTo(Maybe.nothing()); -final AtomicInteger reference = new AtomicInteger(0); -assertThat(Maybe.just(1).peek(reference::set)).isEqualTo(Maybe.just(1)); -assertThat(reference).hasValue(1); -assertThat(Maybe.nothing().peek(v -> reference.incrementAndGet())).isEqualTo(Maybe.nothing()); -assertThat(reference).hasValue(1); -assertThatCode(() -> Maybe.just(1).orElseThrow(IllegalStateException::new)) - .doesNotThrowAnyException(); -assertThatThrownBy(() -> Maybe.nothing().orElseThrow(IllegalStateException::new)) - .isInstanceOf(IllegalStateException.class); +class Test { + @Test + public void maybeTests() { + assertThat(Maybe.maybe(null)).isEqualTo(Maybe.nothing()); + assertThat(Maybe.maybe(1)).isEqualTo(Maybe.just(1)); + assertThat(Maybe.nothing().orElseGet(() -> 1)).isEqualTo(1); + assertThat(Maybe.just(1).orElseGet(() -> 2)).isEqualTo(1); + assertThat(Maybe.nothing().orElse(1)).isEqualTo(1); + assertThat(Maybe.just(1).orElse(2)).isEqualTo(1); + assertThat(Maybe.just(1).filter(v -> v > 2)).isEqualTo(Maybe.nothing()); + assertThat(Maybe.just(3).filter(v -> v > 2)).isEqualTo(Maybe.just(3)); + assertThat(Maybe.just(1).toOptional()).isEqualTo(Optional.of(1)); + assertThat(Maybe.nothing().toOptional()).isEqualTo(Optional.empty()); + assertThat(Maybe.fromOptional(Optional.of(1))).isEqualTo(Maybe.just(1)); + assertThat(Maybe.fromOptional(Optional.empty())).isEqualTo(Maybe.nothing()); + final AtomicInteger reference = new AtomicInteger(0); + assertThat(Maybe.just(1).peek(reference::set)).isEqualTo(Maybe.just(1)); + assertThat(reference).hasValue(1); + assertThat(Maybe.nothing().peek(v -> reference.incrementAndGet())).isEqualTo(Maybe.nothing()); + assertThat(reference).hasValue(1); + assertThatCode(() -> Maybe.just(1).orElseThrow(IllegalStateException::new)).doesNotThrowAnyException(); + assertThatThrownBy(() -> Maybe.nothing().orElseThrow(IllegalStateException::new)).isInstanceOf(IllegalStateException.class); + assertThat(Maybe.just(1).stream()).containsExactly(1); + assertThat(Maybe.nothing().stream()).isEmpty(); + } +} +``` + +### Result + +A container for method return values that may raise an Exception. Useful for when a checked exceptions can't be added +to the method signature. + +```java +package net.kemitix.mon; + +import net.kemitix.mon.result.Result; + +import java.io.IOException; + +class ResultExample implements Runnable { + + public static void main(String[] args) { + new ResultExample().run(); + } + + @Override + public void run() { + System.out.println("run"); + final Result goodResult = goodMethod(); + if (goodResult.isOkay()) { + doGoodThings(); + } + if (goodResult.isError()) { + notCalled(0); + } + + goodResult.flatMap(number -> convertToString(number)) + .flatMap(str -> stringLength(str)) + .match( + success -> System.out.format("Length is %s%n", success), + error -> System.out.println("Count not determine length") + ); + + final Result badResult = badMethod(); + badResult.match( + success -> notCalled(success), + error -> handleError(error) + ); + } + + private Result goodMethod() { + System.out.println("goodMethod"); + return Result.ok(1); + } + + private void doGoodThings() { + System.out.println("doGoodThings"); + } + + private void notCalled(final Integer success) { + System.out.println("notCalled"); + } + + private Result convertToString(final Integer number) { + System.out.println("convertToString"); + return Result.ok(String.valueOf(number)); + } + + private Result stringLength(final String value) { + System.out.println("stringLength"); + if (value == null) { + return Result.error(new NullPointerException("value is null")); + } + return Result.ok(value.length()); + } + + // doesn't need to declare "throws IOException" + private Result badMethod() { + System.out.println("badMethod"); + return Result.error(new IOException("error")); + } + + private void handleError(final Throwable error) { + System.out.println("handleError"); + throw new RuntimeException("Handled exception", error); + } + +} +``` +Will output: +```text +run +goodMethod +doGoodThings +convertToString +stringLength +Length is 1 +badMethod +handleError +Exception in thread "main" java.lang.RuntimeException: Handled exception + at net.kemitix.mon.ResultExample.handleError(ResultExample.java:72) + at net.kemitix.mon.ResultExample.lambda$run$5(ResultExample.java:34) + at net.kemitix.mon.result.Err.match(Err.java:56) + at net.kemitix.mon.ResultExample.run(ResultExample.java:32) + at net.kemitix.mon.ResultExample.main(ResultExample.java:10) +Caused by: java.io.IOException: error + at net.kemitix.mon.ResultExample.badMethod(ResultExample.java:67) + at net.kemitix.mon.ResultExample.run(ResultExample.java:31) + ... 1 more ```