【问题标题】:Java 8 stream "Cannot use this in a static context"Java 8 流“不能在静态上下文中使用它”
【发布时间】:2017-03-02 01:35:57
【问题描述】:

我是 java8 流的新手,很抱歉这个愚蠢的问题。这是我的代码,我正在尝试创建 id & value 的映射,但我收到此错误,无法修复。谁能帮助我有什么替代方法?

    public static Map<Integer, String> findIdMaxValue(){
        Map<Integer, Map<String, Integer>> attrIdAttrValueCountMap = new HashMap<>();
        Map<Integer, String> attrIdMaxValueMap = new HashMap<>(); 
                attrIdAttrValueCountMap.forEach((attrId, attrValueCountMap) -> {
                    attrValueCountMap.entrySet().stream().sorted(this::compareAttrValueCountEntry).findFirst().ifPresent(e -> {
                        attrIdMaxValueMap.put(attrId, e.getKey());
                    });
                });
    }

及排序方法

public static int compareAttrValueCountEntry(Map.Entry<String, Integer> e1, Map.Entry<String, Integer> e2) {
    int diff = e1.getValue() - e2.getValue();
    if (diff != 0) {
        return -diff;
    }
    return e1.getKey().compareTo(e2.getKey());
}

我收到了这个错误

"Cannot use this in a static context"

【问题讨论】:

  • 尝试使用实际的类名而不是this
  • 我明白了,那么解决方案是什么?我正在尝试迭代地图并尝试对其进行排序 attrValueCountMap.entrySet().stream().sorted(this::compareAttrValueCountEntry)

标签: java java-8 java-stream


【解决方案1】:

您的代码存在几个问题。虽然this::compareAttrValueCountEntry 很容易 通过将其更改为ContainingClassName::compareAttrValueCountEntry来修复,此方法是不必要的 因为有几种工厂方法,如Map.Entry.comparingByKeyMap.Entry.comparingByValueComparator.reversedComparator.thenComparing,可以结合起来达到同一个目标

这可以保护您免受compareAttrValueCountEntry 中的错误。比较 int 很诱人 通过减法计算值,但这很容易出错,因为两个 int 值之间的差异并不总是 适合int 范围,因此可能会发生溢出。此外,否定颠倒顺序的结果是 坏了,因为值可能是Integer.MIN_VALUE,它没有正对应,因此,否定它 将溢出回Integer.MIN_VALUE,而不是更改符号。

不是通过forEach 循环添加到另一个地图,您可以使用更清晰的流操作生成 地图,您可以将sorted(…).findFirst() 简化为min(…),这不仅更短,而且 可能更便宜的操作。

把它放在一起,我们得到

Map<Integer, String> attrIdMaxValueMap =
    attrIdAttrValueCountMap.entrySet().stream()
        .filter(e -> !e.getValue().isEmpty())
        .collect(Collectors.toMap(Map.Entry::getKey,
            e -> e.getValue().entrySet().stream()
                .min(Map.Entry.<String, Integer>comparingByValue().reversed()
                        .thenComparing(Map.Entry.comparingByKey())).get().getKey()));

请注意,我在前面添加了一个 filter 操作来拒绝空地图,这样可以确保始终存在 一个匹配元素,所以不需要处理ifPresent或类似的东西。相反,Optional.get 可以无条件调用。

由于此方法称为findIdMaxValue,因此可能希望通过调用max 来反映这一点 在 Stream 而不是 min 上,这只是要反转哪个比较器的问题:

Map<Integer, String> attrIdMaxValueMap =
    attrIdAttrValueCountMap.entrySet().stream()
        .filter(e -> !e.getValue().isEmpty())
        .collect(Collectors.toMap(Map.Entry::getKey,
            e -> e.getValue().entrySet().stream()
                .max(Map.Entry.<String, Integer>comparingByValue()
                       .thenComparing(Map.Entry.comparingByKey(Comparator.reverseOrder())))
                .get().getKey()));

不幸的是,这样的构造遇到了类型推断的限制,这要求我们要么, 使用嵌套结构(例如 Map.Entry.comparingByKey(Comparator.reverseOrder()) 而不是 Map.Entry.comparingByKey().reversed()) 或插入显式类型,例如 Map.Entry.&lt;String, Integer&gt;comparingByValue()。在第二个变体中,反转第二个比较器, 我们两次达到了限制……

在这种特定情况下,可能需要只创建一次比较器,将其保存在一个变量中并在流操作中重用它:

Comparator<Map.Entry<String, Integer>> valueOrMinKey
    = Map.Entry.<String, Integer>comparingByValue()
         .thenComparing(Map.Entry.comparingByKey(Comparator.reverseOrder()));

Map<Integer, String> attrIdMaxValueMap =
    attrIdAttrValueCountMap.entrySet().stream()
        .filter(e -> !e.getValue().isEmpty())
        .collect(Collectors.toMap(Map.Entry::getKey,
            e -> e.getValue().entrySet().stream().max(valueOrMinKey).get().getKey()));

【讨论】:

    【解决方案2】:

    由于方法compareAttrValueCountEntry被声明为静态,

    替换方法引用

    this::compareAttrValueCountEntry

    &lt;Yourclass&gt;::compareAttrValueCountEntry

    【讨论】:

    猜你喜欢
    • 2017-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-17
    • 2013-04-05
    相关资源
    最近更新 更多