Today, at work, I had the dire need of discriminated unions in Java, which of course doesn’t support it. Then I found the idea of the Either
type, which I implemented myself using the Optional
class from Java 8:
import java.util.Optional; import java.util.function.Consumer; /** * Guarda 3 elementos mutuamente exclusivos, isto é, apenas 1 dos 3 pode existir * dentro do objeto. */ public class Either3<T1, T2, T3> { private Optional<T1> v1 = Optional.empty(); private Optional<T2> v2 = Optional.empty(); private Optional<T3> v3 = Optional.empty(); /** Cria um objeto com o valor do tipo 1. */ public static <<1, T2, T3> Either3<T1, T2, T3> of1(T1 v1) { Either3<T1, T2, T3> obj = new Either3<>(); obj.v1 = Optional.of(v1); return obj; } /** Cria um objeto com o valor do tipo 1. */ public static <T1, T2, T3> Either3<T1, T2, T3> of2(T2 v2) { Either3<T1, T2, T3> obj = new Either3<>(); obj.v2 = Optional.of(v2); return obj; } /** Cria um objeto com o valor do tipo 1. */ public static <T1, T2, T3> Either3<T1, T2, T3> of3(T3 v3) { Either3<T1, T2, T3> obj = new Either3< obj.v3 = Optional.of(v3); return obj; } /** Retorna o valor do tipo 1; caso não exista, lança {@code NoSuchElementException}. */ public T1 get1() { return v1.get(); } /** Retorna o valor do tipo 2; caso não exista, lança {@code NoSuchElementException}. */ public T2 get2() { return v2.get(); } /** Retorna o valor do tipo 3; caso não exista, lança {@code NoSuchElementException}. */ public T3 get3() { return v3.get(); } /** Diz se o objeto possui um valor do tipo 1. */ public boolean has1() { return v1.isPresent(); } /** Diz se o objeto possui um valor do tipo 2. */ public boolean has2() { return v2.isPresent(); } /** Diz se o objeto possui um valor do tipo 3. */ public boolean has3() { return v3.isPresent(); } /** Executa a função caso haja um valor do tipo 1. */ public void if1(Consumer<? super T1> consumer) { v1.ifPresent(consumer); } /** Executa a função caso haja um valor do tipo 2. */ public void if2(Consumer<? super T2> consumer) { v2.ifPresent(consumer); } /** Executa a função caso haja um valor do tipo 3. */ public void if3(Consumer<? super T3> consumer) { v3.ifPresent(consumer); } }
Since Java doesn’t have variadic generic parameters, having one class to each amount is needed. Nonetheless, it’s doable and remarkably ergonomic.