I've created a small library called StreamX, which acts like a type-safe, index-aware zipper to enable parallel streaming over multiple lists. It supports functional operations like forEach, map, filter, reduce, etc.
It provides full type safety across 1 to 20 zipped lists.
To avoid exposing generics to the user, my library uses a StreamX entry point with an internal factory method fromLists(...), which dynamically returns the correct StreamX1, StreamX2, ..., StreamX20 depending on the number and type of input lists.
Each version supports chained operations like:
StreamX.addElements("Rectangle 1", "Rectangle 2", "Rectangle 3").addElements(1.8, 1.7, 1.6).addElements(3, 3, 4).addList(units).forEach((i, name, width, height, unit) ->System.out.println(i + ": " + name + " area = " + (width * height) + " " + unit));
This works well in inline usage, and thanks to overloading, users don't need to specify generics when chaining.
The Problem:
If a user wants to store the result of the stream before using it, the only option is:
StreamX4<String, Double, Integer, String> stream = StreamX.addElements(...);
But I want to keep the API clean and not force users to write out these long generic types, especially if the stream is only stored for delayed usage.
Using var works in local scope:
var stream = StreamX.addElements(...);
But not for class fields.
My Question:
Is there any trick or design pattern in Java that would allow me to hide or wrap the generics so the user can store a stream without explicitly writing the generic types — while still keeping full type safety and IDE support?
Any feedback on this problem or the overall library design is also welcome.
The project is open-source and available here: https://github.com/mekkiseghier/streamx
var
isn't supported for fields. You have no choice but to use the full generic types.