60 votes

Java 8 Lambda : Comparateur

Je veux trier une liste avec Lambda :

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

Mais j'ai eu cette erreur de compilation :

 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) 
     -> {})

90voto

Eugene Points 6271

Comparator#compareTo renvoie un int ; tandis que getTime est évidemment long .

Ce serait plus joli écrit comme ça :

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

36voto

Tony Points 3371

Lambda

Le lambda peut être vu comme le raccourci d'une classe anonyme quelque peu encombrante :

Version Java8 :

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

Version pré-Java8 :

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

Ainsi, chaque fois que vous ne savez pas comment écrire un lambda correct, vous pouvez essayer d'écrire une version pré-lambda, et voir en quoi elle est fausse.

Application

Dans votre problème spécifique, vous pouvez voir le compare renvoie à int où votre getTime retourne un long, ce qui est la source de l'erreur.

Vous pouvez utiliser l'une ou l'autre méthode comme autre méthode de réponse, par exemple :

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

Avis

  • Vous devez éviter d'utiliser - sur Comparator ce qui peut provoquer un dépassement de capacité, dans certains cas, et faire planter votre programme.

24voto

Eran Points 35360

El Comparator 's compare() doit retourner un int et il semble que le vôtre renvoie un long .

Vous pouvez le changer en :

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

Cela suppose (d'après votre message d'erreur) que o1.getTime() renvoie un long .

0 votes

Je pense qu'ils peuvent utiliser directement la méthode de comparaison longue comme o1.getTime().compareTo(o1.getTime()). car la classe wrapper Long a implémenté l'interface Comparable.

16voto

Yash Points 4565

Comparateur

Nous utilisons l'interface du comparateur pour trier les éléments homogènes et hétérogènes pour un ordre de tri par défaut ou personnalisé.

int compare(T o1, T o2);

il prend deux arguments pour la commande. Elle renvoie un

    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.

Classes anonymes comment trier une liste d'objets dans les versions antérieures de Java 8 en utilisant des classes internes.

Une classe anonyme ne peut pas accéder aux variables locales de sa portée englobante qui ne sont pas déclarées comme finales ou effectivement finales.

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

Java 8 Lambda Expressions uing comparer la méthode

Une expression lambda est comme une méthode : elle fournit une liste de paramètres formels et un corps - une expression ou un bloc - exprimé en fonction de ces paramètres.

LambdaExpression : LambdaParameters -> LambdaBody

Toute variable locale, paramètre formel ou paramètre d'exception utilisé mais non déclaré dans une expression lambda doit être déclaré final ou être effectivement final, ou une erreur de compilation se produit lorsque l'utilisation est tentée.

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

Tri de base avec support Lambda

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

Utilisation de Clé extraite et Méthode de comparaison : Un comparateur qui compare par une clé extraite. Passez les références en utilisant le mot-clé : :.

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

Exemple de code de test :

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
}

Voir aussi ces articles :

4voto

Igal Points 836

Vous devriez changer

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

à

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

Cela suppose que la valeur est Comparable ce qui fournit un ordre de tri naturel.

Si vous voulez ajouter d'autres champs, vous pouvez les enchaîner au comparateur. Par exemple, pour trier d'abord par heure, puis par expéditeur :

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

Pour inverser l'ordre de n'importe quel Comparator la chaîne le reveresed() pour, par exemple, trier d'abord par heure en ordre décroissant, puis par expéditeur :

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

Voir aussi https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X