How to Get Max or Min Element in Java Collection

Introduction

In this guide, we'll take a look at how to get the maximum or minimum element in a Java Collection, both for primitive types and custom comparable objects, via their fields.

Getting the Maximum or Minimum Element with Collections.max()

The Collections framework provides us with a wide variety of helper, static methods for working with Collections in Java. It's no wonder that this same framework allows us to search and return the maximum or minimum element of a collection as well.

Collections.max() and Collections.min() with Primitive Types

Working with primitive types is fairly easy in most regards, and as long as they're Comparable - we can easily search through them.

To find the maximum or minimum element of a Collection consisting of primitive types, we simply call the Collections.max() or Collections.min() methods, passing in the collections we're searching in:

List<Integer> list = List.of(1, 5, 4, 3, 7, 6, 9, 4);
        
Integer min = Collections.min(list);
Integer max = Collections.max(list);

System.out.println(String.format("Minimum element is %s", min));
System.out.println(String.format("Maximum element is %s", max));

Running this code returns our maximum and minimum elements:

Minimum element is 1
Maximum element is 9

Collections.max() and Collections.min() with Custom Objects

Though, we rarely only work with just primitive types. Typically, we'll be working with objects. Naturally, since these structures are much more complex - you get to decide what constitutes a greater element between the two.

Usually, this is achieved by implementing the Comparable interface, which allows you to compare any two instances of a class to determine which is greater. Let's define a class and make it Comparable:

public class Book implements Comparable<Book> {
    private String author;
    private String name;
    private int pageNumber;

    // Constructor, getters and setters

    @Override
    public int compareTo(Book book) {
        return (this.pageNumber > book.pageNumber) ? 1 : -1;
    }

    @Override
    public String toString() {
        return "Book{" +
                "author='" + author + '\'' +
                ", name='" + name + '\'' +
                ", pageNumber=" + pageNumber +
                '}';
    }
}

You'll have to @Override the compareTo() method and define by which criteria the entities are compared with. It'll typically boil down to simple primitive types in the end, such as comparing the pageNumber attribute. We've also added a toString() method for convenient formatting.

Now, searching for the maximum or minimum element, in a collection of custom objects is as easy as calling Collections.max() or Collections.min() on the Collection:

List<Book> bookList = new ArrayList<>();
bookList.add(new Book("Nick Bostrom", "Superintelligence", 352));
bookList.add(new Book("Ray Kurzweil", "The Singularity is Near", 652));
bookList.add(new Book("Max Tegmark", "Our Mathematical Universe", 432));

Book min = Collections.min(bookList);
Book max = Collections.max(bookList);

System.out.println(String.format("Minimum element is %s", min));
System.out.println(String.format("Maximum element is %s", max));

Given our comparison criteria, the results are:

Minimum element is Book{author='Nick Bostrom', name='Superintelligence', pageNumber=352}
Maximum element is Book{author='Ray Kurzweil', name='The Singularity is Near', pageNumber=652}

Custom Comparator

You can avoid making the Book comparable, if you can't by supplying a new Comparator in the Collections calls. Though, this solution is verbose and best avoided/substituted with the techniques outlined after this.

Nevertheless, it's a fully valid way to compare entities and find the maximum/minimum value:

Book min = Collections.min(bookList, new Comparator<Book>() {
    @Override
    public int compare(Book o1, Book o2) {
        return (o1.getPageNumber() > o2.getPageNumber()) ? 1 : -1;
    }
});

System.out.println(String.format("Minimum by page count is %s", min));

Or, this can be shortened through a Lambda Expression:

Book min = Collections.min(bookList, 
    (o1, o2) -> (o1.getPageNumber() > o2.getPageNumber()) ? 1 : -1);

Getting the Maximum or Minimum Element with Stream.max() and Stream.min()

With the advent of Java 8, we've been introduced to a wonderful Stream API that allows us to perform various processing pipelines. A Stream can find a maximum or minimum element via the max() or min() methods, leveraging either a new Comparator for the job, or using an already existing one, such as the comparator we've built-into our Book class.

This allows you to have non-Comparable classes and quickly use a new Comparator to set the criteria using any field. This flexibility is what makes Streams so amazing for processing data.

Stream.max() and Stream.min() with Primitive Types

Let's start off with a simple Collection of primitive types. To get the maximum or minimum element of the collection, we stream() it and call the min() or max() methods:

List<Integer> list = List.of(1, 5, 4, 3, 7, 6, 9, 4);
Integer maxInt = list.stream().mapToInt(i -> i).max().getAsInt();
Integer minInt = list.stream().mapToInt(i -> i).min().getAsInt();

System.out.println(String.format("Minimum element is %s", minInt));
System.out.println(String.format("Maximum element is %s", maxInt));

Instead of mapping i -> i, we could've alternatively just use:

Integer maxInt = list.stream().mapToInt(Integer::intValue).max().getAsInt();

The max() and min() methods return an Optional - or a derivative of the class, such as OptionalInt, OptionalDouble, etc. To extract the integer value - we use the getAsInt() at the end of the call chain.

Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

Running this code results in:

Minimum element is 1
Maximum element is 9

Instead of mapToInt() you can also use a Comparator, such as comparing() or comparingInt() (both of which would produce the same output):

Integer maxInt = list.stream().max(Comparator.comparing(Integer::intValue)).get();
Integer minInt = list.stream().min(Comparator.comparingInt(Integer::intValue)).get();

Again, these methods return an Optional, so we get() the result in the end. comparing() has the flexibility of comparing non-Integer values as well, but since we're constraining ourselves to just Integers here, it doesn't make any difference.

Stream.max() and Stream.min() with Custom Objects

Using custom comparators with custom objects is where Streams shine the most and where they provide the most flexibility. When using the Collections framework, we were constrained to compare the elements via the compareTo() method, overridden from the Comparable interface, if you don't want to define a chunky new Comparator.

With Streams - we can define a new Comparator on the fly with any field, without the class even having to implement the Comparable interface. Let's find the maximum and minimum element of a collection with custom objects, using a custom comparator and streams:

List<Book> bookList = new ArrayList<>();
bookList.add(new Book("Nick Bostrom", "Superintelligence", 352));
bookList.add(new Book("Ray Kurzweil", "The Singularity is Near", 652));
bookList.add(new Book("Max Tegmark", "Our Mathematical Universe", 432));

// Using native compareTo() Method
Book min = bookList.stream().min(Book::compareTo).get();
Book max = bookList.stream().max(Book::compareTo).get();

// Using custom new Comparator
Book minByAuthor = bookList.stream().min(Comparator.comparing(Book::getAuthor)).get();
Book maxByAuthor = bookList.stream().max(Comparator.comparing(Book::getAuthor)).get();

System.out.println(String.format("Minimum by page count is %s", min));
System.out.println(String.format("Maximum by page count is %s", max));

System.out.println(String.format("Minimum by author is %s", minByAuthor));
System.out.println(String.format("Maximum by author is %s", maxByAuthor));

This time around, we can use any field and supply it to the Comparator.comparing() method. You can also use alternative methods, such as comparingInt() here, but since we're comparing the lexicographical value of Strings, we'll be sticking with the generic comparing() method.

Running this code results in:

Minimum by page count is Book{author='Nick Bostrom', name='Superintelligence', pageNumber=352}
Maximum by page count is Book{author='Ray Kurzweil', name='The Singularity is Near', pageNumber=652}

Minimum by author is Book{author='Max Tegmark', name='Our Mathematical Universe', pageNumber=432}
Maximum by author is Book{author='Ray Kurzweil', name='The Singularity is Near', pageNumber=652}

Using a for Loop

Finally, the good old for loop can be used to search for a maximum or minimum element:

List<Book> bookList = new ArrayList<>();
bookList.add(new Book("Nick Bostrom", "Superintelligence", 352));
bookList.add(new Book("Ray Kurzweil", "The Singularity is Near", 652));
bookList.add(new Book("Max Tegmark", "Our Mathematical Universe", 432));

List<Integer> intList = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9);

// Instantiate as the first book initially
Book maxBook = bookList.get(0);
Integer maxInt = 0;

for (Book book : bookList) {
    // book.getPageNumber() < minBook.getPageNumber()
    if (book.getPageNumber() > maxBook.getPageNumber()) {
        maxBook = book;
    }
}

for (Integer integer : intList) {
    // integer < minInt
    if (integer > maxInt) {
        maxInt = integer;
    }
}

System.out.println(String.format("Maximum by page count is %s", maxBook));
System.out.println(String.format("Maximum int is %s", maxInt));

This results in the same results we've been seeing so far:

Maximum by page count is Book{author='Ray Kurzweil', name='The Singularity is Near', pageNumber=652}
Maximum int is 9

Conclusion

In this guide, we've taken a look at how to find the maximum and minimum elements of a Java Collection. We've taken a look at both primitive types and custom objects, default and custom comparators, and best practices, including a manual for loop.

Last Updated: March 7th, 2023
Was this article helpful?

Improve your dev skills!

Get tutorials, guides, and dev jobs in your inbox.

No spam ever. Unsubscribe at any time. Read our Privacy Policy.

David LandupAuthor

Entrepreneur, Software and Machine Learning Engineer, with a deep fascination towards the application of Computation and Deep Learning in Life Sciences (Bioinformatics, Drug Discovery, Genomics), Neuroscience (Computational Neuroscience), robotics and BCIs.

Great passion for accessible education and promotion of reason, science, humanism, and progress.

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms