Skip to content

Instantly share code, notes, and snippets.

@987Nabil
Last active November 2, 2024 07:18
Show Gist options
  • Save 987Nabil/1731324b1959e18a65e37016e6093526 to your computer and use it in GitHub Desktop.
Save 987Nabil/1731324b1959e18a65e37016e6093526 to your computer and use it in GitHub Desktop.
public record Author(String name) {
}
import java.util.List;
record Book(NonBlankString title, ISBN isbn, NonEmptyList<Author> authors) {
static Either<String, Book> create(String title, String isbn, List<Author> authors) {
var nonBlankTitle = NonBlankString.create(title);
var nonEmptyAuthors = NonEmptyList.fromList(authors);
var isbn_ = ISBN.fromString(isbn);
if (nonBlankTitle.isRight() && nonEmptyAuthors.isRight() && isbn_.isRight()) {
return Either.right(
new Book(
nonBlankTitle.rightValue(),
isbn_.rightValue(),
nonEmptyAuthors.rightValue()
)
);
} else {
return (Either<String, Book>) Either.firstLeft(nonBlankTitle, isbn_, nonEmptyAuthors);
}
}
}
sealed interface Either<L, R> {
static <L, R> Either<L, R> left(L value) {
return new Left<>(value);
}
static <L, R> Either<L, R> right(R value) {
return new Right<>(value);
}
@SafeVarargs
static <L> Left<L, ?> firstLeft(Either<L, ?>... eithers) {
for (Either<L, ?> either : eithers) {
if (either instanceof Left<L, ?> left) {
return left;
}
}
throw new IllegalStateException("No left value present");
}
public R rightValue();
public default boolean isRight() {
return this instanceof Right;
}
record Left<L, R>(L value) implements Either<L, R> {
@Override
public R rightValue() {
throw new IllegalStateException("No right value present");
}
}
record Right<L, R>(R value) implements Either<L, R> {
@Override
public R rightValue() {
return value;
}
}
}
// Impossible to use records, because they cant have private constructors
class ISBN {
private final String value;
private ISBN(String value) {
this.value = value;
}
static Either<String, ISBN> fromString(String value) {
if (value.length() != 13) {
return Either.left("ISBN must be 13 characters long");
}
return Either.right(new ISBN(value));
}
String value() {
return value;
}
}
// Impossible to use records, because they cant have private constructors
public class NonBlankString {
private final String value;
private NonBlankString(String value) {
this.value = value;
}
public String value() {
return value;
}
static Either<String, NonBlankString> create(String value) {
if (value.isBlank()) {
return Either.left("Value must not be blank");
}
return Either.right(new NonBlankString(value));
}
}
public record NonEmptyList<T>(T head, List<T> tail) {
static <T> Either<String, NonEmptyList<T>> fromList(List<T> list) {
if (list.isEmpty()) {
return Either.left("NonEmptyList cannot be created from an empty list");
}
return Either.right(new NonEmptyList<>(list.getFirst(), list.subList(1, list.size())));
}
// Might need some accessors in real life
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment