2016-09-15 1 views
2

J'ai un objet Employee qui contient deux champs name et jobTitle. Pour trier les objets employés, la première priorité devrait être jobTitle, si jobTitle est nulle alors le tri doit être basé sur le nom.Comparateur basé sur différents champs NULL d'un objet

Ci-dessous est l'objet employé

public class Employee { 
    private String name; 
    private String jobTitle; 
} 

J'ai utilisé enchaînée Comparator avec JobTitlecomparator et NameComparator pour y parvenir:

public class EmployeeChainedComparator implements Comparator<Employee> { 

    private List<Comparator<Employee>> listComparators; 

    @SafeVarargs 
    public EmployeeChainedComparator(Comparator<Employee>... comparators) { 
     this.listComparators = Arrays.asList(comparators); 
    } 

    @Override 
    public int compare(Employee emp1, Employee emp2) { 
     for (Comparator<Employee> comparator : listComparators) { 
      int result = comparator.compare(emp1, emp2); 
      if (result != 0) { 
       return result; 
      } 
     } 
     return 0; 
    } 
} 

public class EmployeeJobTitleComparator implements Comparator<Employee> { 

    @Override 
    public int compare(Employee emp1, Employee emp2) { 
     if(emp1.getJobTitle() != null && emp2.getJobTitle() != null){ 
      return emp1.getJobTitle().compareTo(emp2.getJobTitle()); 
     } else { 
      return 0; 
     } 
    } 
} 

public class EmployeeNameComparator implements Comparator<Employee> { 

    @Override 
    public int compare(Employee emp1, Employee emp2) { 
     return emp1.getName().compareTo(emp2.getName()); 
    } 
} 

public class SortingMultipleAttributesExample { 
    public static void main(String[] args) { 
     List<Employee> listEmployees = new ArrayList<Employee>(); 
     listEmployees.add(new Employee("Tom", "Developer")); 
     listEmployees.add(new Employee("Sam", null)); 
     listEmployees.add(new Employee("Tim", "Designer")); 
     listEmployees.add(new Employee("Bob", null)); 
     listEmployees.add(new Employee("Peter", null)); 
     listEmployees.add(new Employee("Craig", "Programmer")); 

     Collections.sort(listEmployees, new EmployeeChainedComparator(new EmployeeJobTitleComparator(), new EmployeeNameComparator() 
       )); 

     for(Employee emp : listEmployees){ 
      System.out.println("Employee Job: "+emp.getJobTitle()+" Employee Name: "+emp.getName()); 
     } 
    } 
} 

Maintenant, je devrais obtenir la sortie comme celui-ci

Employee Job: Designer Employee Name: Tim 
Employee Job: Developer Employee Name: Tom 
Employee Job: Programmer Employee Name: Craig 
Employee Job: null Employee Name: Bob 
Employee Job: null Employee Name: Peter 
Employee Job null Employee Name: Sam 

Mais je n'obtiens pas le résultat escompté comme je m'y attendais. Je reçois la sortie comme ceci

Employee Job Developer Employee Name Tom 
Employee Job null Employee Name Sam 
Employee Job Designer Employee Name Tim 
Employee Job null Employee Name Bob 
Employee Job null Employee Name Peter 
Employee Job Programmer Employee Name Craig 

Quelqu'un peut-il m'aider sur la façon d'y parvenir?

+0

Quel résultat avez-vous obtenu? – Eran

+0

Obtenir la sortie comme ce nom d'emploi employé développeur employé Tom null Nom employé Profession employé Sam Employé Job Designer Nom de l'employé Tim null employé du poste Nom de l'employé Bob null Nom de l'employé employé du poste Peter employé Nom du poste programmeur employé Craig – Digital

+0

Je ne sais pas si c'est tout le problème, mais appeler le constructeur de 'EmployeeChainedComparator' ne fait que passer' EmployeeJobTitleComparator'. Essayez d'ajouter 'EmployeeNameComparator' afin qu'il soit inclus dans la liste. –

Répondre

2

Si soit des titres est null, les deux Employee s évalueront d'égal à égal, même si l'un d'entre eux est non nul. Ce n'est pas ce que tu veux. Vous voulez que tous les titres null soient égaux entre eux, mais pas des valeurs non nulles.

Remplacez votre méthode comparer avec ceci:

public int compare(Employee emp1, Employee emp2) { 
    if(emp1.getJobTitle() == null && emp2.getJobTitle() == null){ 
     return 0; 
    } 
    if(emp1.getJobTitle() == null) return 1; 
    if(emp2.getJobTitle() == null) return -1; 
    return emp1.getJobTitle().compareTo(emp2.getJobTitle()); 
} 

et vous devriez obtenir les résultats que vous attendez.

+0

Merci @resueman J'ai obtenu la sortie attendue avec le code ci-dessus – Digital

6

Puisque vous utilisez Java 8, vous pouvez utiliser les fonctions de comparaison intégrées au lieu de créer vos propres comparateurs. En comparant le titre du poste et le nom peut se faire facilement avec

Comparator<Employee> comparator = 
    Comparator.comparing(Employee::getJobTitle).thenComparing(Employee:getName); 

Comment gérer null valeurs est également intégré avec les méthodes nullsLast et nullsFirst. Ces méthodes enveloppent un comparateur existant dans un comparateur sûr null, en mettant null valeurs à la fin ou au début.

En tant que tel, vous pouvez:

import static java.util.Comparator.comparing; 
import static java.util.Comparator.naturalOrder; 
import static java.util.Comparator.nullsLast; 

// ... 

Comparator<Employee> comparator = 
    comparing(Employee::getJobTitle, nullsLast(naturalOrder())).thenComparing(Employee::getName); 

Collections.sort(listEmployees, comparator); 

Le comparateur est créé par comparing les titres d'emploi avec un null comparateur sûr mettre null les dernières valeurs (see also). Pour les titres égaux, c'est thenComparing le nom des employés.