Effective Java -- 排序敏感的类建议实现Comparable接口

此系列文章为本人对《Effective Java》一书的学习笔记,主要是记录对书中重点内容的理解。
既然有缘看到此文,那么希望能对你有所帮助。
本文对应原书 第14条 考虑实现Comparable接口

原因

对于一个有排序需求的类,建议实现Comparable接口,因为这样可以让它轻松地被分类、搜索以及用在基于比较的集合中。

陈述

首先了解一下Comparable:它是一个带泛型的接口,且只有一个方法compareTo;

public interface Comparable<T> {
	public int compareTo(T o);
}

当你实现了这个接口,重写了compareTo方法,这个类便可以很方便地利用Java自带的方法进行排序操作,如Arrays.sort方法。

Java中的所有值类枚举类都实现了这个接口,值类实现Comparable接口的原因很简单,毕竟整天都在忙着比大小,作排序。枚举类的这个实现相对冷门,我们来一起看一下:
打开java.lang.Enum,找到compareTo方法
Enum类的comareTo方法
这里我们可以看到,首先是把两个枚举的class进行了对比(这里不深究其对比逻辑),然后直接输出了ordinal之差。

看一下ordinal是什么:
ordinal
说白了就是一个序号,这个序号怎么产生的呢,很简单,就是枚举在定义的时候顺序

举个例子:

public enum Type {
    A, // ordinal = 0
    B, // ordinal = 1
    C, // ordinal = 2
    D; // ordinal = 3
}

所以Type.D.compareTo(Type.A)的返回值就是3 - 0 = 3
虽然看起来有点意思,但是实际上有用吗?类的作者也考虑到了这一点,于是在注释上写了几笔:

The ordinal of this enumeration constant (its position in the enum declaration, where the initial constant is assigned an ordinal of zero). Most programmers will have no use for this field. It is designed for use by sophisticated enum-based data structures, such as java.util.EnumSet and java.util.EnumMap.

简单来说就是,这玩意对绝大多数的码农来说没啥用,这个是设计给复杂的数据结构如EnumSetEnumMap使用的。

规范

在重写compareTo方法时,作者建议我们使用装箱类型自带的compare方法来替代“>”和“<”,如:Double.compareShort.compare,相对来说会更加简洁明朗。

作者提到,这本书的前两版是建议对于整数类型用“>”和“<”比较,对于浮点型用compare方法。由于Java 7版本开始所有的装箱基本类型都有了compare方法,因此从第三版开始建议大家都使用compare

另外书中作了一个引申,建议我们使用Compartor接口,因为可以更方便的进行一些操作,拿之前博客里面提到的PhoneNum举个例子:

public class PhoneNum implements Comparable<PhoneNum>{

	 /*区号*/
    private Short areaCode;

    /*号码*/
    private Integer num;

    /*分机号*/
    private Integer extensionNum;

	...
}

正常实现方式:

public int compareTo(PhoneNum other) {
        int result = Short.compare(areaCode, other.areaCode);
        if (result == 0) {
            result = Integer.compare(num, other.num);
            if (result == 0) {
                result = Integer.compare(extensionNum, other.extensionNum);
            }
        }
        return result;
    }

Compartor实现:

	// 先构造一个静态的 Comparator
    private static final Comparator<PhoneNum> COMPARATOR = Comparator
            .comparingInt((PhoneNum pn) -> pn.areaCode)
            .thenComparingInt(pn -> pn.num)
            .thenComparingInt(pn -> pn.extensionNum);
            
    public int compareTo(PhoneNum other) {
        return COMPARATOR.compare(this, other);
    }

如此,代码的质量肉眼可见提升了。

总结

对于一个有排序需求的类,为了让它可以轻松地进行分类、搜索以和用在基于比较的集合中,建议实现Comparable接口。在重写compareTo时,记得使用装箱基本类型自带的compare方法,对于逻辑较为复杂的逻辑,建议使用Comparator

水平有限,若文章中存在错误,恳请不吝赐教,这对我以及后面的读者都有重要意义

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值