web-dev-qa-db-fra.com

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

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

Ce serait plus gentil d'écrire comme ça:

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

La méthode Comparatorcompare() doit renvoyer un int, et il semble que la vôtre renvoie un long.

Vous pouvez le changer pour:

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

Ceci suppose (en fonction de votre message d'erreur) que o1.getTime() renvoie un long.

21
Eran

Lambda

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

Version Java8:

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

Version antérieure à 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 bon lambda, vous pouvez essayer d'écrire une version pré-lambda et voir en quoi c'est faux.

Application

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

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

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

Remarquer

  • Vous devriez éviter d'utiliser - in Comparator, ce qui peut provoquer un débordement dans certains cas et faire planter votre programme.
19
Tony

Comparateur

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

int compare(T o1, T o2);

il faut deux arguments pour commander. Retourne 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 versions antérieures de Java 8 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 finales ou 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 méthode de comparaison

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 soit déclaré final, soit être réellement final, sinon une erreur de compilation survient lors de la tentative d'utilisation.

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 comparant une clé extraite. Passer des références en utilisant :: 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 ces articles aussi:

7
Yash

Tu devrais 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 souhaitez ajouter plus de champs, vous pouvez les chaîner au comparateur. par exemple. 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 toute méthode Comparator, enchaînez la méthode reveresed(), par ex. trier d'abord par heure décroissante, 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

3
isapir

La méthode compare() doit renvoyer un int, et il semble que le vôtre renvoie un long.

Vous pouvez le changer en ceci:

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

Bien expliqué en ce qui concerne le comparateur lambda dans la vidéo présentée ci-dessous lien .

0
Raj