README.org: adjust headings

This commit is contained in:
Paul Campbell 2018-07-16 18:52:33 +01:00
parent e5958ba432
commit c7c7c6ebeb

View file

@ -39,150 +39,146 @@
The latest version should be shown above with the nexus and maven-central The latest version should be shown above with the nexus and maven-central
badges or can be found on [[https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22net.kemitix%22%20AND%20a%3A%22mon%22][Maven Central]]. badges or can be found on [[https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22net.kemitix%22%20AND%20a%3A%22mon%22][Maven Central]].
** Usage
** TypeAlias
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: usage :CUSTOM_ID: typealias
:END: :END:
*** TypeAlias In Haskell it is possible to create an alias for a Type, and to then use
:PROPERTIES: that alias with the same behaviour as the original, except that the compiler
:CUSTOM_ID: typealias doesn't treat the alias as the same Type and will generate compiler errors
:END: if you try and use them together. e.g.:
In Haskell it is possible to create an alias for a Type, and to then use #+BEGIN_SRC haskell
that alias with the same behaviour as the original, except that the compiler type PhoneNumber = String
doesn't treat the alias as the same Type and will generate compiler errors type Name = String
if you try and use them together. e.g.: type PhoneBook = [(Name,PhoneNumber)]
#+END_SRC
#+BEGIN_SRC haskell In Java we don't have the ability to have that true alias, so TypeAlias is
type PhoneNumber = String more of a type-wrapper. It's as close as I could get to a Haskell type alias
type Name = String in Java.
type PhoneBook = [(Name,PhoneNumber)]
#+END_SRC
In Java we don't have the ability to have that true alias, so TypeAlias is The benefits of using TypeAlias are:
more of a type-wrapper. It's as close as I could get to a Haskell type alias
in Java.
The benefits of using TypeAlias are: - encapsulation of the wrapped type when passing references through code
that doesn't need to access the actual value, but only to pass it on
- type-safe parameters where you would otherwise be passing Strings,
Integers, Lists, or other general classes
- equality and hashcode
- less verbose than implementing your own
- encapsulation of the wrapped type when passing references through code *TypeAlias Example:*
that doesn't need to access the actual value, but only to pass it on
- type-safe parameters where you would otherwise be passing Strings,
Integers, Lists, or other general classes
- equality and hashcode
- less verbose than implementing your own
*TypeAlias Example:* #+BEGIN_SRC java
class PhoneNumber extends TypeAlias<String> {
private PhoneNumber(final String value) {
super(value);
}
public static PhoneNumber of(final String phoneNumber) {
return new PhoneNumber(phoneNumber);
}
}
#+END_SRC
#+BEGIN_SRC java *Roll your own:*
class PhoneNumber extends TypeAlias<String> {
private PhoneNumber(final String value) {
super(value);
}
public static PhoneNumber of(final String phoneNumber) {
return new PhoneNumber(phoneNumber);
}
}
#+END_SRC
*Roll your own:* #+BEGIN_SRC java
class PhoneNumber {
private final String value;
private PhoneNumber(final String value) {
this.value = value;
}
public static PhoneNumber of(final String phoneNumber) {
return new PhoneNumber(phoneNumber);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PhoneNumber that = (PhoneNumber) o;
return Objects.equals(value, that.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
public String getValue() {
return value;
}
}
#+END_SRC
#+BEGIN_SRC java *Lombok:*
class PhoneNumber {
private final String value;
private PhoneNumber(final String value) {
this.value = value;
}
public static PhoneNumber of(final String phoneNumber) {
return new PhoneNumber(phoneNumber);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PhoneNumber that = (PhoneNumber) o;
return Objects.equals(value, that.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
public String getValue() {
return value;
}
}
#+END_SRC
*Lombok:* Although, if you are using Lombok, that can be equally terse, both it and
TypeAlias<String> coming in at 8 lines each, compared to 24 for rolling your
own:
Although, if you are using Lombok, that can be equally terse, both it and #+BEGIN_SRC java
TypeAlias<String> coming in at 8 lines each, compared to 24 for rolling your @Value
own: @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
class PhoneNumber {
private final String value;
public static PhoneNumber of(final String phoneNumber) {
return new PhoneNumber(phoneNumber);
}
}
#+END_SRC
#+BEGIN_SRC java ** Maybe
@Value :PROPERTIES:
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) :CUSTOM_ID: maybe
class PhoneNumber { :END:
private final String value;
public static PhoneNumber of(final String phoneNumber) {
return new PhoneNumber(phoneNumber);
}
}
#+END_SRC
*** Maybe Allows specifying that a value may or may not be present. Similar to
:PROPERTIES: =Optional=. =Maybe= provides additional methods that =Optional= doesn't:
:CUSTOM_ID: maybe =isNothing()=, =stream()=, =ifNothing()= and =match()=. =Maybe= does not
:END: have a =get()= method.
Allows specifying that a value may or may not be present. Similar to Unlike =Optional=, when a =map()= results in a =null=, the =Maybe= will
=Optional=. =Maybe= provides additional methods that =Optional= doesn't: continue to be a =Just=. =Optional= would switch to being empty. [[http://blog.vavr.io/the-agonizing-death-of-an-astronaut/][vavi.io
=isNothing()=, =stream()=, =ifNothing()= and =match()=. =Maybe= does not follows the same behaviour as =Maybe=]].
have a =get()= method.
Unlike =Optional=, when a =map()= results in a =null=, the =Maybe= will #+BEGIN_SRC java
continue to be a =Just=. =Optional= would switch to being empty. [[http://blog.vavr.io/the-agonizing-death-of-an-astronaut/][vavi.io import net.kemitix.mon.maybe.Maybe;
follows the same behaviour as =Maybe=]].
#+BEGIN_SRC java import java.util.function.Function;
import net.kemitix.mon.maybe.Maybe; import java.util.function.Predicate;
import java.util.function.Function; class MaybeExample {
import java.util.function.Predicate;
class MaybeExample { public static void main(String[] args) {
Maybe.just(countArgs(args))
.filter(isEven())
.map(validMessage())
.match(
just -> System.out.println(just),
() -> System.out.println("Not an valid value")
);
}
public static void main(String[] args) { private static Function<Integer, String> validMessage() {
Maybe.just(countArgs(args)) return v -> String.format("Value %d is even", v);
.filter(isEven()) }
.map(validMessage())
.match(
just -> System.out.println(just),
() -> System.out.println("Not an valid value")
);
}
private static Function<Integer, String> validMessage() { private static Predicate<Integer> isEven() {
return v -> String.format("Value %d is even", v); return v -> v % 2 == 0;
} }
private static Predicate<Integer> isEven() { private static Integer countArgs(String[] args) {
return v -> v % 2 == 0; return args.length;
} }
}
#+END_SRC
private static Integer countArgs(String[] args) { In the above example, the number of command line arguments are counted, if
return args.length; there are an even number of them then a message is created and printed by
} the Consumer parameter in the =match= call. If there is an odd number of
} arguments, then the filter will return =Maybe.nothing()=, meaning that the
#+END_SRC =nothing= drops straight through the map and triggers the Runnable parameter
in the =match= call.
In the above example, the number of command line arguments are counted, if
there are an even number of them then a message is created and printed by
the Consumer parameter in the =match= call. If there is an odd number of
arguments, then the filter will return =Maybe.nothing()=, meaning that the
=nothing= drops straight through the map and triggers the Runnable parameter
in the =match= call.
**** =Maybe= is a Monad: **** =Maybe= is a Monad:
@ -392,60 +388,60 @@
.toOptional(); .toOptional();
#+END_SRC #+END_SRC
*** Result ** Result
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: result :CUSTOM_ID: result
:END: :END:
Allows handling error conditions without the need to catch exceptions. Allows handling error conditions without the need to catch exceptions.
When a =Result= is returned from a method it will contain one of two values. When a =Result= is returned from a method it will contain one of two values.
Either the actual result, or an error in the form of an =Exception=. The Either the actual result, or an error in the form of an =Exception=. The
exception is returned within the =Result= and is not thrown. exception is returned within the =Result= and is not thrown.
#+BEGIN_SRC java #+BEGIN_SRC java
import net.kemitix.mon.result.Result; import net.kemitix.mon.result.Result;
import java.io.IOException; import java.io.IOException;
class ResultExample implements Runnable { class ResultExample implements Runnable {
public static void main(final String[] args) { public static void main(final String[] args) {
new ResultExample().run(); new ResultExample().run();
} }
@Override @Override
public void run() { public void run() {
Result.of(() -> callRiskyMethod()) Result.of(() -> callRiskyMethod())
.flatMap(state -> doSomething(state)) .flatMap(state -> doSomething(state))
.match( .match(
success -> System.out.println(success), success -> System.out.println(success),
error -> error.printStackTrace() error -> error.printStackTrace()
); );
} }
private String callRiskyMethod() throws IOException { private String callRiskyMethod() throws IOException {
return "I'm fine"; return "I'm fine";
} }
private Result<String> doSomething(final String state) { private Result<String> doSomething(final String state) {
return Result.of(() -> state + ", it's all good."); return Result.of(() -> state + ", it's all good.");
} }
} }
#+END_SRC #+END_SRC
In the above example the string ="I'm fine"= is returned by In the above example the string ="I'm fine"= is returned by
=callRiskyMethod()= within a successful =Result=. The =.flatMap()= call, =callRiskyMethod()= within a successful =Result=. The =.flatMap()= call,
unwraps that =Result= and, as it is a success, passes the contents to unwraps that =Result= and, as it is a success, passes the contents to
=doSomething()=, which in turn returns a =Result= that the =.flatMap()= call =doSomething()=, which in turn returns a =Result= that the =.flatMap()= call
returns. =match()= is called on the =Result= and, being a success, will call returns. =match()= is called on the =Result= and, being a success, will call
the success =Consumer=. the success =Consumer=.
Had =callRiskyMethod()= thrown an exception it would have been caught by the Had =callRiskyMethod()= thrown an exception it would have been caught by the
=Result.of()= method which would have then been an error =Result=. An error =Result.of()= method which would have then been an error =Result=. An error
Result would have ignored the =flatMap= and skipped to the =match()= when it Result would have ignored the =flatMap= and skipped to the =match()= when it
would have called the error =Consumer=. would have called the error =Consumer=.
**** =Result= is a Monad **** =Result= is a Monad