国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

JDK8新特性:使用stream、Comparator和Method Reference實(shí)現(xiàn)集合的優(yōu)雅排序

2019-11-14 10:01:45
字體:
供稿:網(wǎng)友

大家對java接口Comparator和Comparable都不陌生,JDK8里面Comparable還和以前一樣,沒有什么改動(dòng);但是Comparator在之前基礎(chǔ)上增加了很多static和default方法。本文主要結(jié)合JDK的stream編程,學(xué)習(xí)下Comparator。閱讀本文需要一些前置知識(shí),可以參考如下文章。

JDK8新特性:接口的靜態(tài)方法和默認(rèn)方法http://blog.csdn.net/aitangyong/article/details/54134385

JDK8新特性:函數(shù)式接口@FunctionalInterface的使用說明

http://blog.csdn.net/aitangyong/article/details/54137067

JDK8新特性:lambda入門http://blog.csdn.net/aitangyong/article/details/54317539JDK8新特性:使用Method References實(shí)現(xiàn)方法復(fù)用,簡化lambda表達(dá)式http://blog.csdn.net/aitangyong/article/details/54586197

可以使用Stream.sort對集合進(jìn)行排序,sort有2個(gè)重載方法,區(qū)別如下。

// Student實(shí)現(xiàn)Comparable接口,默認(rèn)按照id升序排列public class Student implements Comparable<Student>{	PRivate int id;	private int age;	private String name;	private Address address;	public Student(int id, int age, String name, Address address) {		this.id = id;		this.age = age;		this.name = name;		this.address = address;	}	public int getId() {		return id;	}	public void setId(int id) {		this.id = id;	}	public int getAge() {		return age;	}	public void setAge(int age) {		this.age = age;	}	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}	public Address getAddress() {		return address;	}	public void setAddress(Address address) {		this.address = address;	}	@Override	public String toString() {		return "Student [id=" + id + ", age=" + age + ", name=" + name + ", address=" + address + "]";	}	@Override	public int compareTo(Student o) {		return this.id - o.id;	}}

stream().sorted()/Comparator.naturalOrder()/Comparator.reverSEOrder(),要求元素必須實(shí)現(xiàn)Comparable接口。
import java.util.ArrayList;import java.util.Comparator;import java.util.List;import java.util.stream.Collectors;public class TestComparator {	public static void main(String[] args) {		List<Student> students = buildStudents();				// 按照默認(rèn)順序排序		List<Student> ascList1 = students.stream().sorted().collect(Collectors.toList());		System.out.println(ascList1);				// 按照自然序排序(其實(shí)就是默認(rèn)順序)		List<Student> ascList2 = students.stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList());		System.out.println(ascList2);				// 按照默認(rèn)順序的相反順序排序		List<Student> descList = students.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());		System.out.println(descList);	}	private static List<Student> buildStudents() {		List<Student> students = new ArrayList<>();		students.add(new Student(10, 20, "aty", new Address("d")));		students.add(new Student(1, 22, "qun", new Address("c")));		students.add(new Student(1, 26, "Zen", new Address("b")));		students.add(new Student(5, 23, "aty", new Address("a")));		return students;	}}如果Student沒有實(shí)現(xiàn)Comparable接口,效果如下:

接下來測試,都不要求Student實(shí)現(xiàn)Comparable接口,這里直接給出Student和Address實(shí)體類。

public class Student {	private int id;	private int age;	private String name;	private Address address;	public Student(int id, int age, String name, Address address) {		this.id = id;		this.age = age;		this.name = name;		this.address = address;	}	public int getId() {		return id;	}	public void setId(int id) {		this.id = id;	}	public int getAge() {		return age;	}	public void setAge(int age) {		this.age = age;	}	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}	public Address getAddress() {		return address;	}	public void setAddress(Address address) {		this.address = address;	}	@Override	public String toString() {		return "Student [id=" + id + ", age=" + age + ", name=" + name + ", address=" + address + "]";	}}
public class Address {	private String address;	public Address(String address) {		super();		this.address = address;	}	public String getAddress() {		return address;	}	public void setAddress(String address) {		this.address = address;	}	@Override	public String toString() {		return "Address [address=" + address + "]";	}	}

Comparator.comparing(Function keyExtractor)生成1個(gè)Comparator對象,要求keyExtractor.apply()返回值一定要實(shí)現(xiàn)Comparable接口。比如下面代碼extractIdWay1和extractIdWay2都是等價(jià)的,從Student對象中提取id屬性,而id是int類型(Integer實(shí)現(xiàn)了Comparable)。
import java.util.ArrayList;import java.util.Comparator;import java.util.List;import java.util.function.Function;import java.util.stream.Collectors;public class TestComparator {	public static void main(String[] args) {		List<Student> students = buildStudents();		// 使用lambda表達(dá)式創(chuàng)建Function對象		Function<Student, Integer> extractIdWay1 = (student) -> student.getId();				// 使用方法引用簡化lambda		Function<Student, Integer> extractIdWay2 = Student::getId;				// Comparator.comparing(Function keyExtractor)		Comparator<Student> byId = Comparator.comparing(extractIdWay2);				// 升序		List<Student> ascList = students.stream().sorted(byId).collect(Collectors.toList());		System.out.println(ascList);				// 降序		List<Student> descList = students.stream().sorted(byId.reversed()).collect(Collectors.toList());		System.out.println(descList);	}	private static List<Student> buildStudents() {		List<Student> students = new ArrayList<>();		students.add(new Student(10, 20, "aty", new Address("d")));		students.add(new Student(1, 22, "qun", new Address("c")));		students.add(new Student(1, 26, "Zen", new Address("b")));		students.add(new Student(5, 23, "aty", new Address("a")));		return students;	}}

由于Student.getAddress()返回的對象沒有實(shí)現(xiàn)Comparable接口,所以不能通過Comparator.comparing()創(chuàng)建一個(gè)Comparator對象。

如果我們想安裝Address(沒有實(shí)現(xiàn)Comparable接口)排序怎么辦呢?使用另一種形式的comparing方法:

import java.util.ArrayList;import java.util.Comparator;import java.util.List;import java.util.stream.Collectors;public class TestComparator {	public static void main(String[] args) {		List<Student> students = buildStudents();		Comparator<Address> cmpAddr = Comparator.comparing(Address::getAddress);		Comparator<Student> byAddress = Comparator.comparing(Student::getAddress, cmpAddr);		List<Student> sortedAddressList = students.stream().sorted(byAddress).collect(Collectors.toList());		System.out.println(sortedAddressList);	}	private static List<Student> buildStudents() {		List<Student> students = new ArrayList<>();		students.add(new Student(10, 20, "aty", new Address("d")));		students.add(new Student(1, 22, "qun", new Address("c")));		students.add(new Student(1, 26, "Zen", new Address("b")));		students.add(new Student(5, 23, "aty", new Address("a")));		return students;	}}

這種形式的comparing()接收2個(gè)參數(shù),第一個(gè)參數(shù)提取要排序的key,第二個(gè)參數(shù)指定排序的Comparator。自己指定比較器,可以靈活定制比較邏輯。比如,我們想實(shí)現(xiàn)字符串不區(qū)分大小寫比較。
//getName()返回String本身已經(jīng)實(shí)現(xiàn)了Comparable,但是我們可以自己傳遞一個(gè)不區(qū)分大小寫的比較器Comparator<Student> byName = Comparator.comparing(Student::getName, String.CASE_INSENSITIVE_ORDER);List<Student> sortedNameList = students.stream().sorted(byName).collect(Collectors.toList());System.out.println(sortedNameList);comparingDouble()、comparingLong()、comparingInt()不過是comparing()更具體的版本,使用方式相同。
public static void main(String[] args) {	List<Student> students = buildStudents();	Comparator<Student> byAge1 = Comparator.comparingInt(Student::getAge);	Comparator<Student> byAge2 = Comparator.comparing(Student::getAge);	List<Student> sortedAgeList1 = students.stream().sorted(byAge1).collect(Collectors.toList());	List<Student> sortedAgeList2 = students.stream().sorted(byAge2).collect(Collectors.toList());	System.out.println(sortedAgeList1);	System.out.println(sortedAgeList2);}private static List<Student> buildStudents() {	List<Student> students = new ArrayList<>();	students.add(new Student(10, 20, "aty", new Address("d")));	students.add(new Student(1, 22, "qun", new Address("c")));	students.add(new Student(1, 26, "Zen", new Address("b")));	students.add(new Student(5, 23, "aty", new Address("a")));	return students;}Comparator.nullsFirst()和Comparator.nullsLast(),前面我們創(chuàng)建的Student列表中沒有null,如果有null的話,上面的代碼都會(huì)拋異常。而這2個(gè)方法就是用來處理null的,一個(gè)認(rèn)為null比所有非null都小,一個(gè)認(rèn)為比所有都大。
public class TestComparator {	public static void main(String[] args) {		List<Student> students = buildStudents();		Comparator<Student> nullNotAllowed = Comparator.comparing(Student::getId);		Comparator<Student> allowNullComparator = Comparator.nullsFirst(nullNotAllowed);				// 正常排序		List<Student> result1 = students.stream().sorted(allowNullComparator).collect(Collectors.toList());		System.out.println(result1);				// 拋異常		List<Student> result2 = students.stream().sorted(nullNotAllowed).collect(Collectors.toList());		System.out.println(result2);	}	private static List<Student> buildStudents() {		List<Student> students = new ArrayList<>();		students.add(new Student(10, 20, "aty", new Address("d")));		students.add(new Student(1, 22, "qun", new Address("c")));		students.add(new Student(1, 26, "Zen", new Address("b")));		students.add(new Student(5, 23, "aty", new Address("a")));		students.add(null);		return students;	}}至此Comparator的static方法已經(jīng)介紹完畢,接下來我們看下它的default方法。

reversed()前面已經(jīng)介紹了,返回一個(gè)新的比較器(排序順序相反)

thenComparing()系列方法與comparing()使用方法類似

如果我們先按照id排序,id相等的話再按照name排序,那么可以這樣寫。

public static void main(String[] args) {	List<Student> students = buildStudents();		// id升序	Comparator<Student> byIdASC = Comparator.comparing(Student::getId);		// named不分區(qū)大小寫降序	Comparator<Student> byNameDESC = Comparator.comparing(Student::getName, String.CASE_INSENSITIVE_ORDER)			.reversed();	// 聯(lián)合排序	Comparator<Student> finalComparator = byIdASC.thenComparing(byNameDESC);		List<Student> result = students.stream().sorted(finalComparator).collect(Collectors.toList());	System.out.println(result);}private static List<Student> buildStudents() {	List<Student> students = new ArrayList<>();	students.add(new Student(10, 20, "aty", new Address("d")));	students.add(new Student(1, 22, "qun", new Address("c")));	students.add(new Student(1, 26, "Zen", new Address("b")));	students.add(new Student(5, 23, "aty", new Address("a")));	return students;}


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 屏南县| 岳阳市| 临汾市| 米脂县| 江城| 铁力市| 讷河市| 新乡县| 亚东县| 垫江县| 加查县| 丰镇市| 汾西县| 施秉县| 犍为县| 保靖县| 泗阳县| 德令哈市| 沈阳市| 个旧市| 丹东市| 大化| 勃利县| 北宁市| 台中市| 宝清县| 湾仔区| 宣武区| 奇台县| 双鸭山市| 尤溪县| 保德县| 扶余县| 湾仔区| 阆中市| 洛隆县| 台江县| 北碚区| 鄢陵县| 太仓市| 康保县|