Skip to content

Streams code samples

flbulgarelli edited this page Mar 15, 2012 · 11 revisions

Streams Code Samples

Introduction

An snippet is worth a thousand words, so here we provide code samples of stream constructed using Streams hub.

Examples

Streams offer more than 130 operations. Some of them are shown here.

Filtering and mapping

With Streams you can perform the most common functional-style list operations: filtering (aka select) and mapping (aka collect). Also, any stream can be converted into a List, Set or Array, and is already Iterable.

    import static net.sf.staccatocommons.lang.Compare.*;
    import static net.sf.staccatocommons.lang.number.NumberTypes.*;
    
    //Answer the next integers of those > 30 in the list [20, 60, 9, 31, 26]
    Streams
     .cons(20, 60, 9, 31, 26)
     .filter(greaterThan(30))
     .map(add(1))
     .toList();

Mapping and getting average

You can also create Streams by wrapping collections:

    interface BusinessArea { BigDecimal getBucket(); }

    List<BusinessArea> businessAreas = ...;

   //Return the average bucket of the business areas
    Streams
     .from(businessAreas) //
     .map(lambda($(BusinessArea.class).getBucket()))
     .average(bigDecimal());

Comparing elements of an enumeration and and iterable

Streams are useful for dealing with the legacy Enumeration API

  //Are the first elements of legacyAttributeNames equal
  //  - and in the same order  - to ["attr1", "attr2", "attr3"] ?
  Enumeration<String> legacyAttributeNames = ...;

  Streams
     .from(legacyProperyNames)
     .take(3)
     .equiv("attr1", "attr2", "attr3");

Filtering based on index, and printing

Streams may also filter based on the index of elements, which is useful when stream's source is ordered - like a java.util.List or a String

  //Prints elements in positions between 4 and 8
  Streams.from(...an ordered source...)
         .filterIndex(Compare.between(4, 8))
         .println();

Random access over streams with undefined elements

Unlike many functional-style collection frameworks, Streams are truly lazy: they do not even to compute previous elements in order to get the next one.

 //Answers the third element of the stream [1/50,1/0,1/60,1/10].
 // Notice that second element is undefined - evaluating it would result in an ArithmeticException,
 // but thanks to stream laziness, the operation succeeds  
 Streams 
    .cons(50, 0, 60, 10)
    .map(integer().inverse())
    .third();

Dropping and getting any element

    interface Fruit {...};
    class Apple implements Fruit {...};
    Iterator<Fruit> fruits = ...;
    
    //Answers any fruit, except of the first one.
    //If there is no fruit, or just one fruit element, 
    //returns a new Apple.
    Streams
      .from(fruits)
      .drop(1)
      .anyOrElse(new Apple());

Folding elements

You can perform (left)folds - aka injectInto using the fold message:

  //Calculates the product of [2..10]
  //Equivalent to Streams.enumerate(2,10).product(integer());
  Streams.enumerate(2, 10).fold(1, integer().multiply()); //answers 2 * 3 * .. * 10 = 3628800

Reducing elements with Staccatissimo-Reductions

In addition to standard folds, you can perform reductions that do not have initial value, or even use a Reduction:

TODO

Getting the Cartesian product and testing all elements

    interface Buyer {
        boolean buys(Product product);
    }
    interface Product {}

    Collection<Product> products = ...;
    Collection<Buyer> buyers = ...;

    //Answers if all buyers can buy all the products
    Streams
      .from(buyers)
      .cross(Streams.from(products))
      .all(new AsbtractPredicate<Pair<Buyer, Product>>() {
          public boolean eval(Pair<Buyer, Product> p) {
              return p.first().buys(p.second());
          }
      });

Concatenating, FlatMapping and getting max element

    interface Holding { 
        Collection<Company> getCompanies();
    }
    interface Company {
        BigDecimal getRevenue();
    }
    
    Collection<Holding> otherHoldings = ...;
    Holding thisHolding = ...;
    
    //Answer the company that has the highest revenue, among all the companies 
    //of thisHolding and otherHoldings
    Streams
        .cons(thisHolding)
        .concat(otherHoldings)
        .flatMap(lambda($(Holding.class).getCompanies()))
        .maximumOn(lambda($(Company.class).getRevenue()));

Finding an element

    interface Product { 
        String getSku();
        URI getDetailsPage();
    }
    
    Iterable<Product> products = ...;
    //Answer the first product whose SKU is "PX896-A"
    Streams
        .cons(products)
        .find(lambda($(Product.class).getSku()).equal("PX896-A"));
        
    //Answer the first product with a non null details page
    Streams
        .cons(products)
        .find(lambda($(Product.class).getDetailsPage()).notNull());     
        

Grouping elements on an attribute

    class Recording { 
        public String getTitle() { ... }
        public Author getAuthor() { ... }
        public int getLengthInMinutes() { ... }
    }
    
    Iterable<Recording> recordings = ...;
    
    //Group recordings by its author, and
    //aggregate the total length all the recordings for each of them
    Map<Author, Integer> totalRecordingLengthByAuthor = 
       Streams
        .cons(recordings)
        .groupOn(
            lambda($(Recording.class).getAuthor()), 
            lambda($(Recording.class).getLengthInMinutes()),
            integer().add());

Using Strings as streams, and testing if an element is before another

Streams can also wrap CharSequences out of the box:

 
//Is Character 'W' before character '!'?
 Streams
   .from("Hello World!")
   .isBefore('W', '!'); //true        
   

Prepending, Appending and Inserting into an Array

    Class[] classes = new Class[]{String.class, Integer.class, Object.class}; 
    Class[] moreClasses = Streams
      .from(classes)
      .append(Thread.class) //adds as last element
      .insertBeforeIndex(List.class, 1) //adds at position 1
      .insertBefore(Double.class, Object.class) //adds before Object
      .prepend(Collection.class) //adds as first element
      .toArray(Class.class); // answers [Collection, String, List, Integer, Double, Object, Thread]

Learn More