You can skip the first match by adding skip(1) after the filter:

employees.stream()
         .filter(e -> e.getName().charAt(0) == 's')
         .skip(1)
         .findAny()
         .ifPresent(e -> System.out.println("Employee : " + e));
Answer from Eran on Stack Overflow
🌐
w3resource
w3resource.com › java-exercises › stream › java-stream-exercise-8.php
Java Program: Find Second Smallest and Largest Elements in List of Integers using Streams
import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List < Integer > nums = Arrays.asList(1, 17, 54, 14, 14, 33, 45, -11); System.out.println("List of numbers: " + nums); // Find the second smallest element Integer secondSmallest = nums.stream() .distinct() .sorted() .skip(1) .findFirst() .orElse(null); // Find the second largest element Integer secondLargest = nums.stream() .distinct() .sorted((a, b) -> Integer.compare(b, a)) .skip(1) .findFirst() .orElse(null); System.out.println("\nSecond smallest element: " + secondSmallest); System.out.println("\nSecond largest element: " + secondLargest); } }
Top answer
1 of 10
284

It is possible to get the last element with the method Stream::reduce. The following listing contains a minimal example for the general case:

Stream<T> stream = ...; // sequential or parallel stream
Optional<T> last = stream.reduce((first, second) -> second);

This implementations works for all ordered streams (including streams created from Lists). For unordered streams it is for obvious reasons unspecified which element will be returned.

The implementation works for both sequential and parallel streams. That might be surprising at first glance, and unfortunately the documentation doesn't state it explicitly. However, it is an important feature of streams, and I try to clarify it:

  • The Javadoc for the method Stream::reduce states, that it "is not constrained to execute sequentially".
  • The Javadoc also requires that the "accumulator function must be an associative, non-interfering, stateless function for combining two values", which is obviously the case for the lambda expression (first, second) -> second.
  • The Javadoc for reduction operations states: "The streams classes have multiple forms of general reduction operations, called reduce() and collect() [..]" and "a properly constructed reduce operation is inherently parallelizable, so long as the function(s) used to process the elements are associative and stateless."

The documentation for the closely related Collectors is even more explicit: "To ensure that sequential and parallel executions produce equivalent results, the collector functions must satisfy an identity and an associativity constraints."


Back to the original question: The following code stores a reference to the last element in the variable last and throws an exception if the stream is empty. The complexity is linear in the length of the stream.

CArea last = data.careas
                 .stream()
                 .filter(c -> c.bbox.orientationHorizontal)
                 .reduce((first, second) -> second).get();
2 of 10
58

If you have a Collection (or more general an Iterable) you can use Google Guava's

Iterables.getLast(myIterable)

as handy oneliner.

Top answer
1 of 12
59

One of the prime motivations for the introduction of Java streams was to allow parallel operations. This led to a requirement that operations on Java streams such as map and filter be independent of the position of the item in the stream or the items around it. This has the advantage of making it easy to split streams for parallel processing. It has the disadvantage of making certain operations more complex.

So the simple answer is that there is no easy way to do things such as take every nth item or map each item to the sum of all previous items.

The most straightforward way to implement your requirement is to use the index of the list you are streaming from:

List<String> list = ...;
return IntStream.range(0, list.size())
    .filter(n -> n % 3 == 0)
    .mapToObj(list::get)
    .toList();

A more complicated solution would be to create a custom collector that collects every nth item into a list.

class EveryNth<C> {
    private final int nth;
    private final List<List<C>> lists = new ArrayList<>();
    private int next = 0;

    private EveryNth(int nth) {
        this.nth = nth;
        IntStream.range(0, nth).forEach(i -> lists.add(new ArrayList<>()));
    }

    private void accept(C item) {
        lists.get(next++ % nth).add(item);
    }

    private EveryNth<C> combine(EveryNth<C> other) {
        other.lists.forEach(l -> lists.get(next++ % nth).addAll(l));
        next += other.next;
        return this;
    }

    private List<C> getResult() {
        return lists.get(0);
    }

    public static Collector<Integer, ?, List<Integer>> collector(int nth) {
        return Collector.of(() -> new EveryNth(nth), 
            EveryNth::accept, EveryNth::combine, EveryNth::getResult));
}

This could be used as follows:

Stream.of("Anne", "Bill", "Chris", "Dean", "Eve", "Fred", "George")
    .parallel().collect(EveryNth.collector(3)).toList();

Which returns the result ["Anne", "Dean", "George"] as you would expect.

This is a very inefficient algorithm even with parallel processing. It splits all items it accepts into n lists and then just returns the first. Unfortunately it has to keep all items through the accumulation process because it's not until they are combined that it knows which list is the nth one.

Given the complexity and inefficiency of the collector solution I would definitely recommend sticking with the indices based solution above in preference to this if you can. If you aren't using a collection that supports get (e.g. you are passed a Stream rather than a List) then you will either need to collect the stream using Collectors.toList or use the EveryNth solution above.

2 of 12
14

EDIT - Nov 28, 2017

As user @Emiel suggests in the comments, the best way to do this would be to use Stream.itearate to drive the list through a sequence of indices:

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

int skip = 3;
int size = list.size();
// Limit to carefully avoid IndexOutOfBoundsException
int limit = size / skip + Math.min(size % skip, 1);

List<Integer> result = Stream.iterate(0, i -> i + skip)
    .limit(limit)
    .map(list::get)
    .collect(Collectors.toList());

System.out.println(result); // [1, 4, 7, 10]

This approach doesn't have the drawbacks of my previous answer, which comes below (I've decided to keep it for historical reasons).


Another approach would be to use Stream.iterate() the following way:

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

int skip = 3;
int size = list.size();
// Limit to carefully avoid IndexOutOfBoundsException
int limit = size / skip + Math.min(size % skip, 1);

List<Integer> result = Stream.iterate(list, l -> l.subList(skip, l.size()))
    .limit(limit)
    .map(l -> l.get(0))
    .collect(Collectors.toList());

System.out.println(result); // [1, 4, 7, 10]

The idea is to create a stream of sublists, each one skipping the first N elements of the previous one (N=3 in the example).

We have to limit the number of iterations so that we don't try to get a sublist whose bounds are out of range.

Then, we map our sublists to their first element and collect our results. Keeping the first element of every sublist works as expected because every sublist's begin index is shifted N elements to the right, according to the source list.

This is also efficient, because the List.sublist() method returns a view of the original list, meaning that it doesn't create a new List for each iteration.


EDIT: After a while, I've learnt that it's much better to take either one of @sprinter's approachs, since subList() creates a wrapper around the original list. This means that the second list of the stream would be a wrapper of the first list, the third list of the stream would be a wrapper of the second list (which is already a wrapper!), and so on...

While this might work for small to medium-sized lists, it should be noted that for a very large source list, many wrappers would be created. And this might end up being expensive, or even generating a StackOverflowError.

🌐
TutorialsPoint
tutorialspoint.com › find-the-last-element-of-a-stream-in-java
Find the Last Element of a Stream in Java
July 31, 2023 - Apply the reduce() terminal operation with a binary operator that returns the second element of the pair. Retrieve the result as an Optional object. Check if the stream was not empty and get the last element if present. import java.util.Optional; import java.util.stream.Stream; public class ...
🌐
codippa
codippa.com › home › get last stream element in java
3 ways to get last element of stream java 8
April 11, 2020 - There are three methods of getting the last element of a stream. Method 1: Using reduce method reduce method of a stream takes a parameter of type java.util.function.BinaryOperator which is a functional interface having a single method apply. This method accepts two arguments and returns a result.
Top answer
1 of 5
24

You can build a custom Collector for this task.

Map<String, String> map = 
    Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
          .collect(MappingErrors.collector());

with:

private static final class MappingErrors {

    private Map<String, String> map = new HashMap<>();

    private String first, second;

    public void accept(String str) {
        first = second;
        second = str;
        if (first != null && first.startsWith("err")) {
            map.put(first, second);
        }
    }

    public MappingErrors combine(MappingErrors other) {
        throw new UnsupportedOperationException("Parallel Stream not supported");
    }

    public Map<String, String> finish() {
        return map;
    }

    public static Collector<String, ?, Map<String, String>> collector() {
        return Collector.of(MappingErrors::new, MappingErrors::accept, MappingErrors::combine, MappingErrors::finish);
    }

}

In this collector, two running elements are kept. Each time a String is accepted, they are updated and if the first starts with "err", the two elements are added to a map.


Another solution is to use the StreamEx library which provides a pairMap method that applies a given function to the every adjacent pair of elements of this stream. In the following code, the operation returns a String array consisting of the first and second element of the pair if the first element starts with "err", null otherwise. null elements are then filtered out and the Stream is collected into a map.

Map<String, String> map = 
    StreamEx.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
            .pairMap((s1, s2) -> s1.startsWith("err") ? new String[] { s1, s2 } : null)
            .nonNull()
            .toMap(a -> a[0], a -> a[1]);

System.out.println(map);
2 of 5
9

You can write a custom collector, or use the much simpler approach of streaming over the list's indexes:

Map<String, String> result = IntStream.range(0, data.size() - 1)
        .filter(i -> data.get(i).startsWith("err"))
        .boxed()
        .collect(toMap(data::get, i -> data.get(i+1)));

This assumes that your data is in a random access friendly list or that you can temporarily dump it into one.

If you cannot randomly access the data or load it into a list or array for processing, you can always make a custom pairing collector so you can write

Map<String, String> result = data.stream()
        .collect(pairing(
                (a, b) -> a.startsWith("err"), 
                AbstractMap.SimpleImmutableEntry::new,
                toMap(Map.Entry::getKey, Map.Entry::getValue)
        ));

Here's the source for the collector. It's parallel-friendly and might come in handy in other situations:

public static <T, V, A, R> Collector<T, ?, R> pairing(BiPredicate<T, T> filter, BiFunction<T, T, V> map, Collector<? super V, A, R> downstream) {

    class Pairing {
        T left, right;
        A middle = downstream.supplier().get();
        boolean empty = true;

        void add(T t) {
            if (empty) {
                left = t;
                empty = false;
            } else if (filter.test(right, t)) {
                downstream.accumulator().accept(middle, map.apply(right, t));
            }
            right = t;
        }

        Pairing combine(Pairing other) {
            if (!other.empty) {
                this.add(other.left);
                this.middle = downstream.combiner().apply(this.middle, other.middle);
                this.right = other.right;
            }
            return this;
        }

        R finish() {
            return downstream.finisher().apply(middle);
        }
    }

    return Collector.of(Pairing::new, Pairing::add, Pairing::combine, Pairing::finish);
}
🌐
Medium
gainjavaknowledge.medium.com › how-to-find-second-highest-element-from-an-array-in-java-8-bc657932c18f
How to find second highest element from an array in java 8. | by Gain Java Knowledge | Medium
August 24, 2023 - In this tutorial, we will learn how to find second highest element from an array in java 8 using stream API. package com.demo.main; import java.util.Arrays; public class FineSecondHighestElementFromArray { public static void main(String[] args) { int[] numbers = {5, 13, 41, 88, 99, 77}; Integer SecondHighestElement = Arrays.stream(numbers) .boxed().sorted(Comparator.reverseOrder()) .skip(1).findFirst().get(); System.out.println(SecondHighestElement); } } First we will convert numbers of array into stream.
Find elsewhere
🌐
Oracle
docs.oracle.com › javase › 8 › docs › api › java › util › stream › Stream.html
Stream (Java Platform SE 8 )
1 week ago - Performs a mutable reduction operation on the elements of this stream. A mutable reduction is one in which the reduced value is a mutable result container, such as an ArrayList, and elements are incorporated by updating the state of the result rather than by replacing the result. This produces a result equivalent to: R result = supplier.get(); for (T element : this stream) accumulator.accept(result, element); return result;
🌐
Baeldung
baeldung.com › home › java › java streams › how to get the last element of a stream in java?
How to Get the Last Element of a Stream in Java? | Baeldung
January 8, 2024 - Get started with the Reactor project basics and reactive programming in Spring Boot: ... Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.
🌐
Baeldung
baeldung.com › home › java › java streams › taking every n-th element from finite and infinite streams in java
Taking Every N-th Element from Finite and Infinite Streams in Java | Baeldung
March 7, 2025 - Get started with the Reactor project basics and reactive programming in Spring Boot: ... Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.
🌐
Blogger
javarevisited.blogspot.com › 2016 › 03 › how-to-find-first-element-of-stream-in.html
How to find the first element in Stream in Java 8? findFirst() Example
October 5, 2024 - In this article, I'll show you a couple of examples of the findFirst() method with Predicate to show the true power of Stream in Java 8. You can also join these Functional Programming and Stream API courses for some really good examples and ...
Top answer
1 of 16
307

Create a custom Collector

public static <T> Collector<T, ?, T> toSingleton() {
    return Collectors.collectingAndThen(
            Collectors.toList(),
            list -> {
                if (list.size() != 1) {
                    throw new IllegalStateException();
                }
                return list.get(0);
            }
    );
}

We use Collectors.collectingAndThen to construct our desired Collector by

  1. Collecting our objects in a List with the Collectors.toList() collector.
  2. Applying an extra finisher at the end, that returns the single element — or throws an IllegalStateException if list.size != 1.

Used as:

User resultUser = users.stream()
        .filter(user -> user.getId() > 0)
        .collect(toSingleton());

You can then customize this Collector as much as you want, for example give the exception as argument in the constructor, tweak it to allow two values, and more.

An alternative — arguably less elegant — solution:

You can use a 'workaround' that involves peek() and an AtomicInteger, but really you shouldn't be using that.

What you could do instead is just collecting it in a List, like this:

LinkedList<User> users = new LinkedList<>();
users.add(new User(1, "User1"));
users.add(new User(2, "User2"));
users.add(new User(3, "User3"));
List<User> resultUserList = users.stream()
        .filter(user -> user.getId() == 1)
        .collect(Collectors.toList());
if (resultUserList.size() != 1) {
    throw new IllegalStateException();
}
User resultUser = resultUserList.get(0);
2 of 16
188

For the sake of completeness, here is the ‘one-liner’ corresponding to @prunge’s excellent answer:

User user1 = users.stream()
        .filter(user -> user.getId() == 1)
        .reduce((a, b) -> {
            throw new IllegalStateException("Multiple elements: " + a + ", " + b);
        })
        .get();

This obtains the sole matching element from the stream, throwing

  • NoSuchElementException in case the stream is empty, or
  • IllegalStateException in case the stream contains more than one matching element.

A variation of this approach avoids throwing an exception early and instead represents the result as an Optional containing either the sole element, or nothing (empty) if there are zero or multiple elements:

Optional<User> user1 = users.stream()
        .filter(user -> user.getId() == 1)
        .collect(Collectors.reducing((a, b) -> null));
🌐
Java67
java67.com › 2018 › 03 › java-8-stream-find-first-and-filter-example.html
Java 8 Stream filter() + findFirst Example Tutorial | Java67
It's also lazy which means it will not do anything until you call a terminal method like findFirst(). You can further see Learn Java Functional Programming with Lambdas and Stream course by Ranga Karnam to learn more about Stream features. Here is the code to find the first element from a List in Java 8 after applying a predicate:
Top answer
1 of 2
94

To get a range from a Stream<T>, you can use skip(long n) to first skip a set number of elements, and then you can call limit(long n) to only take a specific amount of items.

Consider a stream with 10 elements, then to get elements 3 to 7, you would normally call from a List:

list.subList(3, 7);

Now with a Stream, you need to first skip 3 items, and then take 7 - 3 = 4 items, so it becomes:

stream.skip(3).limit(4);

As a variant to @StuartMarks' solution to the second answer, I'll offer you the following solution which leaves the possibility to chain intact, it works similar to how @StuartMarks does it:

private <T> Collector<T, ?, Stream<T>> topPercentFromRangeCollector(Comparator<T> comparator, double from, double to) {
    return Collectors.collectingAndThen(
        Collectors.toList(),
        list -> list.stream()
            .sorted(comparator)
            .skip((long)(list.size() * from))
            .limit((long)(list.size() * (to - from)))
    );
}

and

IntStream.range(0, 100)
        .boxed()
        .collect(topPercentFromRangeCollector(Comparator.comparingInt(i -> i), 0.1d, 0.3d))
        .forEach(System.out::println);

This will print the elements 10 through 29.

It works by using a Collector<T, ?, Stream<T>> that takes in your elements from the stream, transforms them into a List<T>, then obtains a Stream<T>, sorts it and applies the (correct) bounds to it.

2 of 2
67

User skiwi already answered the first part of the question. The second part is:

(2) How to get top items from top 10% to top 30% from a stream with certain amount of items....

To do this, you have to use a similar technique as topPercent in my answer to the other question. That is, you have to collect the elements into a list in order to be able to get a count of the elements, possibly after some upstream filtering has been done.

Once you have the count, then you compute the right values for skip and limit based on the count and the percentages you want. Something like this might work:

Criterion topPercentFromRange(Comparator<Widget> cmp, double from, double to) {
    return stream -> {
        List<Widget> temp =
            stream.sorted(cmp).collect(toList());
        return temp.stream()
                   .skip((long)(temp.size() * from))
                   .limit((long)(temp.size() * (to - from)));
    };
}

Of course you will have to do error checking on from and to. A more subtle problem is determining how many elements to emit. For example, if you have ten elements, they are at indexes [0..9], which correspond to 0%, 10%, 20%, ..., 90%. But if you were to ask for a range from 9% to 11%, the above code would emit no elements at all, not the one at 10% like you might expect. So some tinkering with the percentage computations is probably necessary to fit the semantics of what you're trying to do.

🌐
@ankurm
ankurm.com › home › java stream api: how to get the last element
Java Stream API: How to Get the Last Element
November 15, 2025 - How it works: The lambda (first, second) -> second continuously discards the first parameter and returns the second. After processing all elements, the final value remains. This runs in O(n) time with minimal memory overhead. When working with sized streams (like those from List), you can calculate ...
🌐
TutorialsPoint
tutorialspoint.com › find-the-first-element-of-a-stream-in-java
Find the first element of a Stream in Java
July 31, 2023 - Use the filter method to match the desired condition. Use the findFirst method to obtain an Optional object with the first matching element. Check if the Optional object is empty or contains a value.
🌐
Manning Publications
livebook.manning.com › book › java-8-in-action › chapter-5
Chapter 5. Working with streams · Java 8 in Action: Lambdas, streams, and functional-style programming
August 14, 2014 - you can use the Streams API (internal iteration), which supports the filter and collect operations, to manage the iteration over the collection of data for you.