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();
Answer from nosid on Stack Overflow
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.

🌐
HowToDoInJava
howtodoinjava.com › home › java 8 › getting the last item of a stream
Getting the Last Item of a Stream - Java 8
March 14, 2022 - The reduce() method uses the reduction technique on the elements of the Stream. To get the last element, it continues picking up the two elements of the stream and choosing the latter. This will go on until all elements are exhausted.
🌐
Java8
java8.info › streams › findmatch.html
Java 8 - Finding & Matching Streams - java8.info
The last match selects all element within the stream that match the predicatee of age 16+, in this case all employees are over 16 and so false is returned. ... In this lesson we looked at the finding and matching terminal operators.
🌐
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 - If the stream is empty it will return a null value. The other way to get the last element of the stream is by skipping all the elements before it. This can be achieved using Skip function of Stream class.
🌐
Mkyong
mkyong.com › home › java8 › java 8 – get the last element of a stream?
Java 8 - Get the last element of a Stream? - Mkyong.com
March 14, 2020 - package com.mkyong; import java.util.Arrays; import java.util.List; public class Java8Example2 { public static void main(String[] args) { List<String> list = Arrays.asList("node", "java", "c++", "react", "javascript"); // get last element from a list String result = list.get(list.size() - 1); System.out.println(result); // get last element from a stream, via skip String result2 = list.stream().skip(list.size() - 1).findFirst().orElse("no last element"); System.out.println(result2); } }
🌐
Level Up Lunch
leveluplunch.com › java › examples › find-last-element-java8-stream
Find last element of java 8 stream | Level Up Lunch
August 11, 2015 - The difference between the two is the first will return a java 8 optional where we should first check if there is present value. The second uses orElse which returns the value passed if no values are present. In this case there is a possibility that the value returned could be null. This native java way is not as eloquent as getting the last segment in a list in groovy or finding the last value in an list. @Test public void last_element_stream() { Optional<String> optionalJava = Stream.of("a", "b", "c").reduce( (a, b) -> b); assertEquals("c", optionalJava.get()); String lastValue = Stream.of("a", "b", "c").reduce((a, b) -> b) .orElse("false"); assertEquals("c", lastValue); } Load Comments
Top answer
1 of 7
134

Do a reduction that simply returns the current value:

Stream<T> stream;
T last = stream.reduce((a, b) -> b).orElse(null);
2 of 7
39

This heavily depends on the nature of the Stream. Keep in mind that “simple” doesn’t necessarily mean “efficient”. If you suspect the stream to be very large, carrying heavy operations or having a source which knows the size in advance, the following might be substantially more efficient than the simple solution:

static <T> T getLast(Stream<T> stream) {
    Spliterator<T> sp=stream.spliterator();
    if(sp.hasCharacteristics(Spliterator.SIZED|Spliterator.SUBSIZED)) {
        for(;;) {
            Spliterator<T> part=sp.trySplit();
            if(part==null) break;
            if(sp.getExactSizeIfKnown()==0) {
                sp=part;
                break;
            }
        }
    }
    T value=null;
    for(Iterator<T> it=recursive(sp); it.hasNext(); )
        value=it.next();
    return value;
}

private static <T> Iterator<T> recursive(Spliterator<T> sp) {
    Spliterator<T> prev=sp.trySplit();
    if(prev==null) return Spliterators.iterator(sp);
    Iterator<T> it=recursive(sp);
    if(it!=null && it.hasNext()) return it;
    return recursive(prev);
}

You may illustrate the difference with the following example:

String s=getLast(
    IntStream.range(0, 10_000_000).mapToObj(i-> {
        System.out.println("potential heavy operation on "+i);
        return String.valueOf(i);
    }).parallel()
);
System.out.println(s);

It will print:

potential heavy operation on 9999999
9999999

In other words, it did not perform the operation on the first 9999999 elements but only on the last one.

🌐
CodingTechRoom
codingtechroom.com › question › java-stream-find-element-or-last-one
How to Use Java Streams to Find an Element or Retrieve the Last One? - CodingTechRoom
java list lambda java-8 java-stream · How can I use Java Streams to find a specific element or retrieve the last element in a stream? Copied · List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Diana", "Edward"); String firstMatch = names.stream() .filter(name -> name.startsWith("D")) .findFirst() .orElse("No match found"); String lastElement = names.stream() .reduce((first, second) -> second) .orElse("List is empty"); In Java Streams, you can efficiently locate a match for specific criteria using filtering and terminal operations.
Find elsewhere
🌐
codippa
codippa.com › home › get last stream element in java
3 ways to get last element of stream java 8
April 11, 2020 - List<Integer> list = Arrays.asList(new Integer[] {1,2,3,55,67,34,20}); Integer lastElement = list.stream(). reduce((first, second) -> second). orElse(null); This method will return null if the stream is empty. Method 2: Using skip skip method of java.util.stream.Stream accepts a numeric value and skip the number of stream elements equal to this value.
🌐
Oracle
docs.oracle.com › javase › 8 › docs › api › java › util › stream › Stream.html
Stream (Java Platform SE 8 )
2 weeks ago - Returns whether any elements of this stream match the provided predicate. May not evaluate the predicate on all elements if not necessary for determining the result.
🌐
TutorialsPoint
tutorialspoint.com › find-the-last-element-of-a-stream-in-java
Find the Last Element of a Stream in Java
July 31, 2023 - Note: LastElementFinder.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. 8 · We characterize a findLastElement() strategy that takes a Stream as input and returns an Optional representing the last element.
🌐
GeeksforGeeks
geeksforgeeks.org › java › find-the-last-element-of-a-stream-in-java
Find the last element of a Stream in Java - GeeksforGeeks
July 12, 2025 - To get the last element, you can use the reduce() method to ignore the first element, repeatedly, till there is no first element. ... This reduces the set of elements in a Stream to a single element, which is last.
Top answer
1 of 4
7

Well, there is a very neat way to solve your problem IMO, original idea coming from Holger (I'll find the question and link it here).

You could define your method that does the checks (I've simplified it just a bit):

static boolean checkClick(List<Campaign> campaigns, Click click) {
    return campaigns.stream().anyMatch(camp -> camp.getCampaignId() 
               == click.getCampaignId());
}

And define a function that binds the parameters:

public static <T, U> Predicate<U> bind(BiFunction<T, U, Boolean> f, T t) {
    return u -> f.apply(t, u);
}

And the usage would be:

BiFunction<List<Campaign>, Click, Boolean> biFunction = YourClass::checkClick;
Predicate<Click> predicate = bind(biFunction, campaigns);

clicks.stream()
      .filter(predicate::test)
      .collect(Collectors.toList());
2 of 4
6

One thing that stands out is that your 2nd requirement has nothing to do with the matching, it's a condition on campaigns only. You'd have to test if this is any better for you:

clicks.stream()
    .filter(click -> campaigns.stream()
        .filter(camp -> "prospecting".equals(camp.type))
        .anyMatch(camp -> 
            camp.campaignId == click.campaignId &&
            camp.end.after(click.date) &&
            camp.start.before(click.date)
        )
    )
    .collect(Collectors.toList());

Otherwise, I have never seen a streams solution which does not involve streaming the 2nd collection inside the predicate of the 1st, so you can't do much better than what you did. In terms of readability, if it looks that confusing to you then create a method that test for the boolean condition and call it:

clicks.stream()
    .filter(click -> campaigns.stream()
        .filter(camp -> "pre".equals(camp.type))
        .anyMatch(camp -> accept(camp, click))
    )
    .collect(Collectors.toList());

static boolean accept(Campaign camp, Click click) {
    return camp.campaignId == click.campaignId &&
            camp.end.after(click.date) &&
            camp.start.before(click.date);
}

Finally, 2 unrelated suggestions:

  1. Don't use the old Date class, instead use the new java.time API's LocalDate.
  2. If Campaign's type can only have some predefined values (like "submitted", "prospecting", "accepted"...) then an enum would be a better fit than a general String.
Top answer
1 of 3
394

This might be what you are looking for:

yourStream
    .filter(/* your criteria */)
    .findFirst()
    .get();

And better, if there's a possibility of matching no element, in which case get() will throw a NPE. So use:

yourStream
    .filter(/* your criteria */)
    .findFirst()
    .orElse(null); /* You could also create a default object here */


An example:
public static void main(String[] args) {
    class Stop {
        private final String stationName;
        private final int    passengerCount;

        Stop(final String stationName, final int passengerCount) {
            this.stationName    = stationName;
            this.passengerCount = passengerCount;
        }
    }

    List<Stop> stops = new LinkedList<>();

    stops.add(new Stop("Station1", 250));
    stops.add(new Stop("Station2", 275));
    stops.add(new Stop("Station3", 390));
    stops.add(new Stop("Station2", 210));
    stops.add(new Stop("Station1", 190));

    Stop firstStopAtStation1 = stops.stream()
            .filter(e -> e.stationName.equals("Station1"))
            .findFirst()
            .orElse(null);

    System.out.printf("At the first stop at Station1 there were %d passengers in the train.", firstStopAtStation1.passengerCount);
}

Output is:

At the first stop at Station1 there were 250 passengers in the train.
2 of 3
10

When you write a lambda expression, the argument list to the left of -> can be either a parenthesized argument list (possibly empty), or a single identifier without any parentheses. But in the second form, the identifier cannot be declared with a type name. Thus:

this.stops.stream().filter(Stop s-> s.getStation().getName().equals(name));

is incorrect syntax; but

this.stops.stream().filter((Stop s)-> s.getStation().getName().equals(name));

is correct. Or:

this.stops.stream().filter(s -> s.getStation().getName().equals(name));

is also correct if the compiler has enough information to figure out the types.

🌐
Blogger
java8example.blogspot.com › 2019 › 09 › java-stream-last-element.html
Java 8: How to Get the Last Element of a Stream in Java? Java8Example
September 11, 2019 - skippedStream = fruits.stream().skip(noOfValues - 1); Optional · lastFruit = skippedStream.findFirst(); String lastFruitFromList = lastFruit.get(); System.out.println("Last fruit from the list : " + lastFruitFromList); ... Last fruit from the list : BlueBerry if we pass n value as negative then it throws the below IllegalArgumnetException. Exception in thread "main" java.lang.IllegalArgumentException: -1
🌐
Baeldung
baeldung.com › home › java › java streams › understanding findany() and anymatch() in streams
Understanding findAny() and anyMatch() in Streams | Baeldung
September 20, 2024 - However, the real advantage of findAny() comes when working with parallel streams, where it can quickly grab any matching element, potentially improving performance when order isn’t important: @Test public void whenParallelStreamUsingFindAny_thenOK() { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Integer result = numbers.parallelStream() .filter(n -> n % 2 == 0) .findAny() .orElse(null); assertNotNull(result); assertTrue(Arrays.asList(2, 4, 6, 8, 10).contains(result)); }