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.