
groovy.stream.Stream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of groovy-stream Show documentation
Show all versions of groovy-stream Show documentation
A collection of classes to give a fluent builder for Streams (Lazy Groovy Generators).
The newest version!
/*
* Copyright 2013-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package groovy.stream ;
import groovy.lang.Closure ;
import groovy.stream.iterators.* ;
import groovy.stream.iterators.java.* ;
import groovy.stream.iterators.groovy.* ;
import groovy.stream.functions.Function ;
import groovy.stream.functions.Function2 ;
import groovy.stream.functions.Predicate ;
import groovy.stream.functions.IndexedFunction ;
import groovy.stream.functions.IndexedFunction2 ;
import groovy.stream.functions.IndexedPredicate ;
import java.io.BufferedReader ;
import java.lang.reflect.Array ;
import java.util.ArrayList ;
import java.util.Collection ;
import java.util.Iterator ;
import java.util.List ;
import java.util.Map ;
import java.util.jar.JarEntry ;
import java.util.jar.JarFile ;
import java.util.zip.ZipEntry ;
import java.util.zip.ZipFile ;
/**
*
* @author Tim Yates
* @param the type of each element returned from the Stream.
*/
public class Stream implements Iterator {
private final Iterator iterator ;
private Stream( Iterator iterator ) {
this.iterator = iterator ;
}
/**
* Filter the current stream, passing each element through a predicate filter.
*
*
* import groovy.stream.*
*
* assert Stream.from( 1..3 )
* .filter { it % 2 == 1 }
* .collect() == [ 1, 3 ]
*
*
* @param predicate A single parameter closure to pass the element through,
* returning {@code true} if the element is to be included.
* @return A new {@code Stream} wrapping a {@link FilteringIterator}
*/
public Stream filter( Closure predicate ) {
return new Stream( new FilteringIterator( iterator, predicate, false ) ) ;
}
/**
* Filter the current stream, passing each element through a predicate filter (Java friendly version).
*
* @param predicate A {@link Predicate} instance returning {@code true} from it's {@code call} method
* if the element is to be included.
* @return A new {@code Stream} wrapping a {@link FilteringIteratorForPredicate}
*/
public Stream filter( Predicate predicate ) {
return new Stream( new FilteringIteratorForPredicate( iterator, predicate ) ) ;
}
/**
* Filter the current stream, passing each element and it's index through a predicate filter.
*
*
* import groovy.stream.*
*
* assert Stream.from( 1..3 )
* .filterWithIndex { it, index -> index % 2 == 1 }
* .collect() == [ 2 ]
*
*
* @param predicate A two parameter closure, the first parameter being the
* element in the {@code Stream}, the second the index (starting at 0).
* @return A new {@code Stream} wrapping a {@link FilteringIterator}
*/
public Stream filterWithIndex( Closure predicate ) {
return new Stream( new FilteringIterator( iterator, predicate, true ) ) ;
}
/**
* Filter the current stream, passing each element and its index through a predicate filter (Java friendly version).
*
* @param predicate An {@link IndexedPredicate} instance returning {@code true} from it's {@code call} method
* if the element is to be included.
* @return A new {@code Stream} wrapping a {@link FilteringIteratorForIndexedPredicate}
*/
public Stream filterWithIndex( IndexedPredicate predicate ) {
return new Stream( new FilteringIteratorForIndexedPredicate( iterator, predicate ) ) ;
}
/**
* Returns a new {@code Stream} which will iterate the elements in the current {@code Stream},
* followed by the elements in the {@code other} {@code Stream}.
*
*
* import groovy.stream.*
*
* def a = Stream.from( 1..3 )
* def b = Stream.from( 'a'..'c' )
*
* assert a.concat( b ).collect() == [ 1, 2, 3, 'a', 'b', 'c' ]
*
*
* @param other The {@code Stream} to iterate after the current one is exhausted.
* @return A new {@code Stream} wrapping a {@link ConcatenationIterator}
*/
public Stream concat( Iterator extends T> other ) {
return new Stream( new ConcatenationIterator( iterator, other ) ) ;
}
/**
* Skip {@code n} elements.
*
*
* import groovy.stream.*
*
* assert Stream.from( 1..10 )
* .skip( 6 ).collect() == [ 7, 8, 9, 10 ]
*
*
* @param n the number of elements to skip
* @return A new {@code Stream} wrapping a {@link SkipIterator}
*/
public Stream skip( int n ) {
return new Stream( new SkipIterator( iterator, n ) ) ;
}
/**
* Takes a {@code Closure} that returns a {@code Collection}. Each element
* in this {@code Collection} is passed on in turn, before the next element is
* fetched from upstream, and the Closure executed again.
*
*
* import groovy.stream.*
*
* assert Stream.from( 1..3 )
* .flatMap { [ it ] * it }
* .collect() == [ 1, 2, 2, 3, 3, 3 ]
*
*
* @param The type of the new Stream.
* @param map A single parameter closure to pass the element through,
* returning a new Collection of elements to iterate.
* @return A new {@code Stream} wrapping a {@link FlatMapIterator}
*/
public Stream flatMap( Closure extends Collection> map ) {
return new Stream( new FlatMapIterator( iterator, map, false ) ) ;
}
/**
* Takes a {@link Function} that returns a {@code Collection}. Each element
* in this {@code Collection} is passed on in turn, before the next element is
* fetched from upstream, and the {@link Function} is executed again.
*
* @param The type of the new Stream.
* @param map A single {@link Function} to pass the element through, returning a
* new Collection of elements to iterate.
* @return A new {@code Stream} wrapping a {@link FlatMapIteratorForFunction}
*/
public Stream flatMap( Function> map ) {
return new Stream( new FlatMapIteratorForFunction( iterator, map ) ) ;
}
/**
* Takes a {@code Closure} that returns a {@code Collection}. Each element
* in this {@code Collection} is passed on in turn, before the next element is
* fetched from upstream, and the Closure executed again.
*
*
* import groovy.stream.*
*
* assert Stream.from( 1..3 )
* .flatMapWithIndex { it, index -> [ it ] * index }
* .collect() == [ 2, 3, 3 ]
*
*
* @param The type of the new Stream.
* @param map A two parameter closure to pass the element and it's index through,
* returning a new Collection of elements to iterate.
* @return A new {@code Stream} wrapping a {@link FlatMapIterator}
*/
public Stream flatMapWithIndex( Closure extends Collection> map ) {
return new Stream( new FlatMapIterator( iterator, map, true ) ) ;
}
/**
* Takes an {@link IndexedFunction} that returns a {@code Collection}. Each element
* in this {@code Collection} is passed on in turn, before the next element is
* fetched from upstream, and the {@link IndexedFunction} is executed again.
*
* @param The type of the new Stream.
* @param map A single {@link IndexedFunction} to pass the element and its index through,
* returning a new Collection of elements to iterate.
* @return A new {@code Stream} wrapping a {@link FlatMapIteratorForIndexedFunction}
*/
public Stream flatMapWithIndex( IndexedFunction> map ) {
return new Stream( new FlatMapIteratorForIndexedFunction( iterator, map ) ) ;
}
/**
* Inspect every value in the {@code Stream} and pass it on unmodified.
*
*
* import groovy.stream.*
*
* def list = []
* assert Stream.from( 1..3 )
* .tap { list << it }
* .collect() == [ 1, 2, 3 ]
* assert list == [ 1, 2, 3 ]
*
*
* @param output The {@code Closure} to be called for every element
* @return A new {@code Stream} wrapping a {@link TapIterator}
*/
public Stream tap( Closure output ) { return tapEvery( 1, output ) ; }
/**
* Inspect every value in the {@code Stream} and pass it on.
*
* @see #tap(groovy.lang.Closure)
* @param output The {@code Function} to be called for every element
* @return A new {@code Stream} wrapping a {@link TapIteratorForFunction}
*/
public Stream tap( Function output ) { return tapEvery( 1, output ) ; }
/**
* Inspect the every nth value in the {@code Stream} and pass it on unmodified.
*
*
* import groovy.stream.*
*
* def list = []
* assert Stream.from( 1..3 )
* .tapEvery( 2 ) { list << it }
* .collect() == [ 1, 2, 3 ]
* assert list == [ 2 ]
*
*
* @param n the elements to inspect
* @param output The {@code Closure} to be called for every nth element
* @return A new {@code Stream} wrapping a {@link TapIterator}
*/
public Stream tapEvery( int n, Closure output ) {
return new Stream( new TapIterator( iterator, n, false, output ) ) ;
}
/**
* Inspect the every nth value in the {@code Stream} and pass it on.
*
* @see #tapEvery(int, groovy.lang.Closure)
* @param n the elements to inspect
* @param output The {@code Function} to be called for every nth element
* @return A new {@code Stream} wrapping a {@link TapIteratorForFunction}
*/
public Stream tapEvery( int n, Function output ) {
return new Stream( new TapIteratorForFunction( iterator, n, output ) ) ;
}
/**
* Inspect every value in the {@code Stream} with its {@code index} and pass it on unmodified.
*
*
* import groovy.stream.*
*
* def list = []
* assert Stream.from( 1..3 )
* .tapWithIndex { it, idx -> list << [ (it):idx ] }
* .collect() == [ 1, 2, 3 ]
* assert list == [ [ 1:0 ], [ 2:1 ], [ 3:2 ] ]
*
*
* @param output The closure to call for each element in the Stream.
* @return A new {@code Stream} wrapping a {@link TapIterator}
*/
public Stream tapWithIndex( Closure output ) { return tapEveryWithIndex( 1, output ) ; }
/**
* Inspect every value in the {@code Stream} with its {@code index} and pass it on unmodified.
*
* @see #tapWithIndex(groovy.lang.Closure)
* @param output The {@link IndexedFunction} to call for each element in the Stream.
* @return A new {@code Stream} wrapping a {@link TapIteratorForIndexedFunction}
*/
public Stream tapWithIndex( IndexedFunction output ) { return tapEveryWithIndex( 1, output ) ; }
/**
* Inspect the every nth value in the {@code Stream} with its index and pass it on unmodified.
*
*
* import groovy.stream.*
*
* def list = []
* assert Stream.from( 1..3 )
* .tapEveryWithIndex( 2 ) { it, index -> list << [ (it):index ] }
* .collect() == [ 1, 2, 3 ]
* assert list == [ [2:1] ]
*
*
* @param n the elements to inspect
* @param output The {@link Closure} to be called for every nth element
* @return A new {@code Stream} wrapping a {@link TapIterator}
*/
public Stream tapEveryWithIndex( int n, Closure output ) {
return new Stream( new TapIterator( iterator, n, true, output ) ) ;
}
/**
* Inspect the every nth value in the {@code Stream} with its index and pass it on unmodified.
*
* @see #tapEveryWithIndex(int, groovy.lang.Closure)
* @param n the elements to inspect
* @param output The {@link IndexedFunction} to be called for every nth element
* @return A new {@code Stream} wrapping a {@link TapIteratorForIndexedFunction}
*/
public Stream tapEveryWithIndex( int n, IndexedFunction output ) {
return new Stream( new TapIteratorForIndexedFunction( iterator, n, output ) ) ;
}
/**
* Maps the elements of a {@code Stream} to a new value as they are requested. Each
* element is passed in to a one arg closure, and the result of the {@link Closure}
* is returned as the next element in the {@code Stream}. The element is also
* set as the delegate of the {@link Closure}, so you can access map entries
* by name.
*
*
* import groovy.stream.*
*
* assert Stream.from( x:1..3, y:'a'..'c' )
* .map { "$x:$y" }
* .collect() == [ "1:a", "1:b", "1:c",
* "2:a", "2:b", "2:c",
* "3:a", "3:b", "3:c" ]
*
*
* @param The type of the new Stream.
* @param map The transforming Closure.
* @return A new {@code Stream} wrapping a {@link TransformingIterator}
*/
public Stream map( Closure map ) {
return new Stream( new TransformingIterator( iterator, map, false ) ) ;
}
/**
* Maps the elements of a {@code Stream} to a new value as they are requested. Each
* element is passed in to a {@link Function}, the result of which is returned as the
* next element in the {@code Stream}.
*
* @see #map(groovy.lang.Closure)
* @param The type of the new Stream.
* @param map The transforming {@link Function}.
* @return A new {@code Stream} wrapping a {@link TransformingIteratorForFunction}
*/
public Stream map( Function map ) {
return new Stream( new TransformingIteratorForFunction( iterator, map ) ) ;
}
/**
* Maps the elements of a {@code Stream} to a new value as they are requested. Each
* element plus an index is passed in to a two arg closure, and the result of
* the {@link Closure} is returned as the next element in the {@code Stream}.
* The element is also set as the delegate of the {@link Closure}, so you can
* access map entries by name.
*
*
* import groovy.stream.*
*
* assert Stream.from( x:1..3, y:'a'..'c' )
* .mapWithIndex { it, idx -> "${x}:${it.y}:${idx}" }
* .collect() == [ "1:a:0", "1:b:1", "1:c:2",
* "2:a:3", "2:b:4", "2:c:5",
* "3:a:6", "3:b:7", "3:c:8" ]
*
*
* @param The type of the new Stream.
* @param map The transforming Closure.
* @return A new {@code Stream} wrapping a {@link TransformingIterator}
*/
public Stream mapWithIndex( Closure map ) {
return new Stream( new TransformingIterator( iterator, map, true ) ) ;
}
/**
* Maps the elements of a {@code Stream} to a new value as they are requested. Each
* element plus an index is passed in to an {@link IndexedFunction}, and the result of
* this is returned as the next element in the {@code Stream}.
*
* @see #mapWithIndex(groovy.lang.Closure)
* @param The type of the new Stream.
* @param map The transforming {@link IndexedFunction}.
* @return A new {@code Stream} wrapping a {@link TransformingIteratorForIndexedFunction}
*/
public Stream mapWithIndex( IndexedFunction map ) {
return new Stream( new TransformingIteratorForIndexedFunction( iterator, map ) ) ;
}
/**
* When the {@link Closure} predicate returns {@code true}, the stream is stopped.
*
*
* import groovy.stream.*
*
* assert Stream.from( 1..5 )
* .until { it > 3 }
* .collect() == [ 1, 2, 3 ]
*
*
* @param predicate The {@link Closure} that stops the Stream when it returns {@code true}.
* @return A new {@code Stream} wrapping an {@link UntilIterator}
*/
public Stream until( Closure predicate ) {
return new Stream( new UntilIterator( iterator, predicate, false ) ) ;
}
/**
* When the {@link Predicate} returns {@code true}, the stream is stopped.
*
* @see #until(groovy.lang.Closure)
* @param predicate The {@link Predicate} that stops the Stream when it returns {@code true}.
* @return A new {@code Stream} wrapping an {@link UntilIteratorForPredicate}
*/
public Stream until( Predicate predicate ) {
return new Stream( new UntilIteratorForPredicate( iterator, predicate ) ) ;
}
/**
* Calls the {@link Closure} predicate with the current element and the index in the stream.
* When the predicate returns {@code true}, the stream is stopped.
*
*
* import groovy.stream.*
*
* assert Stream.from( 1..5 )
* .untilWithIndex { it, index -> index == 2 }
* .collect() == [ 1, 2 ]
*
*
* @param predicate The {@link Closure} that stops the Stream when it returns {@code true}.
* @return A new {@code Stream} wrapping an {@link UntilIterator}
*/
public Stream untilWithIndex( Closure predicate ) {
return new Stream( new UntilIterator( iterator, predicate, true ) ) ;
}
/**
* Calls the {@link IndexedPredicate} with the current element and the index in the stream.
* When the predicate returns {@code true}, the stream is stopped.
*
* @param predicate The {@link IndexedPredicate} that stops the Stream when it returns {@code true}.
* @return A new {@code Stream} wrapping an {@link UntilIteratorForIndexedPredicate}
*/
public Stream untilWithIndex( IndexedPredicate predicate ) {
return new Stream( new UntilIteratorForIndexedPredicate( iterator, predicate ) ) ;
}
/**
* Groups a the elements of a {@code Stream} into groups of length {@code size}.
*
*
* import groovy.stream.*
*
* assert Stream.from( 1..9 )
* .collate( 4 )
* .collect() == [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9 ] ]
*
*
* @param size the size of each collated group
* @return A new {@code Stream} wrapping an {@link CollatingIterator}
*/
public Stream> collate( int size ) { return collate( size, size, true ) ; }
/**
* Groups a the elements of a {@code Stream} into groups of length {@code size}.
*
*
* import groovy.stream.*
*
* assert Stream.from( 1..9 )
* .collate( 4, false )
* .collect() == [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ] ]
*
*
* @param size the size of each collated group
* @param keepRemainder Should any remaining objects be returned at the end
* @return A new {@code Stream} wrapping an {@link CollatingIterator}
*/
public Stream> collate( int size, boolean keepRemainder ) { return collate( size, size, keepRemainder ) ; }
/**
* Groups a the elements of a {@code Stream} into groups of length {@code size}
* using a step-size of {@code step}.
*
*
* import groovy.stream.*
*
* assert Stream.from( 1..9 )
* .collate( 4, 1 )
* .collect() == [ [ 1, 2, 3, 4 ],
* [ 2, 3, 4, 5 ],
* [ 3, 4, 5, 6 ],
* [ 4, 5, 6, 7 ],
* [ 5, 6, 7, 8 ],
* [ 6, 7, 8, 9 ],
* [ 7, 8, 9 ],
* [ 8, 9 ],
* [ 9 ] ]
*
*
* @param size the size of each collated group
* @param step How many to increment the window by each turn
* @return A new {@code Stream} wrapping an {@link CollatingIterator}
*/
public Stream> collate( int size, int step ) { return collate( size, step, true ) ; }
/**
* Groups a the elements of a {@code Stream} into groups of length {@code size}
* using a step-size of {@code step}.
*
*
* import groovy.stream.*
*
* assert Stream.from( 1..9 )
* .collate( 4, 1, false )
* .collect() == [ [ 1, 2, 3, 4 ],
* [ 2, 3, 4, 5 ],
* [ 3, 4, 5, 6 ],
* [ 4, 5, 6, 7 ],
* [ 5, 6, 7, 8 ],
* [ 6, 7, 8, 9 ] ]
*
*
* @param size the size of each collated group
* @param step How many to increment the window by each turn
* @param keepRemainder Should any remaining objects be returned at the end
* @return A new {@code Stream} wrapping an {@link CollatingIterator}
*/
public Stream> collate( int size, int step, boolean keepRemainder ) {
return new Stream>( new CollatingIterator( this.iterator, size, step, keepRemainder ) ) ;
}
/**
* Takes another {@code Iterator} or {@code Stream} and calls the two arg {@code Closure}
* to zip the two together.
*
*
* import groovy.stream.*
*
* def numbers = Stream.from 1..3
* def letters = Stream.from 'a'..'d'
*
* assert numbers.zip( letters ) { n, l -> "$n:$l" }
* .collect() == [ "1:a", "2:b", "3:c" ]
*
*
* @param The type of the secondary {@link Iterator}.
* @param The type of the new {@link Iterator}.
* @param other The other {@link Iterator}
* @param map The 2 arg {@link Closure} to call with each next element from the Stream
* @return A new {@code Stream} wrapping a {@link ZipIterator}
*/
public Stream zip( Iterator other, Closure map ) {
return new Stream( new ZipIterator( this.iterator, other, false, map ) ) ;
}
public Stream zip( Iterable other, Closure map ) {
return new Stream( new ZipIterator( this.iterator, other.iterator(), false, map ) ) ;
}
/**
* Takes another {@code Iterator} or {@code Stream} and calls the two arg {@code Function2}
* to zip the two together.
*
* @see #zip(java.util.Iterator, groovy.lang.Closure)
* @param The type of the secondary {@link Iterator}.
* @param The type of the new {@link Iterator}.
* @param other The other {@link Iterator}
* @param map The 2 arg {@link Function2} to call with each next element from the Stream
* @return A new {@code Stream} wrapping a {@link ZipIteratorForFunction}
*/
public Stream zip( Iterator other, Function2 map ) {
return new Stream( new ZipIteratorForFunction( this.iterator, other, map ) ) ;
}
public Stream zip( Iterable other, Function2 map ) {
return new Stream( new ZipIteratorForFunction( this.iterator, other.iterator(), map ) ) ;
}
/**
* Takes another {@code Iterator} or {@code Stream} and calls the three arg {@code Closure}
* to zip the two together along with the current index.
*
*
* import groovy.stream.*
*
* def numbers = Stream.from 1..3
* def letters = Stream.from 'a'..'d'
*
* assert numbers.zipWithIndex( letters ) { n, l, i -> "$n:$l:$i" }
* .collect() == [ "1:a:0", "2:b:1", "3:c:2" ]
*
*
* @param The type of the secondary {@link Iterator}.
* @param The type of the new {@link Iterator}.
* @param other The other {@link Iterator}
* @param map The 3 arg {@link Closure} to call with each next element from the Stream and the
* current stream index
* @return A new {@code Stream} wrapping a {@link ZipIterator}
*/
public Stream zipWithIndex( Iterator other, Closure map ) {
return new Stream( new ZipIterator( this.iterator, other, true, map ) ) ;
}
public Stream zipWithIndex( Iterable other, Closure map ) {
return new Stream( new ZipIterator( this.iterator, other.iterator(), true, map ) ) ;
}
/**
* Takes another {@code Iterator} or {@code Stream} and calls the three arg {@link IndexedFunction2}
* to zip the two together along with the current index.
*
* @see #zipWithIndex(java.util.Iterator, groovy.lang.Closure)
* @param The type of the secondary {@link Iterator}.
* @param The type of the new {@link Iterator}.
* @param other The other {@link Iterator}
* @param map The 3 arg {@link IndexedFunction2} to call with each next element from the Stream and the
* current stream index
* @return A new {@code Stream} wrapping a {@link ZipIteratorForIndexedFunction}
*/
public Stream zipWithIndex( Iterator other, IndexedFunction2 map ) {
return new Stream( new ZipIteratorForIndexedFunction( this.iterator, other, map ) ) ;
}
public Stream zipWithIndex( Iterable other, IndexedFunction2 map ) {
return new Stream( new ZipIteratorForIndexedFunction( this.iterator, other.iterator(), map ) ) ;
}
/**
* When this stream completes, repeat it's output endlessly.
*
*
* import groovy.stream.*
*
* def numbers = Stream.from 1..3
*
* // We will just take the first 12 elements of this infinite stream
* assert numbers.repeat().take(12).collect() == [1,2,3,1,2,3,1,2,3,1,2,3]
*
*
* @return A new {@code Stream} wrapping a {@link RepeatingIterator}
*/
public Stream repeat() {
return new Stream(new RepeatingIterator(this.iterator));
}
/**
* This stream will repeat count
times.
*
* If count is 0
, the Stream will be empty. If 1
, no repetition will be performed.
*
*
* import groovy.stream.*
*
* def numbers = Stream.from(['alice', 'bob'])
*
* assert numbers.repeat(2).collect() == ['alice','bob','alice','bob']
*
*
* @param count The number of times to repeat the element in this Stream once it is exhausted.
* @return A new {@code Stream} wrapping a {@link RepeatingIterator}
*/
public Stream repeat(int count) {
return new Stream(new RepeatingIterator(this.iterator, count));
}
/**
* Limits the {@code Stream} to {@code n} elements.
*
*
* import groovy.stream.*
*
* assert Stream.from( 1..9 )
* .take( 3 )
* .collect() == [ 1, 2, 3 ]
*
*
* @param n The number of element to limit the {@code Stream} to.
* @return A new {@code Stream} wrapping a {@link LimitedIterator}
*/
public Stream take( int n ) {
return new Stream( new LimitedIterator( this.iterator, n ) ) ;
}
/**
* Construct a {@code Stream} from a {@link Map} of Iterables.
*
*
* import groovy.stream.*
*
* assert Stream.from( a:1..3, b:'a'..'c' )
* .collect() == [ [ a:1, b:'a' ],
* [ a:1, b:'b' ],
* [ a:1, b:'c' ],
* [ a:2, b:'a' ],
* [ a:2, b:'b' ],
* [ a:2, b:'c' ],
* [ a:3, b:'a' ],
* [ a:3, b:'b' ],
* [ a:3, b:'c' ] ]
*
*
* @param They type of the Map keys.
* @param The type of the Iterable value.
* @param map The map of Iterables.
* @return A new {@code Stream} wrapping a {@link MapIterator}.
*/
public static Stream
© 2015 - 2025 Weber Informatics LLC | Privacy Policy