Ok, two favorite functional idioms in Java:
public abstract class Option<T> extends Cursorable<T> { public static <T> Option<T> some(final T value) { return new Option<T>() { @Override public int size() { return 1; } @Override public T get() { return value; } }; } public static <T> Option<T> none() { return new Option<T>() { @Override public int size() { return 0; } @Override public T get() { throw new IllegalStateException(); } }; } public abstract int size(); public abstract T get(); public final boolean isEmpty() { return 0 == size(); } @Override public final Iterator<T> iterator() { return new Iterator<T>() { private boolean empty = isEmpty(); @Override public boolean hasNext() { return !empty; } @Override public T next() { if (empty) throw new NoSuchElementException(); empty = true; return get(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } } public abstract class Cursorable<T> implements Iterable<T> { public static <T> Cursorable<T> over( final Iterable<T> it) { return new Cursorable<T>() { @Override public Iterator<T> iterator() { return it.iterator(); } }; } public final Cursorable<T> select( final Select<T> select) { return new Cursorable<T>() { @Override public Iterator<T> iterator() { return new Iterator<T>() { private final Iterator<T> it = Cursorable.this.iterator(); private Option<T> current = none(); @Override public boolean hasNext() { while (it.hasNext()) { final T next = it.next(); if (!select.accept(next)) continue; current = some(next); return true; } current = none(); return false; } @Override public T next() { if (current.isEmpty()) throw new NoSuchElementException(); return current.get(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }; } public final <U> Cursorable<U> project( final Project<T, U> project) { return new Cursorable<U>() { @Override public Iterator<U> iterator() { return new Iterator<U>() { private final Iterator<T> it = Cursorable.this.iterator(); @Override public boolean hasNext() { return it.hasNext(); } @Override public U next() { return project.on(it.next()); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }; } public interface Select<T> { boolean accept(final T input); } public interface Project<T, U> { U on(final T input); } }
And a demo:
public class SelectAndProjectMain { public static void main(final String... args) { for (final Integer number : over(asList(1, 2, 3, 4)) .select(new Cursorable.Select() { @Override public boolean accept(final Integer input) { return 0 == input % 2; } })) { System.out.println("Even: " + number); } for (final String number : over(asList(1, 2, 3, 4)) .project(new Cursorable.Project () { @Override public String on(final Integer input) { return Integer.toBinaryString(input); } })) { System.out.println("Binary: " + number); } } }
Produces:
Even: 2 Even: 4 Binary: 1 Binary: 10 Binary: 11 Binary: 100
Although I am afraid to add this to my project at work. I worry for the maintainer after me.
UPDATE: A coworker called me to the mat for extreme terseness. Demonstrating a more fluent style, I refactored the demo code:
public class SelectAndProjectMain { public static void main(final String... args) { final List<Integer> numbers = asList(1, 2, 3, 4); for (final Integer number : over(numbers).select(evens())) System.out.println("Even: " + number); for (final String number : over(numbers).project(binaries())) System.out.println("Binary: " + number); } static class Evens implements Cursorable.Select<Integer> { static Evens evens() { return new Evens(); } @Override public boolean accept(final Integer input) { return 0 == input % 2; } } static class Binaries implements Cursorable.Project<Integer, String> { static Binaries binaries() { return new Binaries(); } @Override public String on(final Integer input) { return Integer.toBinaryString(input); } } }
UPDATE: And lastly, more on Option from the land of Scala.
No comments:
Post a Comment