Finding the Highest Value in a Java Map – 寻找Java地图中的最高值

最后修改: 2018年 9月 27日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this quick tutorial, we’ll explore various ways to find the maximum value in a Java Map. We’ll also see how new features in Java 8 have simplified this operation.

在这个快速教程中,我们将探索在Java Map中寻找最大值的各种方法。我们还将看到Java 8中的新功能是如何简化这一操作的。

Before we begin let’s briefly recap how objects are compared in Java.

在我们开始之前,让我们简单回顾一下对象在Java中是如何进行比较的

Typically objects can express a natural ordering by implementing the method compareTo() from the Comparable interface. However, an ordering other than natural ordering can be employed through a Comparator object. We’ll see these in more details as we go on.

通常,对象可以通过实现Comparable接口的compareTo()方法来表达自然排序。然而,除了自然排序之外,还可以通过Comparator对象来实现排序。我们将在接下来的讨论中更详细地了解这些。

2. Before Java 8

2.在Java 8之前

Let’s start first exploring how can we find the highest value without Java 8 features.

让我们首先开始探索如何才能在没有Java 8功能的情况下找到最高价值。

2.1. Using Simple Iteration

2.1.使用简单迭代法

Using iteration we could simply go through all the entries of a Map to pick the highest value, storing the current highest in a variable:

使用迭代,我们可以简单地通过Map的所有条目来挑选最高值,将当前最高值存储在一个变量中。

public <K, V extends Comparable<V>> V maxUsingIteration(Map<K, V> map) {
    Map.Entry<K, V> maxEntry = null;
    for (Map.Entry<K, V> entry : map.entrySet()) {
        if (maxEntry == null || entry.getValue()
            .compareTo(maxEntry.getValue()) > 0) {
            maxEntry = entry;
        }
    }
    return maxEntry.getValue();
}

Here, we’re also making use of Java generics to build a method that can be applied to different types.

在这里,我们也在利用Java的泛型来构建一个可以应用于不同类型的方法。

2.2. Using Collections.max()

2.2.使用Collections.max()

Now let’s see how the utility method max() in the Collections class can save us from writing a lot of this ourselves:

现在让我们看看Collections类中的实用方法max()如何让我们不用自己写很多东西。

public <K, V extends Comparable<V>> V maxUsingCollectionsMax(Map<K, V> map) {
    Entry<K, V> maxEntry = Collections.max(map.entrySet(), new Comparator<Entry<K, V>>() {
        public int compare(Entry<K, V> e1, Entry<K, V> e2) {
            return e1.getValue()
                .compareTo(e2.getValue());
        }
    });
    return maxEntry.getValue();
}

In this example, we’re passing a Comparator object to max() which can leverage the natural ordering of the Entry values through compareTo() or implement a different ordering altogether.

在这个例子中,我们将一个Comparator对象传递给max(),它可以通过compareTo()利用Entry值的自然排序,或者完全实现一个不同的排序。

3. After Java 8

3.Java 8之后

Java 8 features can simplify our attempt above to get the max value from a Map in more ways than one.

Java 8的特性可以简化我们上述从Map中获取最大值的尝试,而且不止一种方式。

3.1. Using Collections.max()  with a Lambda Expression

3.1.在Lambda表达式中使用Collections.max()

Let’s begin by exploring how lambda expressions can simplify the call to Collections.max():

让我们首先探讨一下lambda表达式如何简化对Collections.max()的调用。

public <K, V extends Comparable<V>> V maxUsingCollectionsMaxAndLambda(Map<K, V> map) {
    Entry<K, V> maxEntry = Collections.max(map.entrySet(), (Entry<K, V> e1, Entry<K, V> e2) -> e1.getValue()
        .compareTo(e2.getValue()));
    return maxEntry.getValue();
}

As we can see here, lambda expressions save us from defining the full-fledged functional interface and provide a concise way of defining the logic. To read more about lambda expressions, also check out our previous article.

正如我们在这里看到的,lambda表达式使我们不必定义完整的函数式界面,并提供了一种定义逻辑的简洁方式。要阅读更多关于lambda表达式的内容,还可以查看我们之前的文章

3.2. Using Stream

3.2.使用Stream

The Stream API is another addition to Java 8 which has largely simplified working with collections:

Stream API是Java 8的另一个新增功能,它在很大程度上简化了与集合的工作。

public <K, V extends Comparable<V>> V maxUsingStreamAndLambda(Map<K, V> map) {
    Optional<Entry<K, V>> maxEntry = map.entrySet()
        .stream()
        .max((Entry<K, V> e1, Entry<K, V> e2) -> e1.getValue()
            .compareTo(e2.getValue())
        );
    
    return maxEntry.get().getValue();
}

This API offers a lot of data processing queries like map-reduce transformations on collections. Here, we’ve used max() over a stream of Map Entry which is a special case of a reduction operation. More details about the Stream API are available here.

这个API提供了很多数据处理查询,比如对集合进行map-reduce转换。这里,我们在一个Map Entry的流上使用了max(),这是还原操作的一个特殊情况。关于Stream API的更多细节可在这里获得。

We’re also making use of the Optional API here which is a container object added in Java 8 that may or may not contain a non-null value. More details about Optional can be obtained here.

我们在这里还利用了Optional API,这是一个在Java 8中添加的容器对象,可能包含也可能不包含非空值。关于Optional的更多细节可以在这里获得。

3.3. Using Stream with Method Reference

3.3.使用Stream与方法引用

Lastly, let’s see how method references can further simplify our use of lambda expressions:

最后,让我们看看方法引用如何进一步简化我们对lambda表达式的使用。

public <K, V extends Comparable<V>> V maxUsingStreamAndMethodReference(Map<K, V> map) {
    Optional<Entry<K, V>> maxEntry = map.entrySet()
        .stream()
        .max(Comparator.comparing(Map.Entry::getValue));
    return maxEntry.get()
        .getValue();
}

In cases where lambda expressions are merely calling an existing method, a method reference allows us to do this using the method name directly. For more details about method references have a look at this previous article.

在lambda表达式只是调用一个现有的方法的情况下,方法引用允许我们直接使用方法名来完成这个任务。关于m方法引用的更多细节,请看这篇以前的文章

4. Conclusion

4.总结

In this article, we’ve seen multiple ways of finding the highest value in a Java Map, some of which were using features added as part of Java 8.

在本文中,我们看到了在Java Map中寻找最高值的多种方法,其中一些是使用作为Java 8的一部分而添加的功能。

As always, the code for the examples is available over on GitHub.

像往常一样,这些例子的代码可以在GitHub上找到over