Skip to content
flbulgarelli edited this page Jan 28, 2012 · 1 revision

Streams

Introduction

Streams are potentially infinite, Iterable objects that have a very rich interface and perform most operations in a lazy manner and functional style. They are designed to make complex, truly lazy transformations on iterable or iterable-like objects easier. Although they are primary targeted for dealing with collections, other StaccatoCommons projects offer other alternative implementations that extend their scope.

On the other hand, for performing simple, eager transformations on just iterables, eventually in a more imperative style, have a look at Iterables.

The problem

Quite frequently, developers need to perform in-memory complex, chained transformations over collections, like finding, filtering or mapping elements. In Java, without any support for those operation neither at language nor standard library level, developers have usually to implement them writing ad-hoc methods. Code like the following is far too common:

   /**Gets top 5 more urgent incidents of services that are down*/
   Collection<Incident> getMostUrgentProblems() {
        List<Incident> incidents = new ArrayList<Incident>();
        for (Service service : services) {
            if (service.isDown()) {
                incidents.add(service.getMostRecentIncident());
            }
        }
        Collections.sort(incidents, new Comparator<Incident>() {
            public int compare(Incident arg0, Incident arg1) {
                return arg0.getPriority() - arg1.getPriority();
            }
        });
        if (incidents.size() > 5) {
            for (Iterator<Incident> iter = incidents.listIterator(5); iter.hasNext();) {
                iter.next();
                iter.remove();
            }
        }
        return incidents;
    }

The problem of such code is that it is reinventing the wheel, mixing different transformations in one. In this case, developer is filtering down services, mapping their most recent incidents, and getting top 5 most urgent issues by priority - 4 operations that need to be coded, tested, and probably debugged.

Fortunately, many Java frameworks exists that attack those problems, each one with its pros and cons: Apache Commons Collections, Guava, TotallyLazy, FunctionalJava, Op4J, and of course, Staccatissimo-Collections.

It is not our intention to make a comparison between all those frameworks. As said before, all them have both strengths and flaws, and the developer should decide which fits better. Instead, we will just present the solution Staccatissimo-Collections offers: fully object-oriented, truly lazy, highly rich interfaces Streams, targeted for both developers with and without any functional background, but exploding all its power.

The Solution

Streams are the Staccatissimo solution for performing such operations on iterables. They are generic wrappers that implement many of those common transformation in a lazy manner - that is, no processing is actually performed in most cases unless it it actually necessary, which enables them to perform efficiently chained operations on demand on both small and very large sequences of elements.

For example, the previous code can be refactored to use Streams:

    Collection<Incident> getMostUrgentProblems2() {
        return Streams.from(services).filter(new AbstractPredicate<Service>() {
            public boolean eval(Service argument) {
                return argument.isDown();
            }
        }).map(new AbstractFunction<Service, Incident>() {
            public Incident apply(Service arg) {
                return arg.getMostRecentIncident();
            }
        }).sortOn(new AbstractFunction<Incident, Integer>() {
            public Integer apply(Incident arg) {
                return arg.getPriority();
            }
        }).take(5).toList();
    }

Or even cleaner, if using Staccatissimo-Lambda:

    Collection<Incident> getMostUrgentProblems3() {
        return Streams
            .from(services)
            .filter(lambda($(Service.class).isDown()))
            .map(lambda($(Service.class).getMostRecentIncident()))
            .sortOn(lambda($(Incident.class).getPriority()))
            .take(5)
            .toList();
    }

Constructing Streams

Stream is an interface, and Staccatissimo-Collection provides dozens of implementation of it, but the developer has not to care about it. By using the Streams hub class, you can construct streams by:

  • specifying their elements, using the cons message

  • specifying the elements generation strategy: iterate, enumerate, repeat and similar messages

  • decorating other iterable-like objects, like Collections, Iterators, Strings, Enumerations, and so on, using the from message.

In addition, other Staccatissimo modules and StaccatoCommons projects provide more implementations of Streams, for retrieving databases result sets, directories, file lines, ObjectInputStreams, etc. Even, if you need, you can implement your own Stream by extending AbstractStream

Learn More

  • Streams usage samples

  • Stream Specificaction at its Javadoc: the interface of all streams

  • Streams Javadoc: a class hub for constructing streams of different kinds, from scratch or by adapting many collection-like types.

Clone this wiki locally