Java Comparator Interface - Java 147

Java Comparator Interface – Java 147

Java Comparator Interface

常用於集合或陣列比較元素,也可當作其他方法的傳入參數或是引用其他方法為實例, Comparator Interface 介紹 compare 、 thenComparing 、 reversed 等方法,了解 Comparator 的不同操作和方法,本篇增加了範例,並透過單元測試來驗證產出結果。

o1 大於 o2 傳回 1 。
o1 等於 o2 傳回 0 。
o1 小於 o2 傳回 -1 。

@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);
} 

檔案目錄

./
   +- src
       +- test
       |   +- org
       |       +- ruoxue
       |           +- java_147
       |               +- comparator
       |                   +- ComparatorInterfaceTest.java   

單元測試

Comparator Interface Java 提供 compare 、 thenComparing 、 reversed 等方法操作 Comparator Interface 。

Fruit

Comparator Interface Java 建立 Fruit 類別,覆寫 equals 、 hashCode ,定義屬性和方法,用來建立一個物件。

	@NoArgsConstructor
	@Getter
	@Setter
	@Builder
	public static class Fruit {
		private String name;
		private double quantity;
		private int type;

		public Fruit(String name, double quantity, int type) {
			this.name = name;
			this.quantity = quantity;
			this.type = type;
		}

		public String toString() {
			ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.JSON_STYLE);
			builder.appendSuper(super.toString());
			builder.append("name", name);
			builder.append("quantity", quantity);
			builder.append("type", type);
			return builder.toString();
		}

		public boolean equals(Object object) {
			if (!(object instanceof Fruit)) {
				return false;
			}
			if (this == object) {
				return true;
			}
			Fruit other = (Fruit) object;
			return new EqualsBuilder().append(getName(), other.getName()).isEquals();
		}

		public int hashCode() {
			return new HashCodeBuilder().append(getName()).toHashCode();
		}
	}

traditional

Comparator Interface Java 使用傳統方式,實作 Comparator 接口,比對字串或數字,由小到大排序。

	public static Comparator<Fruit> nameComparator = new Comparator<Fruit>() {
		@Override
		public int compare(Fruit o1, Fruit o2) {
			return o1.name.compareTo(o2.name);
		}
	};

	@Test
	public void traditional() {
		List<Fruit> list = Arrays.asList(new Fruit("Mango", 1, 1), new Fruit("Peach", 3, 1), new Fruit("Orange", 2, 1));
		System.out.println(list);

		Collections.sort(list, nameComparator);
		System.out.println(list);
		assertEquals("Mango", list.get(0).getName());
		assertEquals("Orange", list.get(1).getName());
		assertEquals("Peach", list.get(2).getName());
	}
[{"name":"Mango","quantity":1.0,"type":1}, {"name":"Peach","quantity":3.0,"type":1}, {"name":"Orange","quantity":2.0,"type":1}]
[{"name":"Mango","quantity":1.0,"type":1}, {"name":"Orange","quantity":2.0,"type":1}, {"name":"Peach","quantity":3.0,"type":1}]

compare

Comparator Interface Java 建立集合及陣列,比對字串或數字,由小到大排序。

	@Test
	public void compare() {
		List<Fruit> list = Arrays.asList(new Fruit("Mango", Double.MAX_VALUE, 1), new Fruit("Peach", -1d, 1),
				new Fruit("Orange", 2, 1));
		System.out.println(list);

		Comparator<Fruit> quantityComparator = (o, o2) -> Double.compare(o.quantity, o2.quantity);
		Collections.sort(list, quantityComparator);
		System.out.println(list);
		assertEquals("Peach", list.get(0).getName());
		assertEquals("Orange", list.get(1).getName());
		assertEquals("Mango", list.get(2).getName());
	}
[{"name":"Mango","quantity":1.7976931348623157E308,"type":1}, {"name":"Peach","quantity":-1.0,"type":1}, {"name":"Orange","quantity":2.0,"type":1}]
[{"name":"Peach","quantity":-1.0,"type":1}, {"name":"Orange","quantity":2.0,"type":1}, {"name":"Mango","quantity":1.7976931348623157E308,"type":1}]

reversed

Comparator Interface in Java 建立集合及陣列,比對字串或數字,由大到小排序。

	@Test
	public void reversed() {
		List<Fruit> list = Arrays.asList(new Fruit("Mango", 1, 1), new Fruit("Peach", 3, 1), new Fruit("Orange", 2, 1));
		System.out.println(list);

		Comparator<Fruit> lengthComparator = (o, o2) -> Integer.compare(o.name.length(), o2.name.length());
		Collections.sort(list, lengthComparator.reversed());
		System.out.println(list);
		assertEquals("Orange", list.get(0).getName());
		assertEquals("Mango", list.get(1).getName());
		assertEquals("Peach", list.get(2).getName());
	}
[{"name":"Mango","quantity":1.0,"type":1}, {"name":"Peach","quantity":3.0,"type":1}, {"name":"Orange","quantity":2.0,"type":1}]
[{"name":"Orange","quantity":2.0,"type":1}, {"name":"Mango","quantity":1.0,"type":1}, {"name":"Peach","quantity":3.0,"type":1}]

thenComparing

Comparator Interface in Java 建立集合及陣列,使用 thenComparing 組合比對字串或數字,由小到大排序,其中若有例外拋出,將會中斷執行。

	@Test
	public void thenComparing() {
		List<Fruit> list = Arrays.asList(new Fruit("Mango", 1.2, 1), new Fruit("Peach", 1.1, 1),
				new Fruit("Orange", 2, 1));
		System.out.println(list);

		Comparator<Fruit> lengthComparator = (o, o2) -> Integer.compare(o.name.length(), o2.name.length());
		Comparator<Fruit> quantityComparator = (o, o2) -> Double.compare(o.quantity, o2.quantity);
		Collections.sort(list, lengthComparator.thenComparing(quantityComparator));
		System.out.println(list);
		assertEquals("Peach", list.get(0).getName());
		assertEquals("Mango", list.get(1).getName());
		assertEquals("Orange", list.get(2).getName());
	}
[{"name":"Mango","quantity":1.2,"type":1}, {"name":"Peach","quantity":1.1,"type":1}, {"name":"Orange","quantity":2.0,"type":1}]
[{"name":"Peach","quantity":1.1,"type":1}, {"name":"Mango","quantity":1.2,"type":1}, {"name":"Orange","quantity":2.0,"type":1}]

thenComparingWithKey

Comparator Interface in Java 建立集合及陣列,比對字串或數字,由小到大排序。

	@Test
	public void thenComparingWithKey() {
		List<Fruit> list = Arrays.asList(new Fruit("Mango", 1.2, 1), new Fruit("Peach", 1.1, 1),
				new Fruit("Orange", 2, 1));
		System.out.println(list);

		Comparator<Fruit> lengthComparator = (o, o2) -> Integer.compare(o.name.length(), o2.name.length());
		Collections.sort(list, lengthComparator.thenComparing(Fruit::getQuantity));
		System.out.println(list);
		assertEquals("Peach", list.get(0).getName());
		assertEquals("Mango", list.get(1).getName());
		assertEquals("Orange", list.get(2).getName());
	}
[{"name":"Mango","quantity":1.2,"type":1}, {"name":"Peach","quantity":1.1,"type":1}, {"name":"Orange","quantity":2.0,"type":1}]
[{"name":"Peach","quantity":1.1,"type":1}, {"name":"Mango","quantity":1.2,"type":1}, {"name":"Orange","quantity":2.0,"type":1}]

thenComparingWithKeyComparator

Comparator Interface in Java 建立集合及陣列,比對字串或數字,由小到大排序。

	@Test
	public void thenComparingWithKeyComparator() {
		List<Fruit> list = Arrays.asList(new Fruit("Mango", 1.2, 1), new Fruit("Peach", 1.1, 1),
				new Fruit("Orange", 2, 1));
		System.out.println(list);

		Comparator<Fruit> lengthComparator = (o, o2) -> Integer.compare(o.name.length(), o2.name.length());
		Comparator<Double> doubleCmparator = (d, d2) -> d.compareTo(d2);
		Collections.sort(list, lengthComparator.thenComparing(Fruit::getQuantity, doubleCmparator));
		System.out.println(list);
		assertEquals("Peach", list.get(0).getName());
		assertEquals("Mango", list.get(1).getName());
		assertEquals("Orange", list.get(2).getName());
	}
[{"name":"Mango","quantity":1.2,"type":1}, {"name":"Peach","quantity":1.1,"type":1}, {"name":"Orange","quantity":2.0,"type":1}]
[{"name":"Peach","quantity":1.1,"type":1}, {"name":"Mango","quantity":1.2,"type":1}, {"name":"Orange","quantity":2.0,"type":1}]

ComparatorInterfaceTest.java

Comparator Interface in Java 新增單元測試,驗證 Java Comparator Interface Example 是否符合預期。

package org.ruoxue.java_147.comparator;

import static org.junit.Assert.*;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.junit.Test;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

public class ComparatorInterfaceTest {

	@NoArgsConstructor
	@Getter
	@Setter
	@Builder
	public static class Fruit {
		private String name;
		private double quantity;
		private int type;

		public Fruit(String name, double quantity, int type) {
			this.name = name;
			this.quantity = quantity;
			this.type = type;
		}

		public String toString() {
			ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.JSON_STYLE);
			builder.appendSuper(super.toString());
			builder.append("name", name);
			builder.append("quantity", quantity);
			builder.append("type", type);
			return builder.toString();
		}

		public boolean equals(Object object) {
			if (!(object instanceof Fruit)) {
				return false;
			}
			if (this == object) {
				return true;
			}
			Fruit other = (Fruit) object;
			return new EqualsBuilder().append(getName(), other.getName()).isEquals();
		}

		public int hashCode() {
			return new HashCodeBuilder().append(getName()).toHashCode();
		}
	}

	public static Comparator<Fruit> nameComparator = new Comparator<Fruit>() {
		@Override
		public int compare(Fruit o1, Fruit o2) {
			return o1.name.compareTo(o2.name);
		}
	};

	@Test
	public void traditional() {
		List<Fruit> list = Arrays.asList(new Fruit("Mango", 1, 1), new Fruit("Peach", 3, 1), new Fruit("Orange", 2, 1));
		System.out.println(list);

		Collections.sort(list, nameComparator);
		System.out.println(list);
		assertEquals("Mango", list.get(0).getName());
		assertEquals("Orange", list.get(1).getName());
		assertEquals("Peach", list.get(2).getName());
	}

	@Test
	public void compare() {
		List<Fruit> list = Arrays.asList(new Fruit("Mango", Double.MAX_VALUE, 1), new Fruit("Peach", -1d, 1),
				new Fruit("Orange", 2, 1));
		System.out.println(list);

		Comparator<Fruit> quantityComparator = (o, o2) -> Double.compare(o.quantity, o2.quantity);
		Collections.sort(list, quantityComparator);
		System.out.println(list);
		assertEquals("Peach", list.get(0).getName());
		assertEquals("Orange", list.get(1).getName());
		assertEquals("Mango", list.get(2).getName());
	}

	@Test
	public void reversed() {
		List<Fruit> list = Arrays.asList(new Fruit("Mango", 1, 1), new Fruit("Peach", 3, 1), new Fruit("Orange", 2, 1));
		System.out.println(list);

		Comparator<Fruit> lengthComparator = (o, o2) -> Integer.compare(o.name.length(), o2.name.length());
		Collections.sort(list, lengthComparator.reversed());
		System.out.println(list);
		assertEquals("Orange", list.get(0).getName());
		assertEquals("Mango", list.get(1).getName());
		assertEquals("Peach", list.get(2).getName());
	}

	@Test
	public void thenComparing() {
		List<Fruit> list = Arrays.asList(new Fruit("Mango", 1.2, 1), new Fruit("Peach", 1.1, 1),
				new Fruit("Orange", 2, 1));
		System.out.println(list);

		Comparator<Fruit> lengthComparator = (o, o2) -> Integer.compare(o.name.length(), o2.name.length());
		Comparator<Fruit> quantityComparator = (o, o2) -> Double.compare(o.quantity, o2.quantity);
		Collections.sort(list, lengthComparator.thenComparing(quantityComparator));
		System.out.println(list);
		assertEquals("Peach", list.get(0).getName());
		assertEquals("Mango", list.get(1).getName());
		assertEquals("Orange", list.get(2).getName());
	}

	@Test
	public void thenComparingWithKey() {
		List<Fruit> list = Arrays.asList(new Fruit("Mango", 1.2, 1), new Fruit("Peach", 1.1, 1),
				new Fruit("Orange", 2, 1));
		System.out.println(list);

		Comparator<Fruit> lengthComparator = (o, o2) -> Integer.compare(o.name.length(), o2.name.length());
		Collections.sort(list, lengthComparator.thenComparing(Fruit::getQuantity));
		System.out.println(list);
		assertEquals("Peach", list.get(0).getName());
		assertEquals("Mango", list.get(1).getName());
		assertEquals("Orange", list.get(2).getName());
	}

	@Test
	public void thenComparingWithKeyComparator() {
		List<Fruit> list = Arrays.asList(new Fruit("Mango", 1.2, 1), new Fruit("Peach", 1.1, 1),
				new Fruit("Orange", 2, 1));
		System.out.println(list);

		Comparator<Fruit> lengthComparator = (o, o2) -> Integer.compare(o.name.length(), o2.name.length());
		Comparator<Double> doubleCmparator = (d, d2) -> d.compareTo(d2);
		Collections.sort(list, lengthComparator.thenComparing(Fruit::getQuantity, doubleCmparator));
		System.out.println(list);
		assertEquals("Peach", list.get(0).getName());
		assertEquals("Mango", list.get(1).getName());
		assertEquals("Orange", list.get(2).getName());
	}
}

心得分享

Java Comparator Interface Example 使用 Lambda 表達式能讓程式碼更加簡潔與直接,取代傳統實作接口的方法,減少了很多程式碼,大幅提高可讀性, Comparator Interface in Java 提供了幾種 Comparator 常見方法的操作範例,熟悉這些方法的操作,能夠提高開發效率,節省維護上的成本。

發佈留言