Enhancing Java Stream API

Overview

StreamEx 0.7.3

Enhancing Java Stream API.

Maven Central Javadocs Build Status Coverage Status

This library defines four classes: StreamEx, IntStreamEx, LongStreamEx, DoubleStreamEx which are fully compatible with Java 8 stream classes and provide many additional useful methods. Also EntryStream class is provided which represents the stream of map entries and provides additional functionality for this case. Finally there are some new useful collectors defined in MoreCollectors class as well as primitive collectors concept.

Full API documentation is available here.

Take a look at the Cheatsheet for brief introduction to the StreamEx!

Before updating StreamEx check the migration notes and full list of changes.

StreamEx library main points are following:

  • Shorter and convenient ways to do the common tasks.
  • Better interoperability with older code.
  • 100% compatibility with original JDK streams.
  • Friendliness for parallel processing: any new feature takes the advantage on parallel streams as much as possible.
  • Performance and minimal overhead. If StreamEx allows to solve the task using less code compared to standard Stream, it should not be significantly slower than the standard way (and sometimes it's even faster).

Examples

Collector shortcut methods (toList, toSet, groupingBy, joining, etc.)

List<String> userNames = StreamEx.of(users).map(User::getName).toList();
Map<Role, List<User>> role2users = StreamEx.of(users).groupingBy(User::getRole);
StreamEx.of(1,2,3).joining("; "); // "1; 2; 3"

Selecting stream elements of specific type

public List<Element> elementsOf(NodeList nodeList) {
    return IntStreamEx.range(nodeList.getLength())
      .mapToObj(nodeList::item).select(Element.class).toList();
}

Adding elements to stream

public List<String> getDropDownOptions() {
    return StreamEx.of(users).map(User::getName).prepend("(none)").toList();
}

public int[] addValue(int[] arr, int value) {
    return IntStreamEx.of(arr).append(value).toArray();
}

Removing unwanted elements and using the stream as Iterable:

public void copyNonEmptyLines(Reader reader, Writer writer) throws IOException {
    for(String line : StreamEx.ofLines(reader).remove(String::isEmpty)) {
        writer.write(line);
        writer.write(System.lineSeparator());
    }
}

Selecting map keys by value predicate:

Map<String, Role> nameToRole;

public Set<String> getEnabledRoleNames() {
    return StreamEx.ofKeys(nameToRole, Role::isEnabled).toSet();
}

Operating on key-value pairs:

public Map<String, List<String>> invert(Map<String, List<String>> map) {
    return EntryStream.of(map).flatMapValues(List::stream).invert().grouping();
}

public Map<String, String> stringMap(Map<Object, Object> map) {
    return EntryStream.of(map).mapKeys(String::valueOf)
        .mapValues(String::valueOf).toMap();
}

Map<String, Group> nameToGroup;

public Map<String, List<User>> getGroupMembers(Collection<String> groupNames) {
    return StreamEx.of(groupNames).mapToEntry(nameToGroup::get)
        .nonNullValues().mapValues(Group::getMembers).toMap();
}

Pairwise differences:

DoubleStreamEx.of(input).pairMap((a, b) -> b-a).toArray();

Support of byte/char/short/float types:

short[] multiply(short[] src, short multiplier) {
    return IntStreamEx.of(src).map(x -> x*multiplier).toShortArray(); 
}

Define custom lazy intermediate operation recursively:

static <T> StreamEx<T> scanLeft(StreamEx<T> input, BinaryOperator<T> operator) {
        return input.headTail((head, tail) -> scanLeft(tail.mapFirst(cur -> operator.apply(head, cur)), operator)
                .prepend(head));
}

And more!

License

This project is licensed under Apache License, version 2.0

Installation

Releases are available in Maven Central

Before updating StreamEx check the migration notes and full list of changes.

Maven

Add this snippet to the pom.xml dependencies section:

<dependency>
  <groupId>one.util</groupId>
  <artifactId>streamex</artifactId>
  <version>0.7.3</version>
</dependency>

Gradle

Add this snippet to the build.gradle dependencies section:

implementation 'one.util:streamex:0.7.3'

Pull requests are welcome.

Comments
  • How to do a zip operation on 2 EntryStreams?

    How to do a zip operation on 2 EntryStreams?

    hi, I have the following pseudo code that I want to rewrite in Stream:

    Object[][] array = new Object[allRows.size()][allCols.size()];
    for (int i = 0; i < allRows.size(); i++) {
        for (int j = 0; j < allCols.size(); j++) {
            xxx code;
            array[i,j] = xxx();
        }
    }
    

    The 2 indexes i and j must be used in the loop。

    The way I thought of doing it was to replace the 2-fold for loop with zip and iterate over the elements with index by way of EntryStream.of(allRows), but I found that the zip method is not supported by EntryStream, but is supported by the normal StreamEx class, so how do I do it by way of StreamEx? How can I achieve my requirement by means of StreamEx?

    opened by asasas234 12
  • Collapse not working

    Collapse not working

    I didn't found where it came from but the following code does not work:

    streamEx
        .sorted()
        .collapse(C::isNested,C::merge)
        .collect(toList());
        ...
        //items are not collapsed
    
        public static final boolean isNested(T a, T b) {
            return a.isParent(b) || b.isParent(a);
        };
    
        public static final T merge(T a, T b) {
            return a.isParent(b) ? a : b;
        };
    

    "POJO" is working :

    List<T> tmp = 
        stream
            .sorted()
            .collect(toList());
    Iterator<T> it = tmp.iterator();
    T curr, last;
    curr = last = null;
    while (it.hasNext()) {
        T oldLast = last;
        last = curr;
        curr = it.next();
        if (last != null && last.isParent(curr)) {
            it.remove();
            curr = last;
            last = oldLast;
        }
    }
    tmp.stream().collect(toList());
    //items are sorted
    
    invalid 
    opened by GrmpCerber 11
  • Re-implement Stream.skip to have reasonable parallel behavior

    Re-implement Stream.skip to have reasonable parallel behavior

    Currently, something like StreamEx.ofLines(...).skip(1).parallel().... doesn't do anything reasonable or useful. Instead of skipping the file's header, it skips a random line in the file. I think it should be possible to change its behavior to actually skip the first item if the source stream is ordered.

    opened by almson 9
  • limitSort()

    limitSort()

    Please consider adding a method called limitSort(long max, ...) with all of the flavors sorted(). This method will return a stream which has up to max elements. Passing Long.MAX_VALUE to max causes the limitSort() to behave the same as sorted(). Passing a lower value of max causes the "highest" elements to be discarded.

    For example, if I need to look at the 10 oldest files, then I could do something like...

    StreamEx stream;

    stream. limitSort(10, File::lastModified). ...

    One could implement the same logic with the following...

    stream. sorted(File::lastModified). limit(10). ...

    However, this pattern will hold all of the File objects in memory and sort them. Ouch! Whereas, limitSort() only needs to hold up to 10 (in this case) File objects in memory.

    Instead of implementing limitSort(), StreamEx could see a sorted() followed by a limit() and then merge the two operators into 1.

    opened by numeralnathan 8
  • Zip Streams

    Zip Streams

    Please add a method of the signature: EntryStream<K, V> EntryStream.zip(Stream keys, Stream values). This will allow for zipping two streams together. See this Stack Overflow question for more details.

    http://stackoverflow.com/questions/17640754/zipping-streams-using-jdk8-with-lambda-java-util-stream-streams-zip

    enhancement 
    opened by numeralnathan 8
  • configured automated releases

    configured automated releases

    Adds a GH workflow for triggering a release on demand. Adds JReleaser for creating a Git releases.

    Requires the following repository secrets:

    • SONATYPE_USERNAME: username required for publication to OSSRH
    • SONATYPE_PASSWORD: password required for publication to OSSRH
    • GPG_PASSPHRASE: GPG passphrase
    • GPG_PRIVATE_KEY: ASCII armored GPG secret key
    opened by aalmiray 7
  • Add present() method to filter and extract Optional values

    Add present() method to filter and extract Optional values

    I find myself doing this a lot when working with streams of optionals:

    someStreamOfOptionals
        .filter(Optional::isPresent)
        .map(Optional::get)
        ...
    

    This boilerplate seems common enough that it would be convenient to have a present() method:

    someStreamOfOptionals
        .present()
        ...
    

    Thoughts?

    opened by stickfigure 7
  • multi-release-jar file link broken in maven repository after version 0.7.0

    multi-release-jar file link broken in maven repository after version 0.7.0

    ivy resolver fails to find multi-release-jar file:

    [NOT FOUND ] one.util#streamex;0.7.3!streamex.multi-release-jar ==== central: tried https://repo1.maven.org/maven2/one/util/streamex/0.7.3/streamex-0.7.3.multi-release-jar

    the link to the multi release jar file is broken on mvnrepository.com: https://mvnrepository.com/artifact/one.util/streamex/0.7.3 -> https://repo1.maven.org/maven2/one/util/streamex/0.7.3/streamex-0.7.3.multi-release-jar

    the other, non-multi-release jar files are present, however, as can be seen here: https://repo1.maven.org/maven2/one/util/streamex/0.7.3/

    opened by ayinger1 7
  • IllegalStateException on toList() call in parallel stream

    IllegalStateException on toList() call in parallel stream

    There seems to be a problem with toList() method available in for StreamEx streams when they are executed in parallel, collect(Collectors.toList()) works as expected at the same time.

    Environment: Java 8u171, StreamEx 0.6.7, JUnit 4.12 Test case: https://gist.github.com/KTannenberg/62817706c05037cc43f87f5bba1a6bea

    Stack trace:

    java.lang.IllegalStateException: size passed to Sink.begin exceeds array length
    	at java.util.stream.Nodes$SizedCollectorTask.begin(Nodes.java:1887)
    	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:480)
    	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    	at java.util.stream.Nodes$SizedCollectorTask.compute(Nodes.java:1878)
    	at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
    	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
    	at java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:401)
    	at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:734)
    	at java.util.stream.Nodes.collect(Nodes.java:325)
    	at java.util.stream.ReferencePipeline.evaluateToNode(ReferencePipeline.java:109)
    	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:540)
    	at java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
    	at java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:438)
    	at one.util.streamex.AbstractStreamEx.toArray(AbstractStreamEx.java:344)
    	at one.util.streamex.AbstractStreamEx.toList(AbstractStreamEx.java:1154)
    	at gist.stream.StreamExToListTest.testStreamExFailing(StreamExToListTest.java:48)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
    
    opened by KTannenberg 7
  • allow nulls in EntryStream.toMap() and similar

    allow nulls in EntryStream.toMap() and similar

    Hello, I understand the reason, but I think this is too limitating. Even when I'm dealing with parallel streams, I'm not sure it's useful: ConcurrentHashMap already throws NullPointerException if any key or value is null (by doc). When dealing with sequential streams instead, I see no straight way collecting to a null-tolerant map.

    So, I want to propose some solution:

    1. I'd prefer to have this limitation totally removed
    2. remove the limitation only for EntryStream.toCustomMap()
    3. create something like EntryStream.toNullTolerantMap()

    Thank you!

    opened by mmariotti 7
  • Add to readme all extra feature provided by streamex.

    Add to readme all extra feature provided by streamex.

    For example, I will need to "merge" two streams. Look to https://github.com/amaembo/streamex - nothing :(

    So I found out the operation name on Google ("zip"), in parallel I found several other libraries provide such functionality (protonpack, Lazy-Seq) and only after it in Eclipse I realized that such method is exists in StreamEx.

    opened by foal 7
  • Request for shorten variants EntryStream#mapKeysPartial, EntryStream#mapValuesPartial

    Request for shorten variants EntryStream#mapKeysPartial, EntryStream#mapValuesPartial

    There are a lot of useful methods already:

    • StreamEx#mapPartial
    • EntryStream#mapToKeyPartial
    • EntryStream#mapToValuePartial
    • EntryStream#mapKeyValuePartial

    Hovewer to exclude some cases to write sequential mapKeys().nonNullKeys() is should be great to use one method.

    Plus, these two methods will be consumers, not bi-consumers, allowing to use method references.

    Tagir, thanks a lot for you library!

    opened by SimSonic 0
  • Refactor code of WithFirstSpliterator

    Refactor code of WithFirstSpliterator

    Simplify the code of WithFirstSpliterator:

    • smaller methods
    • less overall LOC
    • replace manual thread lock management (via ReentrantLock) with more convenient synchronized blocks
    • inline accept method (as it is a one-liner) to improve readability

    Tests are keep passing, perfomance is the same (even a bit higher):

    Benchmark                                                  (N)   Mode  Cnt    Score    Error  Units
    withFirst.WithFirstBenchmark.parallelNew                100000  thrpt   25  729,474 ± 40,193  ops/s
    withFirst.WithFirstBenchmark.parallelOld                100000  thrpt   25  708,247 ± 22,885  ops/s
    withFirst.WithFirstBenchmark.parallelNewShortCircuit    100000  thrpt   25  651,792 ± 19,253  ops/s
    withFirst.WithFirstBenchmark.parallelOldShortCircuit    100000  thrpt   25  605,977 ±  4,831  ops/s
    withFirst.WithFirstBenchmark.sequentialNew              100000  thrpt   25  845,432 ±  4,031  ops/s
    withFirst.WithFirstBenchmark.sequentialOld              100000  thrpt   25  826,331 ±  3,419  ops/s
    withFirst.WithFirstBenchmark.sequentialNewShortCircuit  100000  thrpt   25  432,279 ± 29,359  ops/s
    withFirst.WithFirstBenchmark.sequentialOldShortCircuit  100000  thrpt   25  374,763 ± 27,017  ops/s
    

    WithFirstSpliteratorOld class and new @Deprecated methods & benchmarks are subject for removal upon merging this PR.

    opened by naftalmm 1
  • Please add toOptional and onlyElement collectors

    Please add toOptional and onlyElement collectors

    Hello,

    Please add two more collectors:

    • onlyElement if streams has exactly one element, return it; otherwise throw an exception

    • toOptional return Optional.empty is stream is empty, Optional.of(elem) if streams has exactly one element, and throw an exception otherwise

    Names taken from Guava's MoreCollectors.

    Alternative good choice for naming is single / singleO.

    Thanks!

    opened by trtrmitya 4
  • Provide version of AbstractStreamEx#indexOf which returns int

    Provide version of AbstractStreamEx#indexOf which returns int

    It's inconvenient to cast result of indexOf from long to int. I think developers usually work with streams which contains less than 2^31 elements. So it would be great to have a variant of this method which returns OptionalInt or even int as List::indexOf does.

    opened by chashnikov 3
Releases(streamex-0.8.1)
Owner
Tagir Valeev
Tagir Valeev
Stream utilities for Java 8

protonpack A small collection of Stream utilities for Java 8. Protonpack provides the following: takeWhile and takeUntil skipWhile and skipUntil zip a

Dominic Fox 464 Nov 8, 2022
Backport of Java 8's lambda expressions to Java 7, 6 and 5

Retrolambda: Use Lambdas on Java 7 Just as there was Retroweaver et al. for running Java 5 code with generics on Java 1.4, Retrolambda lets you run Ja

Esko Luontola 3.5k Dec 30, 2022
An advanced, but easy to use, platform for writing functional applications in Java 8.

Getting Cyclops X (10) The latest version is cyclops:10.4.0 Stackoverflow tag cyclops-react Documentation (work in progress for Cyclops X) Integration

AOL 1.3k Dec 29, 2022
Java 8 annotation processor and framework for deriving algebraic data types constructors, pattern-matching, folds, optics and typeclasses.

Derive4J: Java 8 annotation processor for deriving algebraic data types constructors, pattern matching and more! tl;dr Show me how to write, say, the

null 543 Nov 23, 2022
vʌvr (formerly called Javaslang) is a non-commercial, non-profit object-functional library that runs with Java 8+. It aims to reduce the lines of code and increase code quality.

Vavr is an object-functional language extension to Java 8, which aims to reduce the lines of code and increase code quality. It provides persistent co

vavr 5.1k Jan 3, 2023
Functional patterns for Java

λ Functional patterns for Java Table of Contents Background Installation Examples Semigroups Monoids Functors Bifunctors Profunctors Applicatives Mona

null 825 Dec 29, 2022
java port of Underscore.js

underscore-java Requirements Java 1.8 and later or Java 11. Installation Include the following in your pom.xml for Maven: <dependencies> <dependency

Valentyn Kolesnikov 411 Dec 6, 2022
A library that simplifies error handling for Functional Programming in Java

Faux Pas: Error handling in Functional Programming Faux pas noun, /fəʊ pɑː/: blunder; misstep, false step Faux Pas is a library that simplifies error

Zalando SE 114 Dec 5, 2022
RustScript is a functional scripting language with as much relation to Rust as Javascript has to Java.

RustScript RustScript is a scripting language as much relation to Rust as JavaScript has to Java I made this for a school project; it's meant to be im

Mikail Khan 25 Dec 24, 2022
Xposed module for enhancing Snapchat!

SnapTrap SnapTrap is a new Snapchat project that aims at bringing back some enhancing features to Snapchat with the use of the Xposed framework! Curre

Raven 29 Jan 2, 2023
Implementation of Enhancing cubes with models to describe multidimensional data.

Implementation of Enhancing cubes with models to describe multidimensional data.

Business Intelligence Group - University of Bologna 2 Dec 15, 2022
Querystream - Build JPA Criteria queries using a Stream-like API

QueryStream QueryStream allows you to perform JPA queries using a Stream-like API. Just like a Java 8 Stream, a QueryStream is built up in a pipeline,

null 11 Sep 24, 2022
Speedment is a Stream ORM Java Toolkit and Runtime

Java Stream ORM Speedment is an open source Java Stream ORM toolkit and runtime. The toolkit analyzes the metadata of an existing SQL database and aut

Speedment 2k Dec 21, 2022
Stream utilities for Java 8

protonpack A small collection of Stream utilities for Java 8. Protonpack provides the following: takeWhile and takeUntil skipWhile and skipUntil zip a

Dominic Fox 464 Nov 8, 2022
null 8 Dec 22, 2022
Stream Processing and Complex Event Processing Engine

Siddhi Core Libraries Siddhi is a cloud native Streaming and Complex Event Processing engine that understands Streaming SQL queries in order to captur

Siddhi - Cloud Native Stream Processor 1.4k Jan 6, 2023
Distributed Stream and Batch Processing

What is Jet Jet is an open-source, in-memory, distributed batch and stream processing engine. You can use it to process large volumes of real-time eve

hazelcast 1k Dec 31, 2022