本篇文章將介紹使用Java 8 Lambda 進行排序。一般來說專案中要做排序,通常是由儲存資料的部分來進行,比如資料庫。但是,剛好沒有資料庫來幫忙做排序,就只能用程式的方式來進行。因為接到的專案,資料來源是JSON,而API又不排序,只能取得JSON資料後,自己來進行排序了。所以,將JSON中的資料,轉成Java的物件,在依照指定的屬性,進行排序。
先來定義Java物件:
public class Menu {
private String name;
private int no;
// 其他的建構子getters/setters, equals and hashcode 就不寫了
}
不使用 Lambda 的排序方式
在Java 8 之前要做排序,可以建立一個匿名類別並且實作Comparator 介面:
new Comparator<Menu>() {
@Override
public int compare(Menu m1, Menu m2) {
return m1.getName().compareTo(m2.getName());
}
}
上面的匿名類別,依照name進行排序。
public static void main(String args[]){
List<Menu> menus = Lists.newArrayList(
new Menu("HomePage", 12),
new Menu("About US", 10)
);
Collections.sort(menus , new Comparator<Menu>() {
@Override
public int compare(Menu m1, Menu m2) {
return m1.getName().compareTo(m2.getName());
}
});
System.out.println(menus.get(0).getName());
}
使用 Lambda 進行簡單的排序
這邊會使用到 Java 8 新的 java.util.List 排序功能。
(final Menu m1, final Menu m2) -> m1.getName().compareTo(m2.getName());
public static void main(String args[]){
List<Menu> menus = Lists.newArrayList(
new Menu("HomePage", 12),
new Menu("About US", 10)
);
menus.sort((Menu m1,Menu m2) -> m1.getName().compareTo(m2.getName()));
System.out.println(menus.get(0).getName());
}
接下來,排序的時候,不要宣告類別
這次把宣告 Menu 的部分拿掉,只留下變數名稱。
(m1, m2) -> m1.getName().compareTo(m2.getName())
public static void main(String args[]){
List<Menu> menus = Lists.newArrayList(
new Menu("HomePage", 12),
new Menu("About US", 10)
);
menus.sort((m1, m2) -> m1.getName().compareTo(m2.getName()));
System.out.println(menus.get(0).getName());
}
使用自己定義的static method 進行排序
換另外一個方法,在 Menu 物件中增加一個 static mathod 如下:
public static int compareByNameAndNo(Menu m1, Menu m2) {
if (m1.getName().equals(m2.getName())) {
return Integer.compare(m1.getNo(), m2.getNo());
} else {
return m1.getName().compareTo(m2.getName());
}
}
排序的地方,改成呼叫 static method
menus.sort(Menu::compareByNameAndNo);
如下:
public static void main(String args[]){
List<Menu> menus = Lists.newArrayList(
new Menu("HomePage", 12),
new Menu("About US", 10)
);
menus.sort(Menu::compareByNameAndNo);
System.out.println(menus.get(0).getName());
}
改用元件本來就有method 進行排序(instance method)
這次我們會使用到 Comparator.comparing來進行排序。
public static void main(String args[]){
List<Menu> menus = Lists.newArrayList(
new Menu("HomePage", 12),
new Menu("About US", 10)
);
Collections.sort(
menus , Comparator.comparing(Menu::getName));
System.out.println(menus.get(0).getName());
}
反向排序
Java 8 comparator 有提供反向排序的功能。如下:
public static void main(String args[]){
List<Menu> menus = Lists.newArrayList(
new Menu("HomePage", 12),
new Menu("About US", 10)
);
Comparator<Menu> comparator
= (m1, m2) -> m1.getName().compareTo(m2.getName());
menus.sort(comparator.reversed());
System.out.println(menus.get(0).getName());
}
多個不同條件進行排序
可以在排序的method中增加多個if 判斷式,比如:先進行name排序,再進行no排序。
public static void main(String args[]){
List<Menu> menus = Lists.newArrayList(
new Menu("HomePage", 12),
new Menu("About US", 10)
);
menus.sort((m1, m2) ->{
if (m1.getName().equals(m2.getName())) {
return Integer.compare(m1.getNo(), m2.getNo());
} else {
return m1.getName().compareTo(m2.getName());
}
});
System.out.println(menus.get(0).getName());
}
使用 comparators 進行多個條件排序
Java 8中可以使用鏈結的方式,做到多種條件的排序,如下:
public static void main(String args[]){
List<Menu> menus = Lists.newArrayList(
new Menu("HomePage", 12),
new Menu("About US", 10)
);
menus.sort(
Comparator.comparing(Menu::getName).thenComparing(Menu::getNo)
);
System.out.println(menus.get(0).getName());
}
使用Stream.sorted() 對 List 進行排序
我們也可以使用 Java 8 的 Stream sorted() API.來對List做排序。
有兩個選項:
- sorted() –自然排序,前提必須要實作Comparable 介面。
- sorted(Comparator<? super T> comparator) –針對 Comparable 的設定進行排序。
public static void main(String args[]){
List<Menu> menus = Lists.newArrayList(
new Menu("HomePage", 12),
new Menu("About US", 10)
);
Comparator<Menu> nameComparator = (m1, m2) -> m1.getName().compareTo(m2.getName());
List<Menu> sortedMenus =
menus.stream().sorted(nameComparator).collect(Collectors.toList());
System.out.println(sortedMenus .get(0).getName());
}
也可以使用Comparator.comparing() 來簡化程式碼。
public static void main(String args[]){
List<Menu> menus = Lists.newArrayList(
new Menu("HomePage", 12),
new Menu("About US", 10)
);
List<Menu> sortedMenus = menus .stream()
.sorted(Comparator.comparing(Menu::getName))
.collect(Collectors.toList());
System.out.println(sortedMenus .get(0).getName());
}
使用 Stream.sorted()進行反向排序
首先,我們使用Comparator.reverseOrder() 進行反向排序。
public static void main(String args[]){
List<String> words= Lists.newArrayList("B", "A", "C");
List<String> reverseWords = words.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
System.out.println(reverseWords);
}
你可以在 Comparator把排序的邏輯顛倒就能達到反向排序的效果。
public static void main(String args[]){
List<Menu> menus = Lists.newArrayList(
new Menu("HomePage", 12),
new Menu("About US", 10)
);
Comparator<Menu> nameComparator = (m1, m2) -> m2.getName().compareTo(m1.getName());
List<Menu> sortedMenus =
menus.stream().sorted(nameComparator).collect(Collectors.toList());
System.out.println(sortedMenus .get(0).getName());
}
接著,我們來看一下怎麼使用 Comparator.comparing() 進行反向排序
public static void main(String args[]){
List<Menu> menus = Lists.newArrayList(
new Menu("HomePage", 12),
new Menu("About US", 10)
);
List<Menu> reverseSortedMenus = menus.stream()
.sorted(Comparator.comparing(Menu::getName, Comparator.reverseOrder()))
.collect(Collectors.toList());
System.out.println(reverseSortedMenus.get(0).getName());
}
碰到Null物件怎麼辦
上面的方式,一旦碰到List當中有 null,就會發生錯誤-NullPointerException。
當然,簡單的方法就是在比較之前,先針對兩個變數,判斷是否為 null。
比如:
if (m1 == null) {
return m2 == null ? 0 : 1;
} else if (m2 == null) {
return -1;
}
不過,你也可以使用 Comparator.nullsLast() 將null 擺到List的最後方,或是 nullsFirst() 將null 擺到List的最前方。
public static void main(String args[]){
List<Menu> menus = Lists.newArrayList(
new Menu("HomePage", 12),
new Menu("About US", 10)
);
menus .sort(Comparator.nullsFirst(Comparator.comparing(Menu::getName)));
System.out.println(menus );
}
nullsLast(java.util.Comparator)方法返回Comparator,該Comparator是對null友好的Comparator。空值首先通過以下邏輯進行操作:
- null元素被認為大於非null。
- 當兩個元素都為空時,則認為它們相等。
- 當兩個元素都不為空時,指定的Comparator確定順序。
- 如果指定的Comparator為null,則返回的Comparator將所有非null元素視為相等。
- 如果指定的Comparator可序列化,則返回的Comparator可序列化。
nullsFirst(java.util.Comparator)方法返回Comparator,該Comparator是對null友好的Comparator。空值首先通過以下邏輯進行操作:
- null元素被認為小於non-null。
- 當兩個元素都為空時,則認為它們相等。
- 當兩個元素都不為空時,指定的Comparator確定順序。
- 如果指定的Comparator為null,則返回的Comparator將所有非null元素視為相等。
- 如果指定的Comparator可序列化,則返回的Comparator可序列化。
歡迎轉載本文章,請註明出處。
https://javainsoft.com/advanced/java-8-sort-lambda