【问题标题】:Java 8 Lambda: ComparatorJava 8 Lambda:比较器
【发布时间】:2017-10-28 18:47:57
【问题描述】:

我想用 Lambda 对列表进行排序:

List<Message> messagesByDeviceType = new ArrayList<Message>();      
messagesByDeviceType.sort((Message o1, Message o2)->o1.getTime()-o2.getTime());

但是我得到了这个编译错误:

 Multiple markers at this line
    - Type mismatch: cannot convert from long to int
    - The method sort(Comparator<? super Message>) in the type List<Message> is not applicable for the arguments ((Message o1, Message o2) 
     -> {})

【问题讨论】:

    标签: java lambda java-8 comparator


    【解决方案1】:

    Comparator#compareTo 返回一个int;而getTime 显然是long

    这样写会更好:

    .sort(Comparator.comparingLong(Message::getTime))
    

    【讨论】:

      【解决方案2】:

      拉姆达

      lambda 可以看作是有些繁琐的匿名类的简写:

      Java8 版本:

      Collections.sort(list, (o1, o2) -> o1.getTime() - o2.getTime());
      

      Java8 之前的版本:

          Collections.sort(list, new Comparator<Message>() {
              @Override
              public int compare(Message o1, Message o2) {
                  return o1.getTime() - o2.getTime();
              }
          }); 
      

      所以,每当你对如何编写正确的 lambda 感到困惑时,你可以尝试编写一个 pre-lambda 版本,看看它是怎么错的。

      应用

      在你的具体问题中,你可以看到compare返回int,你的getTime返回long,这是错误的来源。

      您可以将任一方法用作其他答案方法,例如:

      Long.compare(o1.getTime(),o2.getTime())
      

      通知

      • 您应该避免在Comparator 中使用-,这在某些情况下可能会导致溢出并导致程序崩溃。

      【讨论】:

        【解决方案3】:

        Comparatorcompare() 方法必须返回 int,而您的方法似乎返回 long

        你可以改成:

        (Message o1, Message o2)->Long.compare(o1.getTime(),o2.getTime())
        

        这是假设(根据您的错误消息)o1.getTime() 返回long

        【讨论】:

        • 我认为他们可以直接使用像 o1.getTime().compareTo(o1.getTime()) 这样的长比较方法。因为 Long 包装类已经实现了 Comparable 接口。
        【解决方案4】:

        比较器

        我们使用比较器接口对同质和异质元素进行排序,以实现默认的自定义排序顺序。

        int compare(T o1, T o2);
        

        排序需要两个参数。返回一个

            negative integer(-1) « if first argument is less than the other
            zero             (0) « if both are equal
            positive integer (1) « if first greater than the second.
        

        Anonymous Classes 如何使用内部类对prior versions of Java 8 中的对象列表进行排序。

        匿名类无法访问其封闭范围内未声明为 final 或有效 final 的局部变量。

        Comparator<Employee> timeCompare = new Comparator<Employee>() {
            @Override public int compare(Employee e1, Employee e2) {
                return e1.getCreationTime().compareTo( e2.getCreationTime() );
            }
        };
        

        Java 8 Lambda Expressions 使用比较方法

        一个 lambda 表达式就像一个方法:它提供了一个形式参数的列表和一个体 - 一个表达式或块 - 用这些参数表示。

        LambdaExpressionLambdaParameters -&gt; LambdaBody

        任何使用但未在 lambda 表达式中声明的局部变量、形参或异常参数都必须声明为 final 或实际上是 final,否则在尝试使用时会发生编译时错误。

        Comparator<Employee> functional_semantics = (e1, e2) -> {
           return e1.getCreationTime().compareTo( e2.getCreationTime() );
        };
        

        支持 Lambda 的基本排序

        Comparator<Employee> timeCompareLambda = (o1, o2) -> (int) ( o1.getCreationTime() - o2.getCreationTime());
        Collections.sort(java8, timeCompareLambda );
        

        使用 Extracted Key 和 Comparing method通过提取的 key 进行比较的比较器。使用 :: 关键字传递引用。

        static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor)
        
        ToLongFunction<Employee> keyExtracor = Employee::getCreationTime;
        Comparator<Employee> byTime = Comparator.comparingLong( Employee::getCreationTime );
        

        示例测试代码:

        public class Lambda_Long_Comparator {
            public static void main(String[] args) {
        
                List<Employee> java7 = getEmployees();
        
                // Sort with Inner Class
                Comparator<Employee> timeCompare = new Comparator<Employee>() {
                    @Override public int compare(Employee e1, Employee e2) {
                        return e1.getCreationTime().compareTo( e2.getCreationTime() );
                    }
                };
        
                // Collections.sort(list); // Defaults to Comparable<T> « @compareTo(o1)
                Collections.sort(java7, timeCompare); // Comparator<T> « @compare (o1,o2)
                System.out.println("Java < 8 \n"+ java7);
        
                List<Employee> java8 = getEmployees();
                Collections.sort(java8, Comparator
                        .comparing( Employee::getCreationTime )
                        .thenComparing( Employee::getName ));
                //java8.forEach((emp)-> System.out.println(emp));
                System.out.println("Java 8 \n"+java8);
            }
        
            static List<Employee> getEmployees() {
                Date date = Calendar.getInstance().getTime();
                List<Employee> list = new ArrayList<Employee>();
                list.add( new Employee(4, "Yash", date.getTime()+7));
                list.add( new Employee(2, "Raju", date.getTime()+1));
                list.add( new Employee(4, "Yas", date.getTime()));
                list.add( new Employee(7, "Sam", date.getTime()-4));
                list.add( new Employee(8, "John", date.getTime()));
                return list;
            }
        }
        class Employee implements Comparable<Employee> {
            Integer id;
            String name;
            Long creationTime;
        
            public Employee(Integer id, String name, Long creationTime) {
                this.id = id;
                this.name = name;
                this.creationTime = creationTime;
            }
        
            @Override public int compareTo(Employee e) {
                return this.id.compareTo(e.id);
            }
        
            @Override public String toString() {
                return "\n["+this.id+","+this.name+","+this.creationTime+"]";
            }
        
            // Other getter and setter methods
        }
        

        还可以查看这些帖子:

        【讨论】:

          【解决方案5】:

          你应该改变

           messagesByDeviceType.sort(
               (Message o1, Message o2) -> o1.getTime() - o2.getTime()
           );
          

          messagesByDeviceType.sort(
              Comparator.comparing((Message m) -> m.getTime())
          );
          

          假设值为Comparable,它提供了自然的排序顺序。

          如果您想添加更多字段,则可以将它们链接到比较器。例如先按时间排序,然后按发件人:

          messagesByDeviceType.sort(
              Comparator
                  .comparing((Message m) -> m.getTime())
                  .thenComparing((m)     -> m.getSender())
          );
          

          要反转任何Comparator 的顺序,请将reveresed() 方法链接到它,例如先按时间降序排序,然后按发件人:

          messagesByDeviceType.sort(
              Comparator
                  .comparing((Message m) -> m.getTime())
                  .reversed()
                  .thenComparing((m)     -> m.getSender())
          );
          

          另见https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html

          【讨论】:

            【解决方案6】:

            compare() 方法必须返回 int,而您的方法似乎返回 long

            你可以把它改成:

            Long.compare(o1.getTime(),o2.getTime())
            

            在下面的视频link 中很好地解释了 lambda 比较器。

            【讨论】:

              【解决方案7】:

              lamda 比较器

              In the place of Developer write your class name 
              
                  Comparator<Developer> byName = 
                      (Developer o1, Developer o2)->o1.getName().compareTo(o2.getName());
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-11-02
                • 1970-01-01
                • 1970-01-01
                • 2023-03-09
                • 1970-01-01
                • 2015-10-11
                • 2016-01-04
                相关资源
                最近更新 更多