How do I get the first element while continue streaming?
I have a stream of generic items. I'd like to print the class name of the first item + the toString()
of all the items.
If I had an Iterable, it would look like this:
Iterable<E> itemIter = ...;
boolean first = true;
for (E e : itemIter) {
if (first) {
first = false;
System.out.println(e.getClass().getSimpleName());
}
System.out.println(e);
}
Can I do this on a stream (Stream<T>
) with the stream API?
* Please note that it's a question about streams - not about iterators. I have a stream - not an iterator.
java java-stream
add a comment |
I have a stream of generic items. I'd like to print the class name of the first item + the toString()
of all the items.
If I had an Iterable, it would look like this:
Iterable<E> itemIter = ...;
boolean first = true;
for (E e : itemIter) {
if (first) {
first = false;
System.out.println(e.getClass().getSimpleName());
}
System.out.println(e);
}
Can I do this on a stream (Stream<T>
) with the stream API?
* Please note that it's a question about streams - not about iterators. I have a stream - not an iterator.
java java-stream
Please note that it's a question about streams - not about iterators. I have a stream - not an iterator.
– AlikElzin-kilaka
Mar 6 at 16:38
@AndrewTobilko - I don't have anIterable
- justStream
.
– AlikElzin-kilaka
Mar 6 at 19:29
Note that, if you have a stream, you can get an iterator (and, if you need one, also an iterable).
– Ilmari Karonen
Mar 7 at 8:47
add a comment |
I have a stream of generic items. I'd like to print the class name of the first item + the toString()
of all the items.
If I had an Iterable, it would look like this:
Iterable<E> itemIter = ...;
boolean first = true;
for (E e : itemIter) {
if (first) {
first = false;
System.out.println(e.getClass().getSimpleName());
}
System.out.println(e);
}
Can I do this on a stream (Stream<T>
) with the stream API?
* Please note that it's a question about streams - not about iterators. I have a stream - not an iterator.
java java-stream
I have a stream of generic items. I'd like to print the class name of the first item + the toString()
of all the items.
If I had an Iterable, it would look like this:
Iterable<E> itemIter = ...;
boolean first = true;
for (E e : itemIter) {
if (first) {
first = false;
System.out.println(e.getClass().getSimpleName());
}
System.out.println(e);
}
Can I do this on a stream (Stream<T>
) with the stream API?
* Please note that it's a question about streams - not about iterators. I have a stream - not an iterator.
java java-stream
java java-stream
edited Mar 7 at 9:49
Peter Mortensen
13.7k1986113
13.7k1986113
asked Mar 6 at 16:13
AlikElzin-kilakaAlikElzin-kilaka
18.8k15127206
18.8k15127206
Please note that it's a question about streams - not about iterators. I have a stream - not an iterator.
– AlikElzin-kilaka
Mar 6 at 16:38
@AndrewTobilko - I don't have anIterable
- justStream
.
– AlikElzin-kilaka
Mar 6 at 19:29
Note that, if you have a stream, you can get an iterator (and, if you need one, also an iterable).
– Ilmari Karonen
Mar 7 at 8:47
add a comment |
Please note that it's a question about streams - not about iterators. I have a stream - not an iterator.
– AlikElzin-kilaka
Mar 6 at 16:38
@AndrewTobilko - I don't have anIterable
- justStream
.
– AlikElzin-kilaka
Mar 6 at 19:29
Note that, if you have a stream, you can get an iterator (and, if you need one, also an iterable).
– Ilmari Karonen
Mar 7 at 8:47
Please note that it's a question about streams - not about iterators. I have a stream - not an iterator.
– AlikElzin-kilaka
Mar 6 at 16:38
Please note that it's a question about streams - not about iterators. I have a stream - not an iterator.
– AlikElzin-kilaka
Mar 6 at 16:38
@AndrewTobilko - I don't have an
Iterable
- just Stream
.– AlikElzin-kilaka
Mar 6 at 19:29
@AndrewTobilko - I don't have an
Iterable
- just Stream
.– AlikElzin-kilaka
Mar 6 at 19:29
Note that, if you have a stream, you can get an iterator (and, if you need one, also an iterable).
– Ilmari Karonen
Mar 7 at 8:47
Note that, if you have a stream, you can get an iterator (and, if you need one, also an iterable).
– Ilmari Karonen
Mar 7 at 8:47
add a comment |
7 Answers
7
active
oldest
votes
There is StreamEx
library that extends standard Java's Stream API. Using StreamEx.of(Iterator)
and peekFirst
:
StreamEx.of(itemIter.iterator())
.peekFirst(e -> System.out.println(e.getClass().getSimpleName()))
.forEach(System.out::println);
I wonder how they've implemented it, probably like one of the solutions already given here
– Lino
Mar 6 at 16:50
1
note that the method has some limitations (mentioned in the docs) and "exists mainly to support debugging".
– Andrew Tobilko
Mar 6 at 16:55
@Lino combine this answer which performs an action for the first element (but also consumes it) and this answer which will push the first item back after examining it and you have the necessary tools to construct such an operation.
– Holger
Mar 6 at 17:36
1
By the way, it’s preferable to useStreamEx.of(itemIter.spliterator())
, which may carry additional meta information to the stream (depending on the actualIterable
), potentially improving the performance.
– Holger
Mar 6 at 17:48
add a comment |
Native solution: Stream
in Java is not reusable. This means, that consuming stream can be done only once. If you get the first element from a stream, you can iterate over it one more time.
Workaround would be to create another stream same as the first one or getting the first item and then creating a stream, something like that:
Stream<E> stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED), false);
E firstElement = itemIter.next();
stream.foreach(...);
Edit
There is not really any way to "copy" a stream, you need to keep an iterator / collection. More about it here. When it comes to memory once stream is exhausted, it can be collected by garbage collector as there is no use from it. Stream itself does not take more space than iterator it originates from. Bear in mind, that streams can be potentially infinite. Elements currently manipulated are stored in memory.
1
@AlikElzin-kilaka please don't ask about the memory implications :) To me, it's obvious that none of Stream API solutions will outdo the simple loop approach mentioned by you (I'd go with a fori loop, though) in any way (performance, readability, maintenance). I honestly don't understand why you want streams here.
– Andrew Tobilko
Mar 6 at 16:44
Why do you assume that it's safe to cast:(List<E>) itemIter
?
– ernest_k
Mar 6 at 16:46
@ernest_k it doesn't really matter, I don't know the context (whatitemIter
really is). Let's just treat it as a pseudocode, that can be compiled, just to show the idea :)
– Andronicus
Mar 6 at 16:48
1
Well, it doesn’t even compile. Since objects are not anIterable
and anIterator
at the same time, you can’t cast it toList
and expect it to also have anext()
method. Once you fixed this, you don’t need the questionable type cast:E firstElement = itemIter.iterator().next(); Stream<E> stream = StreamSupport.stream(itemIter.spliterator(), false);
– Holger
Mar 6 at 17:44
add a comment |
If your starting point is a Stream
and you want to retain all of its properties and the laziness, the following solution will do:
public static <E> Stream<E> forFirst(Stream<E> stream, Consumer<? super E> c) {
boolean parallel = stream.isParallel();
Spliterator<E> sp = stream.spliterator();
return StreamSupport.stream(() -> {
if(sp.getExactSizeIfKnown() == 0) return sp;
Stream.Builder<E> b = Stream.builder();
if(!sp.tryAdvance(b.andThen(c))) return sp;
return Stream.concat(b.build(), StreamSupport.stream(sp, parallel)).spliterator();
}, sp.characteristics(), parallel);
}
E.g. when you use it with
List<String> list = new ArrayList<>(List.of("foo", "bar", "baz"));
Stream<String> stream = forFirst(
list.stream().filter(s -> s.startsWith("b")),
s -> System.out.println(s+" ("+s.getClass().getSimpleName()+')')
).map(String::toUpperCase);
list.add(1, "blah");
System.out.println(stream.collect(Collectors.joining(" | ")));
it will print
blah (String)
BLAH | BAR | BAZ
demonstrating that the processing will not start before commencing the terminal operation (collect
), hence reflecting the preceding update to the source List
.
can't tell why this is not a lot higher :|
– Eugene
Mar 7 at 8:31
@Eugene because posted two hours after the other answers and being placed at the end in the default ordering… nothing to worry about
– Holger
Mar 7 at 10:07
add a comment |
You can abuse reduction:
Stream<E> stream = ...;
System.out.println(stream
.reduce("",(out,e) ->
out + (out.isEmpty() ? e.getClass().getSimpleName()+"n" : "")
+ e));
add a comment |
One workaround is to do it like this -
import java.util.*;
import java.util.stream.Collectors;
public class MyClass {
static int i = 0;
static int getCounter(){
return i;
}
static void incrementCounter(){
i++;
}
public static void main(String args) {
List<String> list = Arrays.asList("A", "B", "C", "D", "E", "F", "G");
List<String> answer = list.stream().filter(str -> {if(getCounter()==0) {System.out.println("First Element : " + str);} incrementCounter(); return true;}).
collect(Collectors.toList());
System.out.println(answer);
}
}
Output :
First Element : A
[A, B, C, D, E, F, G]
1
requires you to always reset the value though, and will not work in a multi thread environment
– Lino
Mar 6 at 16:52
add a comment |
You could use peek
for that:
AtomicBoolean first = new AtomicBoolean(true);
StreamSupport.stream(itemIter.spliterator(), false)
.peek(e -> {
if(first.get()) {
System.out.println(e.getClass().getSimpleName());
first.set(false);
}
})
...
1
In that sense, I guess the code in question would be much better even if the iterable is defined. Keeping in mind there is nothing likeitemIter.stream()
available up front.
– Naman
Mar 6 at 16:36
@nullpointer you're right, I've edited my answer to use StreamSupport
– Lino
Mar 6 at 16:46
The action passed topeek
will be executed in the processing order which is not guaranteed to be the Stream’s encounter order.
– Holger
Mar 6 at 17:45
add a comment |
You can also use an boolean atomic reference:
AtomicReference<Boolean> first = new AtomicReference<Boolean>(Boolean.TRUE);
stream.forEach(e ->
System.out.println("First == " + first.getAndUpdate(b -> false)));
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55027574%2fhow-do-i-get-the-first-element-while-continue-streaming%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
7 Answers
7
active
oldest
votes
7 Answers
7
active
oldest
votes
active
oldest
votes
active
oldest
votes
There is StreamEx
library that extends standard Java's Stream API. Using StreamEx.of(Iterator)
and peekFirst
:
StreamEx.of(itemIter.iterator())
.peekFirst(e -> System.out.println(e.getClass().getSimpleName()))
.forEach(System.out::println);
I wonder how they've implemented it, probably like one of the solutions already given here
– Lino
Mar 6 at 16:50
1
note that the method has some limitations (mentioned in the docs) and "exists mainly to support debugging".
– Andrew Tobilko
Mar 6 at 16:55
@Lino combine this answer which performs an action for the first element (but also consumes it) and this answer which will push the first item back after examining it and you have the necessary tools to construct such an operation.
– Holger
Mar 6 at 17:36
1
By the way, it’s preferable to useStreamEx.of(itemIter.spliterator())
, which may carry additional meta information to the stream (depending on the actualIterable
), potentially improving the performance.
– Holger
Mar 6 at 17:48
add a comment |
There is StreamEx
library that extends standard Java's Stream API. Using StreamEx.of(Iterator)
and peekFirst
:
StreamEx.of(itemIter.iterator())
.peekFirst(e -> System.out.println(e.getClass().getSimpleName()))
.forEach(System.out::println);
I wonder how they've implemented it, probably like one of the solutions already given here
– Lino
Mar 6 at 16:50
1
note that the method has some limitations (mentioned in the docs) and "exists mainly to support debugging".
– Andrew Tobilko
Mar 6 at 16:55
@Lino combine this answer which performs an action for the first element (but also consumes it) and this answer which will push the first item back after examining it and you have the necessary tools to construct such an operation.
– Holger
Mar 6 at 17:36
1
By the way, it’s preferable to useStreamEx.of(itemIter.spliterator())
, which may carry additional meta information to the stream (depending on the actualIterable
), potentially improving the performance.
– Holger
Mar 6 at 17:48
add a comment |
There is StreamEx
library that extends standard Java's Stream API. Using StreamEx.of(Iterator)
and peekFirst
:
StreamEx.of(itemIter.iterator())
.peekFirst(e -> System.out.println(e.getClass().getSimpleName()))
.forEach(System.out::println);
There is StreamEx
library that extends standard Java's Stream API. Using StreamEx.of(Iterator)
and peekFirst
:
StreamEx.of(itemIter.iterator())
.peekFirst(e -> System.out.println(e.getClass().getSimpleName()))
.forEach(System.out::println);
edited Mar 6 at 16:50
Andrew Tobilko
28.2k104488
28.2k104488
answered Mar 6 at 16:31
RuslanRuslan
3,642827
3,642827
I wonder how they've implemented it, probably like one of the solutions already given here
– Lino
Mar 6 at 16:50
1
note that the method has some limitations (mentioned in the docs) and "exists mainly to support debugging".
– Andrew Tobilko
Mar 6 at 16:55
@Lino combine this answer which performs an action for the first element (but also consumes it) and this answer which will push the first item back after examining it and you have the necessary tools to construct such an operation.
– Holger
Mar 6 at 17:36
1
By the way, it’s preferable to useStreamEx.of(itemIter.spliterator())
, which may carry additional meta information to the stream (depending on the actualIterable
), potentially improving the performance.
– Holger
Mar 6 at 17:48
add a comment |
I wonder how they've implemented it, probably like one of the solutions already given here
– Lino
Mar 6 at 16:50
1
note that the method has some limitations (mentioned in the docs) and "exists mainly to support debugging".
– Andrew Tobilko
Mar 6 at 16:55
@Lino combine this answer which performs an action for the first element (but also consumes it) and this answer which will push the first item back after examining it and you have the necessary tools to construct such an operation.
– Holger
Mar 6 at 17:36
1
By the way, it’s preferable to useStreamEx.of(itemIter.spliterator())
, which may carry additional meta information to the stream (depending on the actualIterable
), potentially improving the performance.
– Holger
Mar 6 at 17:48
I wonder how they've implemented it, probably like one of the solutions already given here
– Lino
Mar 6 at 16:50
I wonder how they've implemented it, probably like one of the solutions already given here
– Lino
Mar 6 at 16:50
1
1
note that the method has some limitations (mentioned in the docs) and "exists mainly to support debugging".
– Andrew Tobilko
Mar 6 at 16:55
note that the method has some limitations (mentioned in the docs) and "exists mainly to support debugging".
– Andrew Tobilko
Mar 6 at 16:55
@Lino combine this answer which performs an action for the first element (but also consumes it) and this answer which will push the first item back after examining it and you have the necessary tools to construct such an operation.
– Holger
Mar 6 at 17:36
@Lino combine this answer which performs an action for the first element (but also consumes it) and this answer which will push the first item back after examining it and you have the necessary tools to construct such an operation.
– Holger
Mar 6 at 17:36
1
1
By the way, it’s preferable to use
StreamEx.of(itemIter.spliterator())
, which may carry additional meta information to the stream (depending on the actual Iterable
), potentially improving the performance.– Holger
Mar 6 at 17:48
By the way, it’s preferable to use
StreamEx.of(itemIter.spliterator())
, which may carry additional meta information to the stream (depending on the actual Iterable
), potentially improving the performance.– Holger
Mar 6 at 17:48
add a comment |
Native solution: Stream
in Java is not reusable. This means, that consuming stream can be done only once. If you get the first element from a stream, you can iterate over it one more time.
Workaround would be to create another stream same as the first one or getting the first item and then creating a stream, something like that:
Stream<E> stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED), false);
E firstElement = itemIter.next();
stream.foreach(...);
Edit
There is not really any way to "copy" a stream, you need to keep an iterator / collection. More about it here. When it comes to memory once stream is exhausted, it can be collected by garbage collector as there is no use from it. Stream itself does not take more space than iterator it originates from. Bear in mind, that streams can be potentially infinite. Elements currently manipulated are stored in memory.
1
@AlikElzin-kilaka please don't ask about the memory implications :) To me, it's obvious that none of Stream API solutions will outdo the simple loop approach mentioned by you (I'd go with a fori loop, though) in any way (performance, readability, maintenance). I honestly don't understand why you want streams here.
– Andrew Tobilko
Mar 6 at 16:44
Why do you assume that it's safe to cast:(List<E>) itemIter
?
– ernest_k
Mar 6 at 16:46
@ernest_k it doesn't really matter, I don't know the context (whatitemIter
really is). Let's just treat it as a pseudocode, that can be compiled, just to show the idea :)
– Andronicus
Mar 6 at 16:48
1
Well, it doesn’t even compile. Since objects are not anIterable
and anIterator
at the same time, you can’t cast it toList
and expect it to also have anext()
method. Once you fixed this, you don’t need the questionable type cast:E firstElement = itemIter.iterator().next(); Stream<E> stream = StreamSupport.stream(itemIter.spliterator(), false);
– Holger
Mar 6 at 17:44
add a comment |
Native solution: Stream
in Java is not reusable. This means, that consuming stream can be done only once. If you get the first element from a stream, you can iterate over it one more time.
Workaround would be to create another stream same as the first one or getting the first item and then creating a stream, something like that:
Stream<E> stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED), false);
E firstElement = itemIter.next();
stream.foreach(...);
Edit
There is not really any way to "copy" a stream, you need to keep an iterator / collection. More about it here. When it comes to memory once stream is exhausted, it can be collected by garbage collector as there is no use from it. Stream itself does not take more space than iterator it originates from. Bear in mind, that streams can be potentially infinite. Elements currently manipulated are stored in memory.
1
@AlikElzin-kilaka please don't ask about the memory implications :) To me, it's obvious that none of Stream API solutions will outdo the simple loop approach mentioned by you (I'd go with a fori loop, though) in any way (performance, readability, maintenance). I honestly don't understand why you want streams here.
– Andrew Tobilko
Mar 6 at 16:44
Why do you assume that it's safe to cast:(List<E>) itemIter
?
– ernest_k
Mar 6 at 16:46
@ernest_k it doesn't really matter, I don't know the context (whatitemIter
really is). Let's just treat it as a pseudocode, that can be compiled, just to show the idea :)
– Andronicus
Mar 6 at 16:48
1
Well, it doesn’t even compile. Since objects are not anIterable
and anIterator
at the same time, you can’t cast it toList
and expect it to also have anext()
method. Once you fixed this, you don’t need the questionable type cast:E firstElement = itemIter.iterator().next(); Stream<E> stream = StreamSupport.stream(itemIter.spliterator(), false);
– Holger
Mar 6 at 17:44
add a comment |
Native solution: Stream
in Java is not reusable. This means, that consuming stream can be done only once. If you get the first element from a stream, you can iterate over it one more time.
Workaround would be to create another stream same as the first one or getting the first item and then creating a stream, something like that:
Stream<E> stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED), false);
E firstElement = itemIter.next();
stream.foreach(...);
Edit
There is not really any way to "copy" a stream, you need to keep an iterator / collection. More about it here. When it comes to memory once stream is exhausted, it can be collected by garbage collector as there is no use from it. Stream itself does not take more space than iterator it originates from. Bear in mind, that streams can be potentially infinite. Elements currently manipulated are stored in memory.
Native solution: Stream
in Java is not reusable. This means, that consuming stream can be done only once. If you get the first element from a stream, you can iterate over it one more time.
Workaround would be to create another stream same as the first one or getting the first item and then creating a stream, something like that:
Stream<E> stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED), false);
E firstElement = itemIter.next();
stream.foreach(...);
Edit
There is not really any way to "copy" a stream, you need to keep an iterator / collection. More about it here. When it comes to memory once stream is exhausted, it can be collected by garbage collector as there is no use from it. Stream itself does not take more space than iterator it originates from. Bear in mind, that streams can be potentially infinite. Elements currently manipulated are stored in memory.
edited Mar 7 at 5:34
answered Mar 6 at 16:17
AndronicusAndronicus
4,71921531
4,71921531
1
@AlikElzin-kilaka please don't ask about the memory implications :) To me, it's obvious that none of Stream API solutions will outdo the simple loop approach mentioned by you (I'd go with a fori loop, though) in any way (performance, readability, maintenance). I honestly don't understand why you want streams here.
– Andrew Tobilko
Mar 6 at 16:44
Why do you assume that it's safe to cast:(List<E>) itemIter
?
– ernest_k
Mar 6 at 16:46
@ernest_k it doesn't really matter, I don't know the context (whatitemIter
really is). Let's just treat it as a pseudocode, that can be compiled, just to show the idea :)
– Andronicus
Mar 6 at 16:48
1
Well, it doesn’t even compile. Since objects are not anIterable
and anIterator
at the same time, you can’t cast it toList
and expect it to also have anext()
method. Once you fixed this, you don’t need the questionable type cast:E firstElement = itemIter.iterator().next(); Stream<E> stream = StreamSupport.stream(itemIter.spliterator(), false);
– Holger
Mar 6 at 17:44
add a comment |
1
@AlikElzin-kilaka please don't ask about the memory implications :) To me, it's obvious that none of Stream API solutions will outdo the simple loop approach mentioned by you (I'd go with a fori loop, though) in any way (performance, readability, maintenance). I honestly don't understand why you want streams here.
– Andrew Tobilko
Mar 6 at 16:44
Why do you assume that it's safe to cast:(List<E>) itemIter
?
– ernest_k
Mar 6 at 16:46
@ernest_k it doesn't really matter, I don't know the context (whatitemIter
really is). Let's just treat it as a pseudocode, that can be compiled, just to show the idea :)
– Andronicus
Mar 6 at 16:48
1
Well, it doesn’t even compile. Since objects are not anIterable
and anIterator
at the same time, you can’t cast it toList
and expect it to also have anext()
method. Once you fixed this, you don’t need the questionable type cast:E firstElement = itemIter.iterator().next(); Stream<E> stream = StreamSupport.stream(itemIter.spliterator(), false);
– Holger
Mar 6 at 17:44
1
1
@AlikElzin-kilaka please don't ask about the memory implications :) To me, it's obvious that none of Stream API solutions will outdo the simple loop approach mentioned by you (I'd go with a fori loop, though) in any way (performance, readability, maintenance). I honestly don't understand why you want streams here.
– Andrew Tobilko
Mar 6 at 16:44
@AlikElzin-kilaka please don't ask about the memory implications :) To me, it's obvious that none of Stream API solutions will outdo the simple loop approach mentioned by you (I'd go with a fori loop, though) in any way (performance, readability, maintenance). I honestly don't understand why you want streams here.
– Andrew Tobilko
Mar 6 at 16:44
Why do you assume that it's safe to cast:
(List<E>) itemIter
?– ernest_k
Mar 6 at 16:46
Why do you assume that it's safe to cast:
(List<E>) itemIter
?– ernest_k
Mar 6 at 16:46
@ernest_k it doesn't really matter, I don't know the context (what
itemIter
really is). Let's just treat it as a pseudocode, that can be compiled, just to show the idea :)– Andronicus
Mar 6 at 16:48
@ernest_k it doesn't really matter, I don't know the context (what
itemIter
really is). Let's just treat it as a pseudocode, that can be compiled, just to show the idea :)– Andronicus
Mar 6 at 16:48
1
1
Well, it doesn’t even compile. Since objects are not an
Iterable
and an Iterator
at the same time, you can’t cast it to List
and expect it to also have a next()
method. Once you fixed this, you don’t need the questionable type cast: E firstElement = itemIter.iterator().next(); Stream<E> stream = StreamSupport.stream(itemIter.spliterator(), false);
– Holger
Mar 6 at 17:44
Well, it doesn’t even compile. Since objects are not an
Iterable
and an Iterator
at the same time, you can’t cast it to List
and expect it to also have a next()
method. Once you fixed this, you don’t need the questionable type cast: E firstElement = itemIter.iterator().next(); Stream<E> stream = StreamSupport.stream(itemIter.spliterator(), false);
– Holger
Mar 6 at 17:44
add a comment |
If your starting point is a Stream
and you want to retain all of its properties and the laziness, the following solution will do:
public static <E> Stream<E> forFirst(Stream<E> stream, Consumer<? super E> c) {
boolean parallel = stream.isParallel();
Spliterator<E> sp = stream.spliterator();
return StreamSupport.stream(() -> {
if(sp.getExactSizeIfKnown() == 0) return sp;
Stream.Builder<E> b = Stream.builder();
if(!sp.tryAdvance(b.andThen(c))) return sp;
return Stream.concat(b.build(), StreamSupport.stream(sp, parallel)).spliterator();
}, sp.characteristics(), parallel);
}
E.g. when you use it with
List<String> list = new ArrayList<>(List.of("foo", "bar", "baz"));
Stream<String> stream = forFirst(
list.stream().filter(s -> s.startsWith("b")),
s -> System.out.println(s+" ("+s.getClass().getSimpleName()+')')
).map(String::toUpperCase);
list.add(1, "blah");
System.out.println(stream.collect(Collectors.joining(" | ")));
it will print
blah (String)
BLAH | BAR | BAZ
demonstrating that the processing will not start before commencing the terminal operation (collect
), hence reflecting the preceding update to the source List
.
can't tell why this is not a lot higher :|
– Eugene
Mar 7 at 8:31
@Eugene because posted two hours after the other answers and being placed at the end in the default ordering… nothing to worry about
– Holger
Mar 7 at 10:07
add a comment |
If your starting point is a Stream
and you want to retain all of its properties and the laziness, the following solution will do:
public static <E> Stream<E> forFirst(Stream<E> stream, Consumer<? super E> c) {
boolean parallel = stream.isParallel();
Spliterator<E> sp = stream.spliterator();
return StreamSupport.stream(() -> {
if(sp.getExactSizeIfKnown() == 0) return sp;
Stream.Builder<E> b = Stream.builder();
if(!sp.tryAdvance(b.andThen(c))) return sp;
return Stream.concat(b.build(), StreamSupport.stream(sp, parallel)).spliterator();
}, sp.characteristics(), parallel);
}
E.g. when you use it with
List<String> list = new ArrayList<>(List.of("foo", "bar", "baz"));
Stream<String> stream = forFirst(
list.stream().filter(s -> s.startsWith("b")),
s -> System.out.println(s+" ("+s.getClass().getSimpleName()+')')
).map(String::toUpperCase);
list.add(1, "blah");
System.out.println(stream.collect(Collectors.joining(" | ")));
it will print
blah (String)
BLAH | BAR | BAZ
demonstrating that the processing will not start before commencing the terminal operation (collect
), hence reflecting the preceding update to the source List
.
can't tell why this is not a lot higher :|
– Eugene
Mar 7 at 8:31
@Eugene because posted two hours after the other answers and being placed at the end in the default ordering… nothing to worry about
– Holger
Mar 7 at 10:07
add a comment |
If your starting point is a Stream
and you want to retain all of its properties and the laziness, the following solution will do:
public static <E> Stream<E> forFirst(Stream<E> stream, Consumer<? super E> c) {
boolean parallel = stream.isParallel();
Spliterator<E> sp = stream.spliterator();
return StreamSupport.stream(() -> {
if(sp.getExactSizeIfKnown() == 0) return sp;
Stream.Builder<E> b = Stream.builder();
if(!sp.tryAdvance(b.andThen(c))) return sp;
return Stream.concat(b.build(), StreamSupport.stream(sp, parallel)).spliterator();
}, sp.characteristics(), parallel);
}
E.g. when you use it with
List<String> list = new ArrayList<>(List.of("foo", "bar", "baz"));
Stream<String> stream = forFirst(
list.stream().filter(s -> s.startsWith("b")),
s -> System.out.println(s+" ("+s.getClass().getSimpleName()+')')
).map(String::toUpperCase);
list.add(1, "blah");
System.out.println(stream.collect(Collectors.joining(" | ")));
it will print
blah (String)
BLAH | BAR | BAZ
demonstrating that the processing will not start before commencing the terminal operation (collect
), hence reflecting the preceding update to the source List
.
If your starting point is a Stream
and you want to retain all of its properties and the laziness, the following solution will do:
public static <E> Stream<E> forFirst(Stream<E> stream, Consumer<? super E> c) {
boolean parallel = stream.isParallel();
Spliterator<E> sp = stream.spliterator();
return StreamSupport.stream(() -> {
if(sp.getExactSizeIfKnown() == 0) return sp;
Stream.Builder<E> b = Stream.builder();
if(!sp.tryAdvance(b.andThen(c))) return sp;
return Stream.concat(b.build(), StreamSupport.stream(sp, parallel)).spliterator();
}, sp.characteristics(), parallel);
}
E.g. when you use it with
List<String> list = new ArrayList<>(List.of("foo", "bar", "baz"));
Stream<String> stream = forFirst(
list.stream().filter(s -> s.startsWith("b")),
s -> System.out.println(s+" ("+s.getClass().getSimpleName()+')')
).map(String::toUpperCase);
list.add(1, "blah");
System.out.println(stream.collect(Collectors.joining(" | ")));
it will print
blah (String)
BLAH | BAR | BAZ
demonstrating that the processing will not start before commencing the terminal operation (collect
), hence reflecting the preceding update to the source List
.
answered Mar 6 at 18:26
HolgerHolger
169k23238454
169k23238454
can't tell why this is not a lot higher :|
– Eugene
Mar 7 at 8:31
@Eugene because posted two hours after the other answers and being placed at the end in the default ordering… nothing to worry about
– Holger
Mar 7 at 10:07
add a comment |
can't tell why this is not a lot higher :|
– Eugene
Mar 7 at 8:31
@Eugene because posted two hours after the other answers and being placed at the end in the default ordering… nothing to worry about
– Holger
Mar 7 at 10:07
can't tell why this is not a lot higher :|
– Eugene
Mar 7 at 8:31
can't tell why this is not a lot higher :|
– Eugene
Mar 7 at 8:31
@Eugene because posted two hours after the other answers and being placed at the end in the default ordering… nothing to worry about
– Holger
Mar 7 at 10:07
@Eugene because posted two hours after the other answers and being placed at the end in the default ordering… nothing to worry about
– Holger
Mar 7 at 10:07
add a comment |
You can abuse reduction:
Stream<E> stream = ...;
System.out.println(stream
.reduce("",(out,e) ->
out + (out.isEmpty() ? e.getClass().getSimpleName()+"n" : "")
+ e));
add a comment |
You can abuse reduction:
Stream<E> stream = ...;
System.out.println(stream
.reduce("",(out,e) ->
out + (out.isEmpty() ? e.getClass().getSimpleName()+"n" : "")
+ e));
add a comment |
You can abuse reduction:
Stream<E> stream = ...;
System.out.println(stream
.reduce("",(out,e) ->
out + (out.isEmpty() ? e.getClass().getSimpleName()+"n" : "")
+ e));
You can abuse reduction:
Stream<E> stream = ...;
System.out.println(stream
.reduce("",(out,e) ->
out + (out.isEmpty() ? e.getClass().getSimpleName()+"n" : "")
+ e));
edited Mar 6 at 16:38
answered Mar 6 at 16:20
Benjamin UrquhartBenjamin Urquhart
1446
1446
add a comment |
add a comment |
One workaround is to do it like this -
import java.util.*;
import java.util.stream.Collectors;
public class MyClass {
static int i = 0;
static int getCounter(){
return i;
}
static void incrementCounter(){
i++;
}
public static void main(String args) {
List<String> list = Arrays.asList("A", "B", "C", "D", "E", "F", "G");
List<String> answer = list.stream().filter(str -> {if(getCounter()==0) {System.out.println("First Element : " + str);} incrementCounter(); return true;}).
collect(Collectors.toList());
System.out.println(answer);
}
}
Output :
First Element : A
[A, B, C, D, E, F, G]
1
requires you to always reset the value though, and will not work in a multi thread environment
– Lino
Mar 6 at 16:52
add a comment |
One workaround is to do it like this -
import java.util.*;
import java.util.stream.Collectors;
public class MyClass {
static int i = 0;
static int getCounter(){
return i;
}
static void incrementCounter(){
i++;
}
public static void main(String args) {
List<String> list = Arrays.asList("A", "B", "C", "D", "E", "F", "G");
List<String> answer = list.stream().filter(str -> {if(getCounter()==0) {System.out.println("First Element : " + str);} incrementCounter(); return true;}).
collect(Collectors.toList());
System.out.println(answer);
}
}
Output :
First Element : A
[A, B, C, D, E, F, G]
1
requires you to always reset the value though, and will not work in a multi thread environment
– Lino
Mar 6 at 16:52
add a comment |
One workaround is to do it like this -
import java.util.*;
import java.util.stream.Collectors;
public class MyClass {
static int i = 0;
static int getCounter(){
return i;
}
static void incrementCounter(){
i++;
}
public static void main(String args) {
List<String> list = Arrays.asList("A", "B", "C", "D", "E", "F", "G");
List<String> answer = list.stream().filter(str -> {if(getCounter()==0) {System.out.println("First Element : " + str);} incrementCounter(); return true;}).
collect(Collectors.toList());
System.out.println(answer);
}
}
Output :
First Element : A
[A, B, C, D, E, F, G]
One workaround is to do it like this -
import java.util.*;
import java.util.stream.Collectors;
public class MyClass {
static int i = 0;
static int getCounter(){
return i;
}
static void incrementCounter(){
i++;
}
public static void main(String args) {
List<String> list = Arrays.asList("A", "B", "C", "D", "E", "F", "G");
List<String> answer = list.stream().filter(str -> {if(getCounter()==0) {System.out.println("First Element : " + str);} incrementCounter(); return true;}).
collect(Collectors.toList());
System.out.println(answer);
}
}
Output :
First Element : A
[A, B, C, D, E, F, G]
answered Mar 6 at 16:33
Mohammad AdilMohammad Adil
39.5k1471100
39.5k1471100
1
requires you to always reset the value though, and will not work in a multi thread environment
– Lino
Mar 6 at 16:52
add a comment |
1
requires you to always reset the value though, and will not work in a multi thread environment
– Lino
Mar 6 at 16:52
1
1
requires you to always reset the value though, and will not work in a multi thread environment
– Lino
Mar 6 at 16:52
requires you to always reset the value though, and will not work in a multi thread environment
– Lino
Mar 6 at 16:52
add a comment |
You could use peek
for that:
AtomicBoolean first = new AtomicBoolean(true);
StreamSupport.stream(itemIter.spliterator(), false)
.peek(e -> {
if(first.get()) {
System.out.println(e.getClass().getSimpleName());
first.set(false);
}
})
...
1
In that sense, I guess the code in question would be much better even if the iterable is defined. Keeping in mind there is nothing likeitemIter.stream()
available up front.
– Naman
Mar 6 at 16:36
@nullpointer you're right, I've edited my answer to use StreamSupport
– Lino
Mar 6 at 16:46
The action passed topeek
will be executed in the processing order which is not guaranteed to be the Stream’s encounter order.
– Holger
Mar 6 at 17:45
add a comment |
You could use peek
for that:
AtomicBoolean first = new AtomicBoolean(true);
StreamSupport.stream(itemIter.spliterator(), false)
.peek(e -> {
if(first.get()) {
System.out.println(e.getClass().getSimpleName());
first.set(false);
}
})
...
1
In that sense, I guess the code in question would be much better even if the iterable is defined. Keeping in mind there is nothing likeitemIter.stream()
available up front.
– Naman
Mar 6 at 16:36
@nullpointer you're right, I've edited my answer to use StreamSupport
– Lino
Mar 6 at 16:46
The action passed topeek
will be executed in the processing order which is not guaranteed to be the Stream’s encounter order.
– Holger
Mar 6 at 17:45
add a comment |
You could use peek
for that:
AtomicBoolean first = new AtomicBoolean(true);
StreamSupport.stream(itemIter.spliterator(), false)
.peek(e -> {
if(first.get()) {
System.out.println(e.getClass().getSimpleName());
first.set(false);
}
})
...
You could use peek
for that:
AtomicBoolean first = new AtomicBoolean(true);
StreamSupport.stream(itemIter.spliterator(), false)
.peek(e -> {
if(first.get()) {
System.out.println(e.getClass().getSimpleName());
first.set(false);
}
})
...
edited Mar 6 at 16:45
answered Mar 6 at 16:32
LinoLino
10k22043
10k22043
1
In that sense, I guess the code in question would be much better even if the iterable is defined. Keeping in mind there is nothing likeitemIter.stream()
available up front.
– Naman
Mar 6 at 16:36
@nullpointer you're right, I've edited my answer to use StreamSupport
– Lino
Mar 6 at 16:46
The action passed topeek
will be executed in the processing order which is not guaranteed to be the Stream’s encounter order.
– Holger
Mar 6 at 17:45
add a comment |
1
In that sense, I guess the code in question would be much better even if the iterable is defined. Keeping in mind there is nothing likeitemIter.stream()
available up front.
– Naman
Mar 6 at 16:36
@nullpointer you're right, I've edited my answer to use StreamSupport
– Lino
Mar 6 at 16:46
The action passed topeek
will be executed in the processing order which is not guaranteed to be the Stream’s encounter order.
– Holger
Mar 6 at 17:45
1
1
In that sense, I guess the code in question would be much better even if the iterable is defined. Keeping in mind there is nothing like
itemIter.stream()
available up front.– Naman
Mar 6 at 16:36
In that sense, I guess the code in question would be much better even if the iterable is defined. Keeping in mind there is nothing like
itemIter.stream()
available up front.– Naman
Mar 6 at 16:36
@nullpointer you're right, I've edited my answer to use StreamSupport
– Lino
Mar 6 at 16:46
@nullpointer you're right, I've edited my answer to use StreamSupport
– Lino
Mar 6 at 16:46
The action passed to
peek
will be executed in the processing order which is not guaranteed to be the Stream’s encounter order.– Holger
Mar 6 at 17:45
The action passed to
peek
will be executed in the processing order which is not guaranteed to be the Stream’s encounter order.– Holger
Mar 6 at 17:45
add a comment |
You can also use an boolean atomic reference:
AtomicReference<Boolean> first = new AtomicReference<Boolean>(Boolean.TRUE);
stream.forEach(e ->
System.out.println("First == " + first.getAndUpdate(b -> false)));
add a comment |
You can also use an boolean atomic reference:
AtomicReference<Boolean> first = new AtomicReference<Boolean>(Boolean.TRUE);
stream.forEach(e ->
System.out.println("First == " + first.getAndUpdate(b -> false)));
add a comment |
You can also use an boolean atomic reference:
AtomicReference<Boolean> first = new AtomicReference<Boolean>(Boolean.TRUE);
stream.forEach(e ->
System.out.println("First == " + first.getAndUpdate(b -> false)));
You can also use an boolean atomic reference:
AtomicReference<Boolean> first = new AtomicReference<Boolean>(Boolean.TRUE);
stream.forEach(e ->
System.out.println("First == " + first.getAndUpdate(b -> false)));
answered Mar 6 at 16:59
ernest_kernest_k
23.5k42749
23.5k42749
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55027574%2fhow-do-i-get-the-first-element-while-continue-streaming%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Please note that it's a question about streams - not about iterators. I have a stream - not an iterator.
– AlikElzin-kilaka
Mar 6 at 16:38
@AndrewTobilko - I don't have an
Iterable
- justStream
.– AlikElzin-kilaka
Mar 6 at 19:29
Note that, if you have a stream, you can get an iterator (and, if you need one, also an iterable).
– Ilmari Karonen
Mar 7 at 8:47