I understood that when I run an Akka Stream graph, it will materialised the most right component.
But doing this:
Source.range(1,100).to(Sink.reduce((a,b) -> a+b)).run(materializer);
Will materialise NotUsed though the most left component is a sink that returns integer.
However, doing the same with runWith works fine:
Source.range(1, 100).runWith(Sink.reduce((a, b) -> a + b), materializer)
.thenAccept(value -> LOGGER.info("The final value is {}", value));
What is it that I didn't understand well about the run method?
By default, to retains the materialized value of the stream operator that calls that method. In your example...
Source.range(1, 100).to(Sink.reduce((a, b) -> a + b)).run(materializer);
// ^
...the Source invokes to, so calling run on the stream returns the materialized value of the Source, which is NotUsed, and ignores the materialized value of the Sink. This is the equivalent of running source.toMat(sink, Keep.left()).
In contrast, calling runWith instead of to and run in this case returns the materialized value of the Sink, because runWith is a shorthand way of using Keep.right().
From the documentation:
final CompletionStage<Integer> sum = tweets.map(t -> 1).runWith(sumSink, system);
runWith() is a convenience method that automatically ignores the materialized value of any other operators except those appended by the runWith() itself. In the above example it translates to using Keep.right as the combiner for materialized values.
Related
/Hi everyone! I am really struggeling with this methode. I have to find out the question with the highest score and have to filter it with minimumviews.
public Stream<Question> stream() {
Stream<Question> questionStream = Arrays.stream(items);
questionStream.forEach(System.out::println);
return questionStream;
}
public Optional<Question> findHighestScoringQuestionWith(int minimumViews){
return stream()
.sorted(Comparator.comparing(Question::getScore))
.filter(x -> x.getViewCount() >= minimumViews)
.findFirst();
}
//I would be very grateful if someone can help me with this issue. I thank you all in advance.
//My exception
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
at java.base/java.util.stream.AbstractPipeline.<init>(AbstractPipeline.java:203)
at java.base/java.util.stream.ReferencePipeline.<init>(ReferencePipeline.java:94)
at java.base/java.util.stream.ReferencePipeline$StatefulOp.<init>(ReferencePipeline.java:725)
at java.base/java.util.stream.SortedOps$OfRef.<init>(SortedOps.java:126)
at java.base/java.util.stream.SortedOps.makeRef(SortedOps.java:63)
at java.base/java.util.stream.ReferencePipeline.sorted(ReferencePipeline.java:463)
at stackoverflow.Data.sortedStream(Data.java:156)
at stackoverflow.Main.main(Main.java:14)
Stream operations are divided into intermediate and terminal operations, and are combined to form stream pipelines. A stream pipeline consists of a source (such as a Collection, an array, a generator function, or an I/O channel); followed by zero or more intermediate operations such as Stream.filter or Stream.map; and a terminal operation such as Stream.forEach or Stream.reduce.
- Package Summary for java.util.stream
Stream.forEach is a terminal operation, meaning that it completes a stream pipeline. The whole stream pipeline is evaluated when a terminal operation is invoked, it has been operated upon, as stated in the exception.
If you want to have multiple terminal operations, you need to set up multiple stream pipelines.
To perform some operation on the data mid stream, you can use Stream.peek:
public Stream<Question> stream() {
Stream<Question> questionStream = Arrays.stream(items);
return questionStream.peek(System.out::println); // <-
}
public Optional<Question> findHighestScoringQuestionWith(int minimumViews){
return stream()
.sorted(Comparator.comparing(Question::getScore))
.filter(x -> x.getViewCount() >= minimumViews)
.findFirst();
}
This will print out all items in the stream, but only once a terminal operation is called and the stream is evaluated. In your case, that terminal operation is Stream.findFirst in the findHighestScoringQuestionWith method.
Streams are one-shot objects, you can't use them more than once.
The problem is that you are calling questionStream.forEach in the stream() method, so it is already used up before you return. If you really want to print out the contents, then you could do Arrays.asList(items).forEach(System.out::println);
I have a Flux of strings. For each string, I have to make a remote call. But the problem is that the method that makes the remote call actually returns a Mono of the response (obviously since corresponding to a single request, there'll be a single response).
What should be the correct pattern to handle such cases? One solution I can think of is to make serial (or parallel) calls for the stream elements and reduce the responses to a single one and return.
Here's the code:
fluxObj.flatmap(a -> makeRemoteCall(a)//converts the Mono of the response to a Flux).reduce(...)
I am being unable to wrap my head around inside the flatmap.The makeRemoteCall method returns a Mono. But the flatmap returns a Flux of the response. First, why is this happening? Second, does it mean that the returned Flux contains a single response object (that was returned in the Mono)?
If the mapper Function returns a Mono, then it means that there will be (at most) one derived value for each source element in the Flux.
Having the Function return:
an empty Mono (eg. Mono.empty()) for a given value means that this source value is "ignored"
a valued Mono (like in your example) means that this source value is asynchronously mapped to another specific value
a Flux with several derived values for a given value means that this source value is asynchronously mapped to several values
For instance, given the following flatMap:
Flux.just("A", "B")
.flatMap(v -> Mono.just("value" + v))
Subscribing to the above Flux<String> and printing the emitted elements would yield:
valueA
valueB
Another fun example: with delays, one can get out of order results. Like this:
Flux.just(300, 100)
.flatMap(delay -> Mono.delay(Duration.ofMillis(delay))
.thenReturn(delay + "ms")
)
would result in a Flux<String> that yields:
100ms
300ms
If you see documentation flatMap, you can found answers to your questions:
Transform the elements emitted by this Flux asynchronously into Publishers, then flatten these inner publishers into a single Flux, sequentially and preserving order using concatenation.
Long story in short,
#Test
public void testFlux() {
Flux<String> oneString = Flux.just("1");
oneString
.flatMap(s -> testMono(s))
.collectList()
.subscribe(integers -> System.out.println("elements:" + integers));
}
private Mono<Integer> testMono(String s) {
return Mono.just(Integer.valueOf(s + "0"));
}
mapper - s -> testMono(s) where testMono(s) is Publisher (in your case makeRemoteCall(a)), it transforms a type of my oneString to Integer.
I collected Flux result to List, and printed it. Console output:
elements:[10]
It means result Flux after flatMap operator contains just one element.
I am generating a power set (Set<Set<Integer>>) from an original set (Set<Integer>).
i.e. {1, 2, 3} -> { {}, {1}, {2}, {3}, {1,2}, {2,3}, {1,3}, {1,2,3} }
Then I am using an isClique(Set<Integer>) method that returns a boolean if the given set is a clique in the adjacency matrix I am using.
I want to use a java stream to parallelize this operation and return the largest subset that is also a clique.
I am thinking something like this, but every variation I come up with causes a variety of compilation errors.
Optional result = powerSet.stream().parallel().
filter(e ->{return(isClique(e));}).
collect(Collectors.maxBy(Comparator Set<Integer> comparator));
I either get:
MaxClique.java:86: error: incompatible types: Stream<Set<Integer>> cannot be converted to Set<Integer>
currentMax = powerSet.stream().parallel().filter(e -> { return (isClique(e));});//.collect(Collectors.maxBy(Comparator <Set<Integer>> comparator));
or something related to the comparator (which I'm not sure I'm doing correctly).
Please advise, thanks.
You have some syntax problems. But beside that, you can compute the same optional using:
Optional<Set<Integer>> result = powerSet.stream().parallel()
.filter(e -> isClique(e))
.collect(
Collectors.maxBy(
(set1, set2) -> Integer.compare(set1.size(), set2.size())
)
);
This is filtering based on your condition, then pulling the max value based on a comparator that compares set sizes.
Your major issue is using the wrong syntax for the comparator. Rather, you'd want something along the lines of:
Optional<Set<Integer>> resultSet =
powerSet.stream()
.parallel()
.filter(e -> isClique(e))
.max(Comparator.comparingInt(Set::size));
Note the use of the max method as opposed to the maxBy, this is because the maxBy is typically used as a downstream collector. in fact, the real motivation for it to exist is to be used as a downstream collector.
Also, note the use of Optional<Set<Integer>> being the receiver type as opposed to Optional as in your example code snippet. The latter is a raw type and you should avoid to use them unless there is no choice.
Lastly, but not least, if you haven't already done so then I'd suggest you try executing the code sequentially first and if you think you can benefit from parallel streams then you can proceed with the current approach.
Am trying to print the values from the .stream() via two .filter(). But the value is not printing.
With one .filter() am able to print the values.
Please find my code below.
listProducts.stream()
.flatMap(listproducts -> listproducts.getProductAttr().stream())
.flatMap(attr ->attr.getProductAttrValue().stream())
.filter(av -> av.getLabel().equalsIgnoreCase("source"))
.filter(av -> av.getLabel().equalsIgnoreCase("description"))
.forEachOrdered(av -> System.out.println(av.getValue()));
No element of your Stream can pass the Predicates passed to both of your filter calls, since av.getLabel() can't be equal to both "source" and "description" at the same time.
You can use a single filter instead:
.filter(av -> av.getLabel().equalsIgnoreCase("source") ||
av.getLabel().equalsIgnoreCase("description"))
.filter(av -> Pattern.matches("(?i)source|description", av.getLabel()))
You are keeping only "source" strings (ignoring the case) after the first filtering.
The second filter kicks away the previous results.
You should build a composite boolean expression within one filter.
I suggest writing that simple regexp.*
*It can be improved by precompiling the pattern as #daniu's suggested.
I'm wondering if I can add an operation to a stream, based off of some sort of condition set outside of the stream. For example, I want to add a limit operation to the stream if my limit variable is not equal to -1.
My code currently looks like this, but I have yet to see other examples of streams being used this way, where a Stream object is reassigned to the result of an intermediate operation applied on itself:
// Do some stream stuff
stream = stream.filter(e -> e.getTimestamp() < max);
// Limit the stream
if (limit != -1) {
stream = stream.limit(limit);
}
// Collect stream to list
stream.collect(Collectors.toList());
As stated in this stackoverflow post, the filter isn't actually applied until a terminal operation is called. Since I'm reassigning the value of stream before a terminal operation is called, is the above code still a proper way to use Java 8 streams?
There is no semantic difference between a chained series of invocations and a series of invocations storing the intermediate return values. Thus, the following code fragments are equivalent:
a = object.foo();
b = a.bar();
c = b.baz();
and
c = object.foo().bar().baz();
In either case, each method is invoked on the result of the previous invocation. But in the latter case, the intermediate results are not stored but lost on the next invocation. In the case of the stream API, the intermediate results must not be used after you have called the next method on it, thus chaining is the natural way of using stream as it intrinsically ensures that you don’t invoke more than one method on a returned reference.
Still, it is not wrong to store the reference to a stream as long as you obey the contract of not using a returned reference more than once. By using it they way as in your question, i.e. overwriting the variable with the result of the next invocation, you also ensure that you don’t invoke more than one method on a returned reference, thus, it’s a correct usage. Of course, this only works with intermediate results of the same type, so when you are using map or flatMap, getting a stream of a different reference type, you can’t overwrite the local variable. Then you have to be careful to not use the old local variable again, but, as said, as long as you are not using it after the next invocation, there is nothing wrong with the intermediate storage.
Sometimes, you have to store it, e.g.
try(Stream<String> stream = Files.lines(Paths.get("myFile.txt"))) {
stream.filter(s -> !s.isEmpty()).forEach(System.out::println);
}
Note that the code is equivalent to the following alternatives:
try(Stream<String> stream = Files.lines(Paths.get("myFile.txt")).filter(s->!s.isEmpty())) {
stream.forEach(System.out::println);
}
and
try(Stream<String> srcStream = Files.lines(Paths.get("myFile.txt"))) {
Stream<String> tmp = srcStream.filter(s -> !s.isEmpty());
// must not be use variable srcStream here:
tmp.forEach(System.out::println);
}
They are equivalent because forEach is always invoked on the result of filter which is always invoked on the result of Files.lines and it doesn’t matter on which result the final close() operation is invoked as closing affects the entire stream pipeline.
To put it in one sentence, the way you use it, is correct.
I even prefer to do it that way, as not chaining a limit operation when you don’t want to apply a limit is the cleanest way of expression your intent. It’s also worth noting that the suggested alternatives may work in a lot of cases, but they are not semantically equivalent:
.limit(condition? aLimit: Long.MAX_VALUE)
assumes that the maximum number of elements, you can ever encounter, is Long.MAX_VALUE but streams can have more elements than that, they even might be infinite.
.limit(condition? aLimit: list.size())
when the stream source is list, is breaking the lazy evaluation of a stream. In principle, a mutable stream source might legally get arbitrarily changed up to the point when the terminal action is commenced. The result will reflect all modifications made up to this point. When you add an intermediate operation incorporating list.size(), i.e. the actual size of the list at this point, subsequent modifications applied to the collection between this point and the terminal operation may turn this value to have a different meaning than the intended “actually no limit” semantic.
Compare with “Non Interference” section of the API documentation:
For well-behaved stream sources, the source can be modified before the terminal operation commences and those modifications will be reflected in the covered elements. For example, consider the following code:
List<String> l = new ArrayList(Arrays.asList("one", "two"));
Stream<String> sl = l.stream();
l.add("three");
String s = sl.collect(joining(" "));
First a list is created consisting of two strings: "one"; and "two". Then a stream is created from that list. Next the list is modified by adding a third string: "three". Finally the elements of the stream are collected and joined together. Since the list was modified before the terminal collect operation commenced the result will be a string of "one two three".
Of course, this is a rare corner case as normally, a programmer will formulate an entire stream pipeline without modifying the source collection in between. Still, the different semantic remains and it might turn into a very hard to find bug when you once enter such a corner case.
Further, since they are not equivalent, the stream API will never recognize these values as “actually no limit”. Even specifying Long.MAX_VALUE implies that the stream implementation has to track the number of processed elements to ensure that the limit has been obeyed. Thus, not adding a limit operation can have a significant performance advantage over adding a limit with a number that the programmer expects to never be exceeded.
There is two ways you can do this
// Do some stream stuff
List<E> results = list.stream()
.filter(e -> e.getTimestamp() < max);
.limit(limit > 0 ? limit : list.size())
.collect(Collectors.toList());
OR
// Do some stream stuff
stream = stream.filter(e -> e.getTimestamp() < max);
// Limit the stream
if (limit != -1) {
stream = stream.limit(limit);
}
// Collect stream to list
List<E> results = stream.collect(Collectors.toList());
As this is functional programming you should always work on the result of each function. You should specifically avoid modifying anything in this style of programming and treat everything as if it was immutable if possible.
Since I'm reassigning the value of stream before a terminal operation is called, is the above code still a proper way to use Java 8 streams?
It should work, however it reads as a mix of imperative and functional coding. I suggest writing it as a fixed stream as per my first answer.
I think your first line needs to be:
stream = stream.filter(e -> e.getTimestamp() < max);
so that your using the stream returned by filter in subsequent operations rather than the original stream.
I known it is a bit too late, but I had the same question myself and didn't find the satisfying answer, however, inspired by this question and answers I came to the following solution:
return Stream.of( ///< wrap target stream in other stream ;)
/*do regular stream stuff*/
stream.filter(e -> e.getTimestamp() < max)
).flatMap(s -> limit != -1 ? s.limit(limit) : s) ///< apply limit only if necessary and unwrap stream of stream to "normal" stream
.collect(Collectors.toList()) ///< do final stuff