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

PM *_*7-1 3 java max comparator java-8 java-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 +
                    '}';
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我在方法参考上遇到语法错误,我不明白.

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

虽然IntelliJ IDEA抱怨说Non-static method cannot be referenced from a static context.

我到底错在了什么?


附加说明(2014年4月24日):

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

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

由于BigDecimal实现Comparable但似乎没有实现Comparator(它有CompareTo()没有 Compare())我认为自定义Comparator是必要的.这就是我不能使用的原因Comparator.comparing(ft -> ft.value).我的逻辑中有缺陷吗?

Stu*_*rks 13

Sotirios Delimanolis的回答显示了如何解决问题,但我还有一些事情需要补充.

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

    .max(new forTestComparator())
Run Code Online (Sandbox Code Playgroud)

要么

    forTestComparator instance = new forTestComparator();
    ...
    .max(instance)
Run Code Online (Sandbox Code Playgroud)

但是,Comparator上的组合函数通常不需要有一个实现Comparator的类.例如,你可以forTestComparator完全摆脱这个类,只需这样做:

    .max(Comparator.comparing(ft -> ft.value))
Run Code Online (Sandbox Code Playgroud)

或者如果forTest要有明显的getValue()方法,可以重写stream max()调用,如下所示:

    .max(Comparator.comparing(forTest::getValue))
Run Code Online (Sandbox Code Playgroud)

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

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

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

    .max(Comparator.naturalOrder())
Run Code Online (Sandbox Code Playgroud)

两种风格的笔记:

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

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


Sot*_*lis 6

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

就像是

new forTestComparator()::compare
Run Code Online (Sandbox Code Playgroud)

或者很长的路(你的班级没有实例状态,所以你真的不关心参考)

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

请参阅此处的方法参考Java教程.

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


旁注,这个

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

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