Java比较器使用非最终变量

时间:2012-10-04 12:27:41

标签: java list sorting collections final

我想使用包含每个项目值的地图对列表进行排序。

Map<Integer, Float> map = new HashMap<>();
List<Integer> list = new ArrayList<>();

map.put(0, 0.0f);
map.put(1, 5.0f);
map.put(2, 2.0f);

list = new ArrayList<>(map.keySet());

Collections.sort(list, new Comparator<Integer>() {
    public int compare(Integer left, Integer right) {
        Float leftCost = map.get(left);
        Float rightCost = map.get(right);
        return leftCost.compareTo(rightCost);
    }
})

我希望订单为0,2,1,因为1的值高于2。但是java不要让我这样做。我收到以下错误:Cannot refer to a non-final variable map inside an inner class defined in a different method

我怎么能这样做呢?

5 个答案:

答案 0 :(得分:6)

最后决定:

final Map<Integer, Float> map = new HashMap<Integer, Float>();
List<Integer> list = new ArrayList<Integer>(); // this assignment is unncessary [1]

map.put(0, 0.0f);
map.put(1, 5.0f);
map.put(2, 2.0f);

list = new ArrayList<Integer>(map.keySet()); // 1. assignment is replaced here

Collections.sort(list, new Comparator<Integer>() {
    public int compare(Integer left, Integer right) {
        Float leftCost = map.get(left);
        Float rightCost = map.get(right);
        return leftCost.compareTo(rightCost);
    }
})

由于你的地图是可变的,你仍然可以修改它。

答案 1 :(得分:2)

一个匿名内部类(您的比较器是一个)只能引用声明为final的局部变量,以便访问您的地图 - 您必须将其声明为final

请注意,声明为final并不会阻止您修改地图对象,您无法将新对象分配给变量map

答案 2 :(得分:1)

您的Comparator是一个匿名内部类。在其中,您正在尝试访问在包含匿名内部类的方法中声明的局部变量map

Java中存在一个限制,即只有局部变量为final时才能执行此操作。因此,请设置变量map final

final Map<Integer, Float> map = new HashMap<>();

答案 3 :(得分:1)

在您的情况下,解决方案很简单:将地图标记为final

final Map<Integer, Float> map = new HashMap<>();

您可能对单词final感到困惑。它不会限制您对地图的操作。它只是不允许您在您的情况下更改对映射的引用。

此要求的原因是您的比较器是匿名内部类。所有外部方法变量都复制到匿名类中,因此如果在外部方法中更改它们将产生冲突。这就是编译器要求将从匿名类访问的变量标记为final的原因。

其他解决方案是将比较器提取为单独的类,并将映射作为参数构造函数发送给它。

答案 4 :(得分:0)

你绝对可以做到这一点。只需创建一个命名类来代替扩展Comparator的匿名类,并将Map变量作为参数传递。像这样:

  @Test
  public void test() {
    Map<Integer, Float> map = new HashMap<Integer, Float>();
    map.put(0, 0.0f);
    map.put(1, 5.0f);
    map.put(2, 2.0f);

    List<Integer> list = new ArrayList<Integer>(map.keySet());
    Collections.sort(list, new FloatComparator(map));

    System.out.println(list);
  }

  class FloatComparator implements Comparator<Integer> {
    private Map<Integer, Float> mapRef;
    public FloatComparator(Map<Integer, Float> newMap) {
      mapRef = newMap;
    }

    @Override
    public int compare(Integer left, Integer right) {
      Float leftCost = mapRef.get(left);
      Float rightCost = mapRef.get(right);
      return leftCost.compareTo(rightCost);
    }
  }

打印出来:

[0, 2, 1]

还可以使您的代码更清晰,IMO。