Maybe you are thinking too complicated by trying to find a Stream API solution. The task can be easily solved using basic Collection API operations:

List<Timeslot> timeslots;// the source

TreeSet<Timeslot> sorted=new TreeSet<>(timeslots);
if(sorted.size() != timeslots.size())
  throw new IllegalArgumentException("Every timeslot must strictly precede the following");
// get a list where every timeslot strictly precedes the following:
timeslots=new ArrayList<>(sorted);

The equality of the TreeSet’s elements is only determined by the order. So if there are duplicates according to the order, and this is what your problem is all about, they are removed when converting the list to the set. So if the size differs, there were such duplicates. If not, you can convert the sorted set back to a list, if you need a list. Otherwise, you can just continue using the set instead of the list.


It should be mentioned, since you stated to have a ordering which is not consistent with equals, that the TreeSet will also not be fully compliant with the Set contract as stated in its documentation:

Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. […] This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.

Since your operation does not rely on the general contract of the Set interface, as there was no Set before, this is not a problem for this specific use case. Converting to a List as shown above works and so would iterating over the elements, in case you use it without conversion, i.e. don’t need specific list operations.

Answer from Holger on Stack Overflow
🌐
Oracle
docs.oracle.com › javase › 8 › docs › api › java › util › stream › Stream.html
Stream (Java Platform SE 8 )
3 weeks ago - Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.
Top answer
1 of 4
4

Maybe you are thinking too complicated by trying to find a Stream API solution. The task can be easily solved using basic Collection API operations:

List<Timeslot> timeslots;// the source

TreeSet<Timeslot> sorted=new TreeSet<>(timeslots);
if(sorted.size() != timeslots.size())
  throw new IllegalArgumentException("Every timeslot must strictly precede the following");
// get a list where every timeslot strictly precedes the following:
timeslots=new ArrayList<>(sorted);

The equality of the TreeSet’s elements is only determined by the order. So if there are duplicates according to the order, and this is what your problem is all about, they are removed when converting the list to the set. So if the size differs, there were such duplicates. If not, you can convert the sorted set back to a list, if you need a list. Otherwise, you can just continue using the set instead of the list.


It should be mentioned, since you stated to have a ordering which is not consistent with equals, that the TreeSet will also not be fully compliant with the Set contract as stated in its documentation:

Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. […] This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.

Since your operation does not rely on the general contract of the Set interface, as there was no Set before, this is not a problem for this specific use case. Converting to a List as shown above works and so would iterating over the elements, in case you use it without conversion, i.e. don’t need specific list operations.

2 of 4
2

I think sorting the list and comparing adjacent elements is a reasonable approach. Here's the streams-based code that does that:

    timeslots.sort(null);  // sort the list using natural order
    if (IntStream.range(1, timeslots.size())
                 .map(i -> timeslots.get(i-1).compareTo(timeslots.get(i)))
                 .anyMatch(i -> i == 0)) {
        throw new IllegalArgumentException("...");
    }

It's no shorter than what you have, but the streams-based approach might offer more flexibility: it can be run in parallel, you can count the number of duplicate timestamps, etc.

You could also inline the compareTo() call into the anyMatch() call, like so:

    if (IntStream.range(1, timeslots.size())
                 .anyMatch(i -> timeslots.get(i-1).compareTo(timeslots.get(i)) == 0) {

Whether this is preferable is, I think, a matter of style.

🌐
Baeldung
baeldung.com › home › java › java list › determine if all elements are the same in a java list
Determine If All Elements Are the Same in a Java List | Baeldung
April 4, 2025 - If the count of this stream is smaller or equal to 1, then all the elements are equal and we return true.
🌐
Stackify
stackify.com › streams-guide-java-8
A Guide to Java Streams: In-Depth Tutorial With Examples
September 4, 2024 - In the example above, we create an infinite stream starting from 1, then use takeWhile to select numbers less than or equal to 10, calculate their squares, and print them.
Top answer
1 of 3
10

There cannot be a simpler solution:

  • To know the duplicated ids, you must iterate over the entire collection.
  • To print all the persons with duplicated ids, you must keep their full list.

As such, you will need to load the entire collection of persons in memory. There's no way around that. If you needed only the duplicate ids but not the Person objects, then you could keep just the ids with their counts, and throw away the Person objects as you go after use, that would be more efficient. (But that's not the case here.)

In any case, your solution can be more concise if you skip the intermediary map variable with the mapping of ids to lists of users:

people.stream()
        .collect(Collectors.groupingBy(Person::getId)).values().stream()
        .filter(peopleWithSameId -> peopleWithSameId.size() > 1)
        .forEach(peopleWithSameId -> System.out.println("People with identical IDs: " + peopleWithSameId));

Btw, in case you're wondering if the .stream() there could be .parallelStream(), it would be pointless, due to the synchronization in the println method of System.out (a PrintStream). (And without synchronization println wouldn't be thread safe anyway.)

2 of 3
10

Your code and Java 8 usage looks fine in general to me.

I do see an issue with the Person class, it looks like you are intending it to be an immutable class, if so, then you should also enforce it.

You need to ensure that the name and id fields can never be changed, you can do this by adding final to them. Your code currently seems to be safe, but it is not. I can extend Person and offer a method there to change the name and id fields, which violates the assumed variant of that those fields in Person are immutable.

Simply changing it to the following will do:

public class Person {
    private final String name;
    private final String id;
    ...
}

Onto the Java 8 usage now.

It is a good thing that you use the Collectors.groupingBy to provide a Map<String, List<Person>>, you cannot do it much faster either way if you want it to work with any kind of List<Person> as input and in this way you'll save yourself from nasty bugs and reimplementing what lots of people have already done, namely the grouping by operation.

Printing the offending values using Stream seems fine as well, except that you may rewrite it to look a little bit cleaner, something like this could work:

peopleById.values().stream()
    .filter(personList -> personList.size() > 1)
    .forEach(personList -> System.out.println("People with identical IDs: " + personList);

This is my personal preference on how to format it though, the only real change is to rename peopleWithSameId to personList, as it is simply a List<Person> and nothing more or less.

You've done a good job overall.

🌐
DigitalOcean
digitalocean.com › community › tutorials › java-stream-distinct-function
Java Stream distinct() Function to Remove Duplicates | DigitalOcean
August 3, 2022 - Java Stream distinct() method returns a new stream of distinct elements. It’s useful in removing duplicate elements from the collection before processing them. The elements are compared using the equals() method.
🌐
HowToDoInJava
howtodoinjava.com › home › java 8 › java stream distinct(): collect unique values
Java Stream distinct(): Collect Unique Values
July 21, 2024 - In real-world applications, we ... inherit the equals() method from Object class. The default equals() method compares the references for checking the equality of two instances....
Find elsewhere
🌐
Oracle
docs.oracle.com › en › java › javase › 21 › docs › api › java.base › java › util › stream › Stream.html
Stream (Java SE 21 & JDK 21)
January 20, 2026 - Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.
🌐
Mkyong
mkyong.com › home › java8 › java 8 streams filter examples
Java 8 Streams filter examples - Mkyong.com
April 3, 2017 - Hello @Mkyon. Is there possible to multiple filter like this: Person result1 = persons.stream() .filter((p) -> “jack”.equals(p.getName())).filter((p)-> 20 == p.getAge())) .findAny() .orElse(null); ... Mkyong.com has provided Java and Spring tutorials, guides, and code snippets since 2008.
🌐
Oracle
docs.oracle.com › en › java › javase › 11 › docs › api › java.base › java › util › stream › Stream.html
Stream (Java SE 11 & JDK 11 )
January 20, 2026 - Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.
🌐
Oracle
docs.oracle.com › en › java › javase › 17 › docs › api › java.base › java › util › stream › Stream.html
Stream (Java SE 17 & JDK 17)
January 20, 2026 - Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.
🌐
Medium
genezeiniss.medium.com › java-streams-predicate-methods-c1c92e06b873
Matches in Java Stream. Java Stream: Predicate Methods | by Gene Zeiniss | Medium
March 21, 2025 - Given a stream of objects, often we need to check whether objects match specific criteria. Once you provided a predefined predicate as an input to the matching method, then Java processes the function internally and returns the boolean result, ...
🌐
Oracle
docs.oracle.com › javase › 10 › docs › api › java › util › stream › Stream.html
Stream (Java SE 10 & JDK 10 )
Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.
🌐
Oracle
docs.oracle.com › en › java › javase › 24 › docs › api › java.base › java › util › stream › Stream.html
Stream (Java SE 24 & JDK 24)
July 15, 2025 - Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.
Top answer
1 of 2
3

Your immediate problem is trivial to fix:

Optional<Integer> oi = nums.stream()
                           .filter(x -> x > nextNumber)
                           .findFirst();
System.out.println(oi.isPresent()? "Found: "+oi.get() : "Not found");

However, if you want to write code which optimally computes what you require it to, it is not the right approach. A far better option would be this:

OptionalInt oi = Stream.of(scn.nextLine().split(" "))
                       .mapToInt(Integer::parseInt)
                       .filter(i -> i > nextNumber)
                       .min();
System.out.println(oi.isPresent()? "Found: "+oi.getAsInt() : "Not found");

The advantage is that you never get an ArrayList involved and don't need to autobox the integers at any step, and you actually retrieve the smallest number satisfying the criterion, not the first one.

2 of 2
2

If you want to find the smallest number larger than some bound:

private int smallestLargerThan(int x, List<Integer> list) {
    return list.stream().filter(n -> n > x).mapToInt(n -> n).min();
}

.filter(n -> n > x) drops all values less than or equal to x.

.mapToInt(n -> n) transforms the Stream to an IntStream, which is required for the next operation:

.min() returns the smallest element in the IntStream. Since the stream at this point only contains values greater than x, the returned element is the number you are looking for.

The code you posted won't compile because .findFirst() returns an Optional<Integer>, not an Integer. It is also semantically wrong because the first element is not necessarily the smallest as your Stream is unsorted.