Java 使用自定义比较器的最大流

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23259318/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 21:33:04  来源:igfitidea点击:

Maximum of Stream with custom Comparator

javamaxjava-8comparatorjava-stream

提问by PM 77-1

Below is my code written specifically to use custom Comparatorwith maxin Java 8 Stream.

下面是我专门编写使用自定义代码ComparatormaxJava中8 Stream

import java.math.BigDecimal;
import java.util.*;

public class BigDecimalMax  {

    public static BigDecimal getBigDecimalMax(List<forTest> list) {

        return list.stream()
            .filter(t -> t.id % 2 == 0)
            .max(forTestComparator::compare)  //<-- syntax error ----------
            .orElse(null);
    }

    public static class forTestComparator implements Comparator<forTest> {

        @Override
        public int compare(forTest val1, forTest val2) {
            return val1.value.compareTo(val2.value);
        }
    }

    public static void main(String[] args) {

        List<forTest> lst = new ArrayList<>();
        Random rn = new Random();
        BigDecimalMax bdm = new BigDecimalMax();

        for (int i=1; i<22; ++i) {
            lst.add(bdm.new forTest(i, BigDecimal.valueOf(rn.nextLong())));
        }

        System.out.println(getBigDecimalMax(lst));

    }

    class forTest {
        public int id;
        public BigDecimal value;

        forTest(int id, BigDecimal value) {
            this.id = id;
            this.value = value;
        }

        @Override
        public String toString() {
            return "forTest{" +
                    "id=" + id +
                    ", value=" + value +
                    '}';
        }
    }
}

I'm getting a syntax error on a method reference which I don't understand.

我在一个我不明白的方法引用上遇到语法错误。

Error:(15, 18) java: incompatible types: invalid method reference
    cannot find symbol
      symbol:   method compare(BigDecimalMax.forTest, BigDecimalMax.forTest)
      location: class BigDecimalMax.forTestComparator

while IntelliJ IDEA complains that Non-static method cannot be referenced from a static context.

而 IntelliJ IDEA 则抱怨Non-static method cannot be referenced from a static context.

What exactly am I doing wrong here?

我到底做错了什么?



ADDITIONAL EXPLANATION(04/24/14):

附加说明(04/24/14):

  1. I understand now the reason for the syntax error. Thank you.

  2. Was custom Comparatoractually needed here?

  1. 我现在明白语法错误的原因了。谢谢你。

  2. Comparator这里真的需要定制吗?

Since BigDecimalimplements Comparablebut does notseem to implement Comparator( it has CompareTo()but noCompare()) I thought that custom Comparatorwas necessary. That's why I could not just use Comparator.comparing(ft -> ft.value). Is there a flaw in my logic?

由于BigDecimal实现Comparable但似乎没有实现Comparator(它有CompareTo()没有Compare()),我认为自定义Comparator是必要的。这就是为什么我不能只使用Comparator.comparing(ft -> ft.value). 我的逻辑有问题吗?

采纳答案by Stuart Marks

Sotirios Delimanolis' answershows how to fix the problems, but I have a few things to add.

Sotirios Delimanolis 的回答显示了如何解决这些问题,但我有一些要补充的内容。

If you already have a class that implements Comparator, you don't need to use a method reference to its compare() method. You can just pass an instance of it directly, since max() takes a reference to a Comparator:

如果您已经有一个实现 Comparator 的类,则不需要使用对其 compare() 方法的方法引用。您可以直接传递它的一个实例,因为 max() 需要对 Comparator 的引用:

    .max(new forTestComparator())

or

或者

    forTestComparator instance = new forTestComparator();
    ...
    .max(instance)

However, the combinator functions on Comparator usually make it unnecessary to have a class that implements Comparator. For example, you can get rid of the forTestComparatorclass entirely and just do this:

但是,Comparator 上的组合器函数通常不需要实现 Comparator 的类。例如,您可以forTestComparator完全摆脱该类,然后执行以下操作:

    .max(Comparator.comparing(ft -> ft.value))

or if forTestwere to have the obvious getValue() method, one could rewrite the stream max() call as follows:

或者,如果forTest有明显的 getValue() 方法,则可以按如下方式重写流 max() 调用:

    .max(Comparator.comparing(forTest::getValue))

In addition, if you wanted to make forTestimplement the Comparableinterface, you could do this:

另外,如果你想forTest实现Comparable接口,你可以这样做:

public class forTest implements Comparable<forTest> {
    @Override
    public int compareTo(forTest other) {
        return this.value.compareTo(other.value);
    }
    ...
}

and the way to use max() on a Comparable is:

在 Comparable 上使用 max() 的方法是:

    .max(Comparator.naturalOrder())


Two style notes:

两种风格说明:

  1. I strongly discourage using orElse(null)on instances of Optional. This is allowed, though probably its main purpose to retrofit use of new Java 8 APIs into code that's expecting null to indicate the absence of a value. Avoid orElse(null)if you possibly can, since this forces the caller to check for null. Instead, substitute an actual value to replace an absent value, or return the Optionalitself to the caller, so the caller can apply whatever policy it wants.

  2. I recommend sticking to the established Java naming conventions of capitalized, mixed-case class names. The class names forTestand forTestComparatormake this code kind of difficult to work with, since they don't looklike class names.

  1. 我强烈反对orElse(null)Optional. 这是允许的,尽管它的主要目的可能是将新的 Java 8 API 的使用改进为期望 null 以指示缺少值的代码。orElse(null)尽可能避免,因为这会强制调用者检查 null。相反,替换一个实际值来替换一个不存在的值,或者将其Optional本身返回给调用者,这样调用者就可以应用它想要的任何策略。

  2. 我建议坚持既定的 Java 命名约定,即大写、大小写混合的类名。类名forTestforTestComparator使此代码一种很难一起工作,因为他们不像类名。

回答by Sotirios Delimanolis

forTestComparator#compareis an instance method. You need an instancemethod reference, as opposed to a staticmethod reference that you have.

forTestComparator#compare是一个实例方法。您需要一个实例方法引用,而不是static您拥有的方法引用。

Something like

就像是

new forTestComparator()::compare

or the long way (your class doesn't have instance state, so you don't really care about the reference)

或者很长的路(你的类没有实例状态,所以你并不真正关心引用)

forTestComparator instance = new forTestComparator(); // fix for Java conventions
return list.stream()
        .filter(t -> t.id % 2 == 0)
        .max(instance::compare)  //<-- syntax error ----------
        .orElse(null);

See the Java tutorial on method references here.

请参阅此处有关方法引用的 Java 教程。

Reference to an instance method of a particular object -> ContainingObject::instanceMethodName

对特定对象的实例方法的引用 -> ContainingObject::instanceMethodName



Side note, this

旁注,这

return list.stream()
            .filter(t -> t.id % 2 == 0)
            .max(new forTestComparator()::compare)  
            .orElse(null);

resolves in a forTestvalue. You need to change the return type of your method.

解析为一个forTest值。您需要更改方法的返回类型。