annimon / lightweight-stream-api Goto Github PK
View Code? Open in Web Editor NEWStream API from Java 8 rewritten on iterators for Java 7 and below
License: Apache License 2.0
Stream API from Java 8 rewritten on iterators for Java 7 and below
License: Apache License 2.0
I created this function in my project:
public static <T> int contains(List<T> list, Predicate<T> condition) {
if (list.isEmpty()) return -1;
for (int i=0; i < list.size(); i++) {
if (condition.test(list.get(i))) return i;
}
return -1;
}
I use this function for example as
protected int getPosition(String name) {
return contains(getNames(), name::equalsIgnoreCase);
}
Where getNames()
returns List<String>
What about adding something like this function as terminal operation for Stream
?
Also contains(T element)
will be useful
Maybe naming this feature as indexOf
instead of contains
will be better for describing its returning value
Thanks for great library!
Can add some functions like onErrorResumeNext and onErrorReturn at Rxjava?
resumeNext() -> onErrorResumeNext(final Func1<Throwable, ? extends Observable<? extends T>> resumeFunction)
and
resume() -> onErrorReturn(Func1<Throwable, ? extends T> resumeFunction)
eg:
private static <T> Exceptional<T> resumeNext(Exceptional<T> exceptional,
Func1<Throwable, Exceptional<T>> f) {
return Optional.ofNullable(exceptional.getException())
.map(f::call)
.orElse(exceptional);
}
private static <T> Exceptional<T> resume(Exceptional<T> exceptional,
Func1<Throwable, T> f) {
return Optional.ofNullable(exceptional.getException())
.map(t -> Exceptional.of(() -> f.call(t)))
.orElse(exceptional);
}
public static void test() {
resume(
Exceptional.of(() -> IOUtils.read(inputStream))
.map(Observable::just),
Observable::error)
.get()
...
}
Thanks!
line 795 suppilers instead of suppliers.
line 804 the same problem.
In my opinion it would be cool if you add a CI server integration to this repo. So tests can be run automatically with PRs.
Currently, ifPresent
returns void
and breaks chaining. For convenience sake I'll add these methods:
Optional executeIfPresent(Consumer c)
Optional executeIfAbsent(Runnable r)
Optional.ofNullable(result)
.executeIfAbsent(() -> error("Empty result"))
.or(() -> Optional.ofNullable(anotherResult))
.executeIfAbsent(() -> error("Still no result"))
.executeIfPresent(this::processResult);
Hi
It would be nice if the removeIf method will be implemented.
Good job
Applying concat()
on stream that is result of filter()
produces incorrect result.
Below is new test that reproduces the issue:
@Test
public void testConcatOfFilter() {
final PrintConsumer consumer = new PrintConsumer();
final Stream<Integer> first = Stream.ofRange(0, 5)
.filter(it -> true);
final Stream<Integer> second = Stream.ofRange(5, 10)
.filter(it -> true);
Stream.concat(first, second)
.forEach(consumer);
assertEquals("0123456789", consumer.toString());
}
org.junit.ComparisonFailure:
Expected :0123456789
Actual :13null56789
The issue is that hasNext()
implementation in filter()
is not idempotent - when called multiple times, value is skipped.
In concat()
implementation the (filter()
hasNext()
) is called once in hasNext()
and once in next()
, which would be ok, if filter()
hasNext()
did not have the side-effect.
In all projects where I use Stream API I have Hamcrest OptionalMatcher.java
It would be nice to have such Hamcrest support (and not only for Hamcrest) for testing directly in the library.
Tricky part is where to put such support as having it in core library artifact might be confusing. On the other hand this approach is used by some other libraries, i.e. RxJava and its TestObserver
Other option is to create additional artifact only for testing.
What do you think?
Any chances for groupingBy function ?)
Hi,
You added ComparatorCompat recently. I appreciate it.
I have two questions about it.
First, (Even though it is very trival) I wondered why it is not Comparators because I felt Comparators is more natural.
Second, ComparatorCompat has only static methods and I can't use method chaining like comparing().reversed().thenComparing(). Could you provide ComparatorCompat as instantiate-able class? For example, I tried to inherit Comparator to declare Comparators like this: BattleShipPark@5de8328
Thanks.
public IntStream distinct() {
return boxed().distinct().mapToInt(identity());
}
Not sure whether it makes sense but found when backporting some code. Your IntGenerator is not autocloseable.
I have these calls in a stream because I need to map a value based on the index and the value:
.indexed()
.map(p -> getPredecessorForRow(p.getFirst()).pathTo(p.getFirst(), p.getSecond()))
which is very cumbersome having to deal with IntPair and not very readable.
If you look at Sequence in Kotlin (which is the equivalent of a Stream) it has Indexed versions for filter, map, forEach, and reduce (aka fold). It would be nice to have these in this library.
These would depend on some new interfaces that take the index as a parameter along with the value.
With a mapIndexed function the above becomes:
.mapIndexed((i, value) -> getPredecessorForRow(i).pathTo(i, value))
FYI, while looking at Sequence in Kotlin feel free to look for other functions that would be good candidates there for inclusion.
Although its implementation is not complicated, I'd like to check it exists or not.
Thanks.
Android Studio 2.1
Java 7 compiler or java 8 compiler
gradle 2.10 or 2.13
build.gradle file:
//////////////////////////////////
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "com.bignerdranch.android.splineinterpolation"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
jackOptions {
enabled false
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'me.tatarka:gradle-retrolambda:3.2.5'
}
}
// Required because retrolambda is on maven central
repositories {
mavenCentral()
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:design:23.3.0'
compile 'org.apache.commons:commons-math3:+'
compile 'org.apache.commons:commons-lang3:+'
compile 'org.rajawali3d:rajawali:1.+@aar'
compile 'com.annimon:stream:1.0.9'
compile 'org.jetbrains:annotations:15.0'
}
apply plugin: 'me.tatarka.retrolambda'
//Its only experimental. If remove this error is same
retrolambda {
jdk "/usr/lib/jvm/java-8-oracle"
oldJdk "/usr/lib/jvm/java-7-oracle"
javaVersion JavaVersion.VERSION_1_7
defaultMethods false
incremental true
}
//////////////////////////////////
In Android Studio messages:
Error:Error converting bytecode to dex:
Cause: Dex cannot parse version 52 byte code.
This is caused by library dependencies that have been compiled using Java 8 or above.
If you are using the 'java' gradle plugin in a library submodule add
targetCompatibility = '1.7'
sourceCompatibility = '1.7'
to that submodule's build.gradle file.
Error:Execution failed for task ':app:transformClassesWithDexForDebug'.
com.android.build.api.transform.TransformException: java.lang.RuntimeException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: com.android.ide.common.process.ProcessException: Return code 1 for dex process
For example
Creates a safe {@code DoubleConsumer}.
will be
Creates a safe {@link DoubleConsumer}.
Then DoubleConsumer
will be clickable for navigation
Nested Stream.of and Stream.zip creates Error
While below produces error such as the data type of value2 in stream2 is WRONG:
`Stream stream2 = Stream.zip(Stream.range(0, 4).flatMap(i -> Stream.of(new ChatAnswer())), Stream.of(ansTypes), (value1, value2) -> { value1.setAnswerType(value2); return value1; });
Stream.zip(stream1, stream2, (value1, value2) -> {value1.getAnswers().add(value2); return value1;}).forEach(chatQuestion -> chatQuestions.add(chatQuestion));`
Solution:
`Stream str1 = Stream.range(0, 4).flatMap(i -> Stream.of(new ChatAnswer()));
Stream dd = Stream.of(ansTypes);
Stream stream2 = Stream.zip(str1, dd, (value1, value2) -> { value1.setAnswerType(value2); return value1; });
Stream.zip(stream1, stream2, (value1, value2) -> {value1.getAnswers().add(value2); return value1;}).forEach(chatQuestion -> chatQuestions.add(chatQuestion));`
By separating into smaller streams helps as it indicates what the stream returns as its generic type.
For now, Im going to use Rx as the replacement.
Hi,
I'd like to know where Comparator.reversed() is.
Thanks!
Why you added IntStream, but not DoubleStream?
Because it is a lightweight library without all features of original Stream API?
I know this isn't standard Java 8, but many functional languages that provide reduce can do at least this. What do you think about modifying reduce from:
T reduce(T identity, BiFunction<T, T, T> accumulator)
to:
<R> R reduce(R identity, BiFunction<R, T, R> accumulator)
?
This would allow for code like this:
String string123 = Stream.of("1", "2", "3")
.reduce(new StringBuilder(), StringBuilder::append) // returns the StringBuilder
.toString();
You can even go as far as:
<R> R reduce(R identity, BiFunction<? super R, ? super T, ? extends R> accumulator)
to be even more general.
Like this rxjava operator: http://reactivex.io/RxJava/javadoc/rx/Observable.html#takeUntil(rx.Observable)
UPDATE
I meant this method: http://reactivex.io/RxJava/javadoc/rx/Observable.html#takeUntil(rx.functions.Func1)
While using standard list/set/map, LSA gets iterator:
Stream.of(list);
////
public static <T> Stream<T> of(Iterable<? extends T> iterable) {
return new Stream<T>(iterable);
}
private Stream(Iterable<? extends T> iterable) {
this(iterable.iterator());
}
So, this code:
stream = Stream.of(list);
list.add(...);
stream.forEach(...);
equals to:
Iterator iterator = list.iterator();
list.add(...);
and cause java.util.ConcurrentModificationException:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:886)
at java.util.ArrayList$Itr.next(ArrayList.java:836)
at com.annimon.stream.Stream$5.hasNext(Stream.java:116)
All we need is implement new Iterator based on list/set/map.
In my issue about adding takeUntil I noted thar your implementation did not include my code for setting next to null to avoid leaking memory. But looking at some of the other methods have similar problems.
It occurs to me that perhaps this could be handled at the LsaExtIterator level. After the call to nextIteration you can just check if hasNext is false and if so set next to null.
It would be wonderful if this library had javadocs for each of its methods. It would probably be possible to just copy the Java 8 Stream docs over where applicable.
I can no longer use Stream.of(...some Iterable...) without getting many false errors of this kind:
Both:
List<? extends T> in Stream and
Iterable<? extends T> in Stream match
I can confirm I am only ever importing the annimon Stream classes----there are no duplicate imports from the Java API. If I step into the source, I do indeed see methods with the same erasure:
public static <T> Stream<T> of(final List<? extends T> list)
public static <T> Stream<T> of(Iterable<? extends T> iterable)
Casting my objects resolves the error, but leads to un-human-parsable code and lengthy calls to Stream.of
. I should also note this has only been an issue since the latest release. Clearly, the issue is that List also implements Iterable, so it can't decide which method I intended.
Where are implementations for IntFunction, LongFunction and DoubleFunction?
Example for IntFunction:
public static <T, R> IntFunction<T, R> safe(
final ThrowableFunction<? super T, ? extends R, Throwable> throwableFunction,
final R resultIfFailed) {
return new IntFunction<R>() {
@Override
public R apply(int value) {
try {
return throwableFunction.apply(value);
} catch (Throwable throwable) {
return resultIfFailed;
}
}
};
}
Will you add them?
Maybe I don't understand something, but
return Optional.of((Quest) oin.readObject()).filter(q -> q.status != null).orElse(fromJSON(file));
is not the same that
Quest q = (Quest) oin.readObject();
return q.status == null ? fromJSON(file) : q;
Because the first example causes recursion in my code, and the second does not. All other code is the same.
Where is my mistake?
It would be easier to add to this project if it had something like Gradle or Maven for handling building and testing. I may be confused because I don't understand what the nbproject folder is (though it appears to be an IDE/machine specific folder that should not be under version control).
With build.gradle
configuration
...
compile "com.annimon:stream:1.1.0"
testCompile "com.annimon:stream-test:1.0.1"
...
the build will fail with:
Error:Conflict with dependency 'com.annimon:stream'. Resolved versions for app (1.1.0) and test app (1.0.9) differ. See http://g.co/androidstudio/app-test-app-conflict for details.
Also please consider to always use the same version for stream-test
module and the corresponding stream
module to avoid any confusion.
I thought about two enhancements
.collect(Collectors.toList());
- this is so common that maybe adding dedicated method would be justifiable I mean stream.toList()
instead of stream..collect(Collectors.toList());
Stream.ofNullable()
// PS. This project is awesome. Our Android project codebase looks much cleaner now.
Why? I want to flatten double[][]
, but I can't
Stream.of(dm).flatMap(DoubleStream::of)
says about incompatible types, because DoubleStream extends Object, not Stream
And Stream.of
can't process primitive types - result is still double[]
I think this problem was fixed in 1.1.4
How to flatten multidimensional arrays of primitives?
Maybe I missed something?
The Java 8 Stream API supports specifying custom Stream cleanup logic after you are finished with the Stream by utilizing the AutoCloseable along with an onClose(Runnable)
intermediate operation. https://docs.oracle.com/javase/8/docs/api/java/util/stream/BaseStream.html#onClose-java.lang.Runnable-
It would be nice to support this functionality in order to provide custom data source cleanup logic to run when a Stream has been consumed.
Hi,
I am trying to do something like this:
Map<String, Station> map = mStationList.stream().collect(Collectors.toMap(Station::getKey, item -> item));
But toMap method cannot be resolved. Is this possible?
Thank you,
Igor
Why are these classes duplicated in root and iterator
packages?
LazyIterator
LsaExtIterator
LsaIterator
PrimitiveExtIterator
PrimitiveIterator
Please explain. Maybe I missed something in this code magic
First, thanks for great library!
I want to change method name of "ofRange()" to "range()" because following reasons:
range()
class method on IntStream and LongStream, not ofRange()
.First of all I love this port , it is very useful.
Thank you for that !
There are a lot more operators for stream in Java 8 stream API , one of the most usefull is the "sum"
https://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.html#sum--
Any chance you will implement it any time soon ?
Is there a road map for your port anywhere ?
I embedded your code into my Eclipse project because I want to make some changes you might not like. Eclipse mentioned that in some places the Diamond operator could be used. Not sure what JVM you are targeting.
We're having issues with filter
+ mapToObj
. This test:
@Test public void testStream() {
List<Integer> items = newArrayList(0, 1, 2, 3, 4);
List<String> list = range(0, items.size())
.filter(i -> items.get(i) % 2 == 0)
.mapToObj(String::valueOf)
.collect(toList());
assertThat(list).containsOnly("0", "2", "4");
}
is failing with the error.
java.util.NoSuchElementException
at com.annimon.stream.LsaIterator.next(LsaIterator.java:20)
at com.annimon.stream.Stream.collect(Stream.java:1596)
at StreamTest.testStream(StreamTest.java:24)
It looks like a map on a filtered IntStream
does some weird things, the output was never as expected with the few test cases I've played with.
@Test
public void testStreamSortedLazy() {
int[] expected = { -7, 0, 3, 6, 9, 19 };
List<Integer> input = new ArrayList<Integer>(6);
input.addAll(Arrays.asList(6, 3, 9));
IntStream stream = Stream.of(input).mapToInt(Functions.toInt()).sorted();
input.addAll(Arrays.asList(0, -7, 19));
assertThat(stream.toArray(), is(expected));
}
Produces one value -7
instead of six values.
Proguard failed obfuscation with library 1.0.4+ but all is ok for 1.0.3.
From proguard docs:
Warning: can't find enclosing class/method If there are unresolved references to classes that are defined inside methods in your input, once more, your compiled class files are most likely inconsistent. Possibly, some class file didn't get recompiled properly, or some class file was left behind after its source file was removed. Try removing all compiled class files and rebuilding your project.
Failure log:
Warning: com.annimon.stream.Collectors$1$1: can't find enclosing method 'com.annimon.stream.function.Supplier supplier()' in program class com.annimon.stream.Collectors$1
Warning: com.annimon.stream.Collectors$1$2: can't find enclosing method 'com.annimon.stream.function.BiConsumer accumulator()' in program class com.annimon.stream.Collectors$1
Warning: com.annimon.stream.Collectors$2$1: can't find enclosing method 'com.annimon.stream.function.Supplier supplier()' in program class com.annimon.stream.Collectors$2
Warning: com.annimon.stream.Collectors$2$2: can't find enclosing method 'com.annimon.stream.function.BiConsumer accumulator()' in program class com.annimon.stream.Collectors$2
Warning: com.annimon.stream.Collectors$3$1: can't find enclosing method 'com.annimon.stream.function.Supplier supplier()' in program class com.annimon.stream.Collectors$3
Warning: com.annimon.stream.Collectors$3$2: can't find referenced field 'java.lang.CharSequence val$delimiter' in program class com.annimon.stream.Collectors$3
Warning: com.annimon.stream.Collectors$3$2: can't find referenced field 'java.lang.CharSequence val$prefix' in program class com.annimon.stream.Collectors$3
Warning: com.annimon.stream.Collectors$3$2: can't find enclosing method 'com.annimon.stream.function.BiConsumer accumulator()' in program class com.annimon.stream.Collectors$3
Warning: com.annimon.stream.Collectors$3$3: can't find referenced field 'java.lang.String val$emptyValue' in program class com.annimon.stream.Collectors$3
Warning: com.annimon.stream.Collectors$3$3: can't find referenced field 'java.lang.CharSequence val$suffix' in program class com.annimon.stream.Collectors$3
Warning: com.annimon.stream.Collectors$3$3: can't find enclosing method 'com.annimon.stream.function.Function finisher()' in program class com.annimon.stream.Collectors$3
Warning: com.annimon.stream.Collectors$4$1: can't find enclosing method 'com.annimon.stream.function.Supplier supplier()' in program class com.annimon.stream.Collectors$4
Warning: com.annimon.stream.Collectors$4$2: can't find referenced field 'com.annimon.stream.function.Function val$mapper' in program class com.annimon.stream.Collectors$4
Warning: com.annimon.stream.Collectors$4$2: can't find enclosing method 'com.annimon.stream.function.BiConsumer accumulator()' in program class com.annimon.stream.Collectors$4
Warning: com.annimon.stream.Collectors$4$3: can't find enclosing method 'com.annimon.stream.function.Function finisher()' in program class com.annimon.stream.Collectors$4
Warning: com.annimon.stream.Collectors$5$1: can't find enclosing method 'com.annimon.stream.function.Supplier supplier()' in program class com.annimon.stream.Collectors$5
Warning: com.annimon.stream.Collectors$5$2: can't find enclosing method 'com.annimon.stream.function.BiConsumer accumulator()' in program class com.annimon.stream.Collectors$5
Warning: com.annimon.stream.Collectors$5$3: can't find enclosing method 'com.annimon.stream.function.Function finisher()' in program class com.annimon.stream.Collectors$5
Warning: com.annimon.stream.Collectors$7$1: can't find referenced field 'com.annimon.stream.function.Function val$classifier' in program class com.annimon.stream.Collectors$7
Warning: com.annimon.stream.Collectors$7$1: can't find referenced field 'com.annimon.stream.Collector val$downstream' in program class com.annimon.stream.Collectors$7
Warning: com.annimon.stream.Collectors$7$1: can't find enclosing method 'com.annimon.stream.function.BiConsumer accumulator()' in program class com.annimon.stream.Collectors$7
Warning: com.annimon.stream.Collectors$7$2: can't find referenced field 'com.annimon.stream.Collector val$downstream' in program class com.annimon.stream.Collectors$7
Warning: com.annimon.stream.Collectors$7$2: can't find enclosing method 'com.annimon.stream.function.Function finisher()' in program class com.annimon.stream.Collectors$7
Warning: com.annimon.stream.function.BiFunction$Util$2: can't find enclosing method 'com.annimon.stream.function.BiFunction minBy(java.util.Comparator)' in program class com.annimon.stream.function.BiFunction$Util
Warning: com.annimon.stream.function.BiFunction$Util$3: can't find enclosing method 'com.annimon.stream.function.BiFunction maxBy(java.util.Comparator)' in program class com.annimon.stream.function.BiFunction$Util
I want to use zip() which combines pair of items from two stream.
I think it is must-have feature, but it is not included in Java 8/9 API (added in Java 8 draft and removed later).
Note that there is util library for Java-8-native Stream API which contains zip(): https://github.com/poetix/protonpack
Where should I place this function?
Test Code:
@Test
public void testZip() {
Stream<Integer> shorter = Stream.rangeClosed(1, 5);
Stream<Integer> longer = Stream.rangeClosed(1, 10);
List<Integer> zipped = Stream.zip(shorter, longer, new BiFunction<Integer, Integer, Integer>() {
@Override
public Integer apply(Integer value1, Integer value2) {
return value1 + value2;
}
}).collect(Collectors.toList());
assertEquals(Arrays.asList(2, 4, 6, 8, 10), zipped);
}
Thanks!
RxJava has scan operators which would be nice in the stream api.
http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Observable.html#scan(io.reactivex.functions.BiFunction)
http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Observable.html#scan(R,%20io.reactivex.functions.BiFunction)
It recursively applies an accumulator function to each item in the stream like reduce except that instead of giving you only the final value, it gives you a stream containing the seed and all values along the way.
This code
Stream.iterate(0, i -> i+1).filter(i -> i == 0).findFirst()
Will loop forever instead of returning the first element
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.