-
Notifications
You must be signed in to change notification settings - Fork 2
Streams code samples
An snippet is worth a thousand words, so here we provide code samples of stream constructed using Streams
hub.
Stream
s offer more than 130 operations. Some of them are shown here.
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();
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());
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");
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();
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();
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());
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
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());
}
});
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()));
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());
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());
Streams can also wrap CharSequence
s out of the box:
//Is Character 'W' before character '!'?
Streams
.from("Hello World!")
.isBefore('W', '!'); //true
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]
-
IOStreams provided by Staccatissimo-IO
-
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.