比较器工作方式的效率

我试图使用比较器来帮助排序对象列表。 我有一个问题,关于比较器的确切工作原理以及它在以下示例中的作用:

private static Comparator comparator() { return (Student a, Student b) -> { return Integer.compare(complexOperation(a), complexOperation(b)); } } 

如您所见,需要根据complexOperation()方法返回的整数等级对学生进行比较和排序。 顾名思义,这是一项繁重的操作。 上述方法是否最有效? 或者,最好是按照我要排序的列表中的每个学生进行操作,对每个学生执行complexOperation()并将结果存储在Student对象的字段中。 然后比较器会做一个:

 Integer.compare(a.getRank(), b.getRank()) 

这两种方法是否具有可比性,或者由于比较器的工作方式(可能比较同一个对象不止一次,因此在比较期间每个学生多次运行complexOperation()),是否可以更快地进行预计算complexOperation()会导致学生领域?

以上将被称为如下:

 Collections.sort(students, comparator()); 

希望很清楚!

编辑:让我们说,为了它,不可能在Student对象中添加一个字段(对于一个更复杂的情况,这是一个玩具问题,我无法自由修改Student对象)。 是否仍然可以更好地创建一个自定义对象,其中学生坐在里面添加另一个字段而不是在比较器中执行complexOperation()? 或者还有另一种解决问题的方法吗? 我可以考虑创建一个Hashmap,它将student id作为键,complexOperation()的结果作为值,只是在比较器中创建/访问该记录?

平均而言,对于N个学生的数组,排序算法将对log 2 N调用complexOperation()方法N次。 如果操作非常慢,那么每个学生最好再运行一次。 这可以为1,000名学生提供一个数量级的改进。

但是,您不必明确地执行此操作:您可以使complexOperation(...)存储每个学生的结果,然后在后续请求中返回缓存值:

 private Map cache = new HashMap(); private int complexOperation(Student s) { // See if we computed the rank of the student before Integer res = cache.get(s); if (res != null) { // We did! Just return the stored result: return res.intValue(); } ... // do the real computation here // Save the result for future invocations cache.put(s, result); return result; } 

请注意,为了使这种方法起作用, Student类需要实现hashCodeequals

基本上,您希望通过比较每个映射到的某些值来比较学生。 这通常是通过

  static Comparator comparator() { return Comparator.comparing( Foo::complexOperation ); } 

但是,由于函数complexOperation过于昂贵,我们希望缓存其结果。 我们可以有一个通用的实用方法Function cache(Function)

  static Comparator comparator() { return Comparator.comparing( cache(Foo::complexOperation) ); } 

通常,调用者最好提供Map作为缓存

 public static  Function cache(Function f, Map cache) { return k->cache.computeIfAbsent(k, f); } 

我们可以使用IdentityHashMap作为默认缓存

 public static  Function cache(Function f) { return cache(f, new IdentityHashMap<>()); }