Streams to
rule the world
Into the Box 2020
Gavin Pickin
CBStreams => Accelerate Your Functional Programming!
●
About Me?
Who am I?
● Software Consultant for Ortus Solutions
● Work with ColdBox, CommandBox, ContentBox every day
● Working with Coldfusion for 22 years
● Working with Javascript just as long
● Love learning and sharing the lessons learned
● From New Zealand, live in Bakersfield, Ca
● Loving wife, lots of kids, and countless critters
http://www.gpickin.com and @gpickin on twitter
http://www.ortussolutions.com
What are Java Streams
What is CBStreams
Imperative vs Functional Programming
Building Streams
Using Streams
Collecting Streams
What are Java Streams
• Introduced in JDK 8+
• Not I/O Streams
• A data abstraction layer
• Does not store any data, it wraps the data
• Designed to process streams of data elements
• map(), reduce(), filter(), collect()
• Enables functional-style operations on such elements
https://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html
Dr. Venkat Subramaniam
• Streams Changed My Life!
• Devnexus Presentations
• Streams
• Completeable Futures
• Watch these videos
Lambdas + Streams Streams
What is CBStreams
• Port of Java Streams to CFML Land!
• 90% of all Java functionality is there
• Plus some CFML Dynamic Goodness
• Box Module (ColdBox, CommandBox,
etc)
https://forgebox.io/view/cbstreams
install cbstreams
Imperative
VS
Functional
Programming
Imperative Programming
• Major OO languages are imperative (C,++,C#, Java)
• Follow a top-down or procedural design to reach a goal
• Each statement changes the state (side-effect) of a program
• Each statement tells the computer what to change and in what order
• Always cons and pros
function isPrime( number ) {
for( var i = 2; i <= sqr( number ); i++) {
if(number % i == 0) return false;
}
return number > 1;
}
isPrime(9220000000000000039) // Output: true
Functional Programming
• Declarative programming
• We tell the computer what things, actions, etc are
• Runtime determines the best way how to do it
• Functions are first class citizens
• No side-effect or iterating state to worry about
• Always cons and pros
function isPrime(number) {
return number > 1 &&
stream
.rangeClosed( 2, sqr( number ) )
.noneMatch( index => number % index == 0 );
}
isPrime( 9220000000000000039 ) // Output: true
Functional Programming
Comparing Styles
Streams Functional Heaven!
• All about functional programming
• Heavy Lambda/Closure usage
• Must focus on the what and not on the how!
• Create a data processing pipeline
• Not for everything, choose wisely….
You have been warned!
Streams Functional Heaven!
var errors = [];
var errorCount = 0;
var oFile = fileOpen( filename );
var thisLine = fileReadLine( oFile );
while( errorCount < 40 && !isNull( thisLine ) ){
if( line.startsWith( "ERROR" ) ){
errors.append( line );
errorCount++;
}
line = fileReadLine( oFile );
}
var errors = streamBuilder.ofFile( filePath )
.filter( line => line.startsWith( "ERROR" ) )
.limit( 40 )
.collect();
What if I want
to multi-thread
this?
.parallel()
What about CFML Functions?
• They are limited in input, scope & operations
• No short-circuiting operations
• No lazyness, they all fire top to bottom
• Each operation blocks until it finishes processing ALL
elements
• Creates new arrays/queries/structs for each new
concatenated operation
• What about infinite input or biiiiig files?
• map(), reduce(), each(), filter()
Element Stream
Stream Processing Pipeline
Lazy!
Stream Lazyness!
Lazy Example
var empIds = [ 1, 2, 3, 4 ];
var employee = streamBuilder.new( empIds )
// Convert ID's to Employee Objects, passing function reference
.map( employeeService.findByID )
// only valid employees
.filter( (employee) => !isNull( employee ) )
// same as: .filter( function( employee ){ return !isNull (employee); } )
// only salaries > 10000
.filter( (employee) => employee.getSalary() > 100000 )
// Find the first one
.findFirst()
// Return null
.orElse( null );
expect( employee.getSalary() ).toBe( 200000 );
• Stream performs the map and two filter operations, one element at a time.
• Since the salary of id 1 is not greater than 100000, the processing moves on to the next
element.
• Id 2 satisfies both of the filter predicates and hence the stream evaluates the terminal
operation findFirst() and returns the result.
• No operations are performed on id 3 and 4.
Let’s Get Started!
install cbstreams
StreamBuilder@cbstreams
• The StreamBuilder is injected where needed
• Helps you build streams out of native CFML data types
• Strings, Files, Arrays, Structs, Queries, Nulls
• Helps you build infinite or closure based streams
• You can strong type elements for the stream if needed
• For mathematical operations
• int, long, or double
Empty Streams
emptyStream = streamBuilder.new();
emptyStream = streamBuilder.new().empty();
• Simple way to build streams with no elements
• Useful? Maybe…
Building Custom Streams
builder = streamBuilder.builder();
myData.each( function( item ){
builder.add( item );
} );
myStream = builder.build();
stream = streamBuilder.new()
.of( "a", "hello", "stream" );
stream = streamBuilder.new()
.of( argumentCollection=myData );
• Two approaches:
• builder() - Add your own data via the add() method
• Of( arguments ) - Via an array of arguments
Streams of Characters
stream = streamBuilder.new().ofChars( "Welcome to Streams" );
• Stream of string characters
• Great for parsing, lookups, etc.
File Streams
stream = streamBuilder.new().ofFile( absolutePath );
try{
//work on the stream
} finally{
stream.close();
}
• Non Blocking I/O Classes
• Stream of file lines
• Throw any file size to it, I dare ya!
Generate Infinite Streams
// Generate 100 random numbers
stream = streamBuilder.new().generate( function(){
return randRange( 1, 100 );
} ).limit( 100 );
// Seeded iteration
stream = streamBuilder.new().iterate( 40, function( x ){
return x + 2;
} ).limit( 20 );
• Infinite streams of data
• Start with a seed or no seeded results
• Make sure you limit them or wait forever….
Ranged Streams
stream = streamBuilder.new().range( 1, 200 );
stream = streamBuilder.new().rangeClosed( 1, 2030 );
stream = streamBuilder.new().rangeClosed( 1, qUsers.recordcount );
• Create open or closed ranges
• Similar to of() but a whole less typing
Intermediate Operations
• Remember, they are lazy, nothing gets done until a terminator is called.
• Result is always a stream
Operation Description
limit( maxSize ) Limit the stream processing
distinct() Return only distinct elements
skip( n ) Skip from the first element to n
sorted( comparator ) Sort a stream using a compactor closure
unordered() Return an unordered stream (default)
onClose( closeHandler ) Attach a listener to when the close operation is called
concat( stream1, stream2 ) Concatenates two streams together
peek( action ) Allows you to peek on the element in the order is called
Map( mapper ) Transform the elements into something else
filter( predicate ) Returns a new stream containing only the requested elements
parallel() Convert the stream to a parallel multi-threaded stream
Terminal Operations
• They kick off processing of elements sequentially or in parallel
Operation Description
iterator() Returns a java iterator
spliterator() Returns a java spliterator
close() Close the stream
toArray() Convert the stream back into an array
count() Count the elements in the stream
forEach( action ) Iterate through the elements calling the action closure
forEachOrdered( action ) Iterate through the elements calling the action closure in order, even in parallel
reduce( accumulator, identity ) Fold, reduces the stream to a single element.
max( comparator ) Returns the max value in the stream, if a comparator is passed its called for you
min( comparator ) Returns the min value in the stream, if a comparator is passed its called for you
average( comparator ) Returns the avg value in the stream, if a comparator is passed its called for you
summaryStatistics() Gives you a struct of stats containing: { min, max, count, sum, average }
Short-Circuit Operations
• Also terminal, but can short-circuit processing of the stream
Operation Description
findAny() Find any element in the stream
findFirst() Find the first element in the stream
anyMatch( predicate ) Returns a boolean that indicates if any of the elements match the predicate closure
allMatch( predicate ) Returns a boolean that indicates if ALL of the elements match the predicate closure
noneMatch( predicate ) Returns a boolean that indicates if none of the elements match the predicate closure
Collectors
• Finalizes the stream by converting it to concrete collections
• CBStreams auto-converts Java -> CFML Data Types
Operation Description
collect() Return an array of the final elements
collectGroupingBy( classifier )
Build a final collection according to the classifier lambda/closure that
will classify the keys in the group. End result is usually a struct of data
collectAverage( mapper, primitive=long )
Collect an average according to the mapper function/closure and data
type passed
collectSum( mapper, primitive=long )
Collect a sum according to the mapper function/closure and data type
passed
collectSummary( mapper, primitive=long )
Collect a statistics struct according to the mapper function and data type
passed
collectAsList( delimiter=“,”, prefix, suffix )
Collect results into a string list with a delimiter and attached prefix
and/or suffix.
collectAsStruct( keyId, valueID, overwrite=true )
Collect the elements into a struct by leveraging the key identifier and the
value identifier from the stream of elements to pass into the collection.
collectPartitioningBy( predicate )
partitions the input elements according to a Predicate closure/lambda,
and organizes them into a Struct of <Boolean, array >.
Lambda/Closure
References
• CBStreams converts CFML Closures -> Java Lambdas
• Let’s investigate them by Java name:
// BiFunction, BinaryOperator
function( previous, item ){
return item;
}
// Comparator
function compare( o1, o2 ){
return -,+ or 0 for equal
}
// Consumer
void function( item ){
}
// Function, ToDoubleFunction, ToIntFunction,
ToLongFunction, UnaryOperator
function( item ){
return something;
}
// Predicate
boolean function( item ){
return false;
}
// Supplier
function(){
return something;
}
// Runnable
void function(){
// execute something
}
CBStreams Optionals
• Most return values are not the actual values but a CFML Optional
• Wraps a Java Optional
• Simple functional value container instead of doing null checks, with some
cool functions
Operation Description
isPresent() Returns boolean if value is present
ifPresent( consumer ) If value is present call the consumer closure for you
filter( predicate )
If a value is present and the value matches the predicate then return another
Optional :)
map( mapper ) If a value is present, apply the mapping function and return another Optional
get() Get the value!
orElse( other ) Get the value or the `other` if the value is null
orElseGet( other ) Get the value or if not present call the other closure to return a value
hashCode() Unique hash code of the value
toString() Debugging
Examples
myArray = [
"ddd2", "aaa2", "bbb1", "aaa1",
"bbb3", "ccc", "bbb2", "ddd1"
];
// Filtering
streamBuilder.new( myArray )
.filter( function( item ){
return item.startsWith( "a" );
} )
.forEach( function( item ){
writedump( item );
} );
Examples
// Sorted Stream
streamBuilder.new( myArray )
.sorted()
.filter( function( item ){
return item.startsWith( "a" );
} )
.forEach( function( item ){
writedump( item );
} );
Examples
// Mapping
streamBuilder.new( myArray )
.map( function( item ){
return item.ucase();
})
.sorted( function( a, b ){
return a.compareNoCase( b );
}
.forEach( function( item ){
writedump( item );
} );
Examples
// Partition stream to a struct of arrays according to even/odd
var isEven = streamBuilder.new( 2,4,5,6,8 )
.collectPartitioningBy( function(i){
return i % 2 == 0;
} );
expect( isEven[ "true" ].size() ).toBe( 4 );
expect( isEven[ "false" ].size() ).toBe( 1 );
Examples
// Group employees into character groups
component{
var groupByAlphabet = streamBuilder.of( employeeArray )
.collectGroupingBy( function( employee ){
return listFirst( employee.getlastName(), “” );
} );
expect( groupByAlphabet.get( 'B' ).get( 0 ).getName() )
.toBe( "Bill Gates" );
expect( groupByAlphabet.get( 'J' ).get( 0 ).getName() )
.toBe( "Jeff Bezos" );
expect( groupByAlphabet.get( 'M' ).get( 0 ).getName() )
.toBe( "Mark Zuckerberg" );
}
Examples
// Matching
anyStartsWithA =
streamBuilder
.new( myArray )
.anyMatch( function( item ){
return item.startsWith( "a" );
} );
writeDump( anyStartsWithA ); // true
allStartsWithA =
streamBuilder
.new( myArray )
.allMatch( function( item ){
return item.startsWith( "a" );
} );
writeDump( anyStartsWithA ); // false
Examples
noneStartsWithZ =
streamBuilder
.new( myArray )
.noneMatch((s) -> s.startsWith("z"));
noneStartsWithZ =
streamBuilder
.new( myArray )
.noneMatch( function( item ){
return item.startsWith( "z" );
} );
writeDump( noneStartsWithZ ); // true
Examples
// Reduce
optional =
streamBuilder
.new( myArray )
.sorted()
.reduce( function( s1, s2 ){
return s1 & "#" & s2;
} );
writedump( optional.get() );
Examples
// Parallel Sorted Count
count =
streamBuilder
.new( myArray )
.parallel()
.sorted()
.count();
Implement JDK 9-10 features
Threading Intricacies to solve
cbORM, Quick Integration
qb Integration
ColdBox Integration
Reactive Streams
Roadmap
Questions??
● After the presentation in the Breakout Room
● On the Boxteam slack channel - boxteam.herokuapp.com
● On Twitter @lmajano @gpickin @ortussolutions

cb streams - gavin pickin

  • 1.
    Streams to rule theworld Into the Box 2020 Gavin Pickin
  • 2.
    CBStreams => AccelerateYour Functional Programming!
  • 3.
  • 4.
    Who am I? ●Software Consultant for Ortus Solutions ● Work with ColdBox, CommandBox, ContentBox every day ● Working with Coldfusion for 22 years ● Working with Javascript just as long ● Love learning and sharing the lessons learned ● From New Zealand, live in Bakersfield, Ca ● Loving wife, lots of kids, and countless critters http://www.gpickin.com and @gpickin on twitter http://www.ortussolutions.com
  • 5.
    What are JavaStreams What is CBStreams Imperative vs Functional Programming Building Streams Using Streams Collecting Streams
  • 6.
    What are JavaStreams • Introduced in JDK 8+ • Not I/O Streams • A data abstraction layer • Does not store any data, it wraps the data • Designed to process streams of data elements • map(), reduce(), filter(), collect() • Enables functional-style operations on such elements https://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html
  • 7.
    Dr. Venkat Subramaniam •Streams Changed My Life! • Devnexus Presentations • Streams • Completeable Futures • Watch these videos Lambdas + Streams Streams
  • 8.
    What is CBStreams •Port of Java Streams to CFML Land! • 90% of all Java functionality is there • Plus some CFML Dynamic Goodness • Box Module (ColdBox, CommandBox, etc) https://forgebox.io/view/cbstreams install cbstreams
  • 9.
  • 10.
    Imperative Programming • MajorOO languages are imperative (C,++,C#, Java) • Follow a top-down or procedural design to reach a goal • Each statement changes the state (side-effect) of a program • Each statement tells the computer what to change and in what order • Always cons and pros function isPrime( number ) { for( var i = 2; i <= sqr( number ); i++) { if(number % i == 0) return false; } return number > 1; } isPrime(9220000000000000039) // Output: true
  • 11.
    Functional Programming • Declarativeprogramming • We tell the computer what things, actions, etc are • Runtime determines the best way how to do it • Functions are first class citizens • No side-effect or iterating state to worry about • Always cons and pros function isPrime(number) { return number > 1 && stream .rangeClosed( 2, sqr( number ) ) .noneMatch( index => number % index == 0 ); } isPrime( 9220000000000000039 ) // Output: true Functional Programming
  • 12.
  • 13.
    Streams Functional Heaven! •All about functional programming • Heavy Lambda/Closure usage • Must focus on the what and not on the how! • Create a data processing pipeline • Not for everything, choose wisely…. You have been warned!
  • 14.
    Streams Functional Heaven! varerrors = []; var errorCount = 0; var oFile = fileOpen( filename ); var thisLine = fileReadLine( oFile ); while( errorCount < 40 && !isNull( thisLine ) ){ if( line.startsWith( "ERROR" ) ){ errors.append( line ); errorCount++; } line = fileReadLine( oFile ); } var errors = streamBuilder.ofFile( filePath ) .filter( line => line.startsWith( "ERROR" ) ) .limit( 40 ) .collect(); What if I want to multi-thread this? .parallel()
  • 15.
    What about CFMLFunctions? • They are limited in input, scope & operations • No short-circuiting operations • No lazyness, they all fire top to bottom • Each operation blocks until it finishes processing ALL elements • Creates new arrays/queries/structs for each new concatenated operation • What about infinite input or biiiiig files? • map(), reduce(), each(), filter()
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
    Lazy Example var empIds= [ 1, 2, 3, 4 ]; var employee = streamBuilder.new( empIds ) // Convert ID's to Employee Objects, passing function reference .map( employeeService.findByID ) // only valid employees .filter( (employee) => !isNull( employee ) ) // same as: .filter( function( employee ){ return !isNull (employee); } ) // only salaries > 10000 .filter( (employee) => employee.getSalary() > 100000 ) // Find the first one .findFirst() // Return null .orElse( null ); expect( employee.getSalary() ).toBe( 200000 ); • Stream performs the map and two filter operations, one element at a time. • Since the salary of id 1 is not greater than 100000, the processing moves on to the next element. • Id 2 satisfies both of the filter predicates and hence the stream evaluates the terminal operation findFirst() and returns the result. • No operations are performed on id 3 and 4.
  • 21.
    Let’s Get Started! installcbstreams StreamBuilder@cbstreams • The StreamBuilder is injected where needed • Helps you build streams out of native CFML data types • Strings, Files, Arrays, Structs, Queries, Nulls • Helps you build infinite or closure based streams • You can strong type elements for the stream if needed • For mathematical operations • int, long, or double
  • 22.
    Empty Streams emptyStream =streamBuilder.new(); emptyStream = streamBuilder.new().empty(); • Simple way to build streams with no elements • Useful? Maybe…
  • 23.
    Building Custom Streams builder= streamBuilder.builder(); myData.each( function( item ){ builder.add( item ); } ); myStream = builder.build(); stream = streamBuilder.new() .of( "a", "hello", "stream" ); stream = streamBuilder.new() .of( argumentCollection=myData ); • Two approaches: • builder() - Add your own data via the add() method • Of( arguments ) - Via an array of arguments
  • 24.
    Streams of Characters stream= streamBuilder.new().ofChars( "Welcome to Streams" ); • Stream of string characters • Great for parsing, lookups, etc.
  • 25.
    File Streams stream =streamBuilder.new().ofFile( absolutePath ); try{ //work on the stream } finally{ stream.close(); } • Non Blocking I/O Classes • Stream of file lines • Throw any file size to it, I dare ya!
  • 26.
    Generate Infinite Streams //Generate 100 random numbers stream = streamBuilder.new().generate( function(){ return randRange( 1, 100 ); } ).limit( 100 ); // Seeded iteration stream = streamBuilder.new().iterate( 40, function( x ){ return x + 2; } ).limit( 20 ); • Infinite streams of data • Start with a seed or no seeded results • Make sure you limit them or wait forever….
  • 27.
    Ranged Streams stream =streamBuilder.new().range( 1, 200 ); stream = streamBuilder.new().rangeClosed( 1, 2030 ); stream = streamBuilder.new().rangeClosed( 1, qUsers.recordcount ); • Create open or closed ranges • Similar to of() but a whole less typing
  • 28.
    Intermediate Operations • Remember,they are lazy, nothing gets done until a terminator is called. • Result is always a stream Operation Description limit( maxSize ) Limit the stream processing distinct() Return only distinct elements skip( n ) Skip from the first element to n sorted( comparator ) Sort a stream using a compactor closure unordered() Return an unordered stream (default) onClose( closeHandler ) Attach a listener to when the close operation is called concat( stream1, stream2 ) Concatenates two streams together peek( action ) Allows you to peek on the element in the order is called Map( mapper ) Transform the elements into something else filter( predicate ) Returns a new stream containing only the requested elements parallel() Convert the stream to a parallel multi-threaded stream
  • 29.
    Terminal Operations • Theykick off processing of elements sequentially or in parallel Operation Description iterator() Returns a java iterator spliterator() Returns a java spliterator close() Close the stream toArray() Convert the stream back into an array count() Count the elements in the stream forEach( action ) Iterate through the elements calling the action closure forEachOrdered( action ) Iterate through the elements calling the action closure in order, even in parallel reduce( accumulator, identity ) Fold, reduces the stream to a single element. max( comparator ) Returns the max value in the stream, if a comparator is passed its called for you min( comparator ) Returns the min value in the stream, if a comparator is passed its called for you average( comparator ) Returns the avg value in the stream, if a comparator is passed its called for you summaryStatistics() Gives you a struct of stats containing: { min, max, count, sum, average }
  • 30.
    Short-Circuit Operations • Alsoterminal, but can short-circuit processing of the stream Operation Description findAny() Find any element in the stream findFirst() Find the first element in the stream anyMatch( predicate ) Returns a boolean that indicates if any of the elements match the predicate closure allMatch( predicate ) Returns a boolean that indicates if ALL of the elements match the predicate closure noneMatch( predicate ) Returns a boolean that indicates if none of the elements match the predicate closure
  • 31.
    Collectors • Finalizes thestream by converting it to concrete collections • CBStreams auto-converts Java -> CFML Data Types Operation Description collect() Return an array of the final elements collectGroupingBy( classifier ) Build a final collection according to the classifier lambda/closure that will classify the keys in the group. End result is usually a struct of data collectAverage( mapper, primitive=long ) Collect an average according to the mapper function/closure and data type passed collectSum( mapper, primitive=long ) Collect a sum according to the mapper function/closure and data type passed collectSummary( mapper, primitive=long ) Collect a statistics struct according to the mapper function and data type passed collectAsList( delimiter=“,”, prefix, suffix ) Collect results into a string list with a delimiter and attached prefix and/or suffix. collectAsStruct( keyId, valueID, overwrite=true ) Collect the elements into a struct by leveraging the key identifier and the value identifier from the stream of elements to pass into the collection. collectPartitioningBy( predicate ) partitions the input elements according to a Predicate closure/lambda, and organizes them into a Struct of <Boolean, array >.
  • 32.
    Lambda/Closure References • CBStreams convertsCFML Closures -> Java Lambdas • Let’s investigate them by Java name: // BiFunction, BinaryOperator function( previous, item ){ return item; } // Comparator function compare( o1, o2 ){ return -,+ or 0 for equal } // Consumer void function( item ){ } // Function, ToDoubleFunction, ToIntFunction, ToLongFunction, UnaryOperator function( item ){ return something; } // Predicate boolean function( item ){ return false; } // Supplier function(){ return something; } // Runnable void function(){ // execute something }
  • 33.
    CBStreams Optionals • Mostreturn values are not the actual values but a CFML Optional • Wraps a Java Optional • Simple functional value container instead of doing null checks, with some cool functions Operation Description isPresent() Returns boolean if value is present ifPresent( consumer ) If value is present call the consumer closure for you filter( predicate ) If a value is present and the value matches the predicate then return another Optional :) map( mapper ) If a value is present, apply the mapping function and return another Optional get() Get the value! orElse( other ) Get the value or the `other` if the value is null orElseGet( other ) Get the value or if not present call the other closure to return a value hashCode() Unique hash code of the value toString() Debugging
  • 34.
    Examples myArray = [ "ddd2","aaa2", "bbb1", "aaa1", "bbb3", "ccc", "bbb2", "ddd1" ]; // Filtering streamBuilder.new( myArray ) .filter( function( item ){ return item.startsWith( "a" ); } ) .forEach( function( item ){ writedump( item ); } );
  • 35.
    Examples // Sorted Stream streamBuilder.new(myArray ) .sorted() .filter( function( item ){ return item.startsWith( "a" ); } ) .forEach( function( item ){ writedump( item ); } );
  • 36.
    Examples // Mapping streamBuilder.new( myArray) .map( function( item ){ return item.ucase(); }) .sorted( function( a, b ){ return a.compareNoCase( b ); } .forEach( function( item ){ writedump( item ); } );
  • 37.
    Examples // Partition streamto a struct of arrays according to even/odd var isEven = streamBuilder.new( 2,4,5,6,8 ) .collectPartitioningBy( function(i){ return i % 2 == 0; } ); expect( isEven[ "true" ].size() ).toBe( 4 ); expect( isEven[ "false" ].size() ).toBe( 1 );
  • 38.
    Examples // Group employeesinto character groups component{ var groupByAlphabet = streamBuilder.of( employeeArray ) .collectGroupingBy( function( employee ){ return listFirst( employee.getlastName(), “” ); } ); expect( groupByAlphabet.get( 'B' ).get( 0 ).getName() ) .toBe( "Bill Gates" ); expect( groupByAlphabet.get( 'J' ).get( 0 ).getName() ) .toBe( "Jeff Bezos" ); expect( groupByAlphabet.get( 'M' ).get( 0 ).getName() ) .toBe( "Mark Zuckerberg" ); }
  • 39.
    Examples // Matching anyStartsWithA = streamBuilder .new(myArray ) .anyMatch( function( item ){ return item.startsWith( "a" ); } ); writeDump( anyStartsWithA ); // true allStartsWithA = streamBuilder .new( myArray ) .allMatch( function( item ){ return item.startsWith( "a" ); } ); writeDump( anyStartsWithA ); // false
  • 40.
    Examples noneStartsWithZ = streamBuilder .new( myArray) .noneMatch((s) -> s.startsWith("z")); noneStartsWithZ = streamBuilder .new( myArray ) .noneMatch( function( item ){ return item.startsWith( "z" ); } ); writeDump( noneStartsWithZ ); // true
  • 41.
    Examples // Reduce optional = streamBuilder .new(myArray ) .sorted() .reduce( function( s1, s2 ){ return s1 & "#" & s2; } ); writedump( optional.get() );
  • 42.
    Examples // Parallel SortedCount count = streamBuilder .new( myArray ) .parallel() .sorted() .count();
  • 43.
    Implement JDK 9-10features Threading Intricacies to solve cbORM, Quick Integration qb Integration ColdBox Integration Reactive Streams Roadmap
  • 44.
    Questions?? ● After thepresentation in the Breakout Room ● On the Boxteam slack channel - boxteam.herokuapp.com ● On Twitter @lmajano @gpickin @ortussolutions