Partial FluentIterable for Salesforce Apex

Guava's FluentIterable is really handy for processing data sets. Having something like it in Apex would be helpful.

I have a partial implementation of FluentIterable written in Apex.

A key advantage of my implementation is that it processes the input collection in a single pass.  It achieves this by recursively running the operation stack.  This allows me to process each element completely, terminate recusion on a failed filter, and recurse to further operations with transformed elements.

A key disadvantage of implementing FluentIterable in Apex is that it lacks user-definable generics.

I am hoping to add some of the other capabilities like first and firstMatch as I find uses for them in my work with Salesforce.

Listing of FluentIterable.cls:

public class FluentIterable {
    private final List<Object> sourceList;
    private final List<Operation> operations;

    private abstract class Operation {
        public abstract Boolean isFilter();
        public abstract Boolean isTransform();
        public abstract Predicate getFilter();
        public abstract Function getTransform();
    }

    private class Transform extends Operation {
        private final Function transform;
        public Transform(Function transform) {
            this.transform = transform;
        }
        public override Boolean isFilter() {
            return false;
        }
        public override Boolean isTransform() {
            return true;
        }
        public override Predicate getFilter() {
            throw new OperationNotSupportedException('Not a Filter');
        }
        public override Function getTransform() {
            return transform;
        }
    }

    private class Filter extends Operation {
        private final Predicate filter;
        public Filter(Predicate filter) {
            this.filter = filter;
        }
        public override Boolean isFilter() {
            return true;
        }
        public override Boolean isTransform() {
            return false;
        }
        public override Predicate getFilter() {
            return filter;
        }
        public override Function getTransform() {
            throw new OperationNotSupportedException('Not a Transform');
        }
    }

    private class OperationNotSupportedException extends Exception {}

    public static FluentIterable fromList(List<Object> sourceList) {
        return new FluentIterable(sourceList);
    }

    private FluentIterable(List<Object> sourceList) {
        this.sourceList = sourceList;
        this.operations = new List<Operation>();
    }

    public List<Object> intoList(List<Object> listToPopulate) {
        for (Object o : sourceList) {
            runOperations(listToPopulate, o, operations.iterator());
        }
        return listToPopulate;
    }

    private void runOperations(List<Object> listToPopulate, Object o, Iterator<Operation> operationIterator) {
        if (operationIterator.hasNext()) {
            Operation operation = operationIterator.next();
            if (operation.isFilter()) {
                if (operation.getFilter().apply(o)) {
                    runOperations(listToPopulate, o, operationIterator);
                }
            } else if (operation.isTransform()) {
                runOperations(listToPopulate, operation.getTransform().apply(o), operationIterator);
            }    
        } else {
            listToPopulate.add(o);
        }
    }

    private static Boolean included(List<Predicate> filters, Object o) {
        for (Predicate p : filters) {
            if (!(p.apply(o))) {
                return false;
            }
        }
        return true;
    }

    public FluentIterable filter(Predicate p) {
        operations.add(new Filter(p));
        return this;
    }

    public FluentIterable transform(Function f) {
        operations.add(new Transform(f));
        return this;
    }
}

Listing of FluentIterableTest.cls:

@isTest
public class FluentIterableTest
{
    @isTest static void testFilter()
    {
        List<String> toFilter = new List<String> {'1','2','3','4'};
        List<Integer> filtered = (List<Integer>) FluentIterable.fromList(
            toFilter
        ).transform(
            new ToInteger()
        ).filter(
            new EvenPredicate()
        ).intoList(
            new List<Integer>()
        );
        System.assertEquals(2, filtered.size());
        System.assertEquals(2, filtered[0]);
        System.assertEquals(4, filtered[1]);
    }

    @isTest static void testFilter2()
    {
        List<String> toFilter = new List<String> {'1','two','2','3','4'};
        List<Integer> filtered = (List<Integer>) FluentIterable.fromList(
            toFilter
        ).filter(
            new IsNumeric()
        ).transform(
            new ToInteger()
        ).filter(
            new EvenPredicate()
        ).intoList(
            new List<Integer>()
        );
        System.assertEquals(2, filtered.size());
        System.assertEquals(2, filtered[0]);
        System.assertEquals(4, filtered[1]);
    }

    private class ToInteger implements Function
    {
        public Object apply(Object o)
        {
            return Integer.valueOf((String) o);
        }
    }

    private class EvenPredicate implements Predicate
    {
        public Boolean apply(Object o)
        {
            Integer i = (Integer) o;
            return Math.mod(i, 2) == 0;
        }
    }

    private class IsNumeric implements Predicate
    {
        private Pattern numericPattern = Pattern.compile('^\\d+$');
        public Boolean apply(Object o)
        {
            String s = (String) o;
            return numericPattern.matcher(s).matches();
        }
    }
}