Effective Java中的方法部分

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Effective Java中的方法部分相关的知识,希望对你有一定的参考价值。

1.检查参数的有效性

非公有方法应使用断言(Assertion)来检查它们的参数,公有方法需要在Javadoc中标明一旦参数违反限制时,会抛出什么异常。

但并不是说对参数的任何限制都是好事,应当在通用的原则,遵循上面的指导原则。

2.必要时必须进行保护性拷贝

这一节对我的触动非常大,因为我之前在写代码的时候从没注意到这一点。

来看下面一段代码:

public final class Period {
    private final Date start;
    private final Date end;

    public Period(Date start, Date end) {
        if(start.compareTo(end) > 9)
            throw new IllegalArgumentException(
                start + " after " + end);
        this.start = start;
        this.end = end;
    }

    public Date start() {
        return start;
    }

    public Date end() {
        return end;
    }
}

乍一看好像Period是不可变的,实际上,只是start和end不能指向新的引用,但是,可以通过:

Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
end.setYear(78);

这样来改变p中的start和end,如果Period中的接口开放给客户端,则可以随意修改开始和结束的时间,这显然不是我们想要的,于是可以利用保护性拷贝解决该问题:

public final class Period {
    private final Date start;
    private final Date end;

    public Period(Date start, Date end) {
        this.start = new Date(start.getTime());
        this.end = new Date(end.getTime());
        if(start.compareTo(end) > 9)
            throw new IllegalArgumentException(
                start + " after " + end);
    }
}

发现不一样的地方了么,若客户端修改了返回的内部组件,修改的仅仅是组件的一个拷贝,不能修改真正的start和end,但还是Period还是提供了访问start和end的公共接口,于是都可以采用保护性拷贝

解决:

    public Date start() {
        return new Date(start.getTime());
    }

    public Date end() {
        return new Date(end.getTime());
    }

至于为什么不用clone()方法,书中也写的很详细了,Date不是final类,也就是说它可以被继承而修改,如果有人恶意继承Date,将引用记录到一个私有的静态列表中,这种子类便是不可信的,如果当作

参数传入Period的构造方法中,如果使用clone()方法进行拷贝,则拷贝的是这种不可信子类,还是会使Period变得很脆弱,这里使用java.util.Date类避免了这一情况。

至于数组等内部组件,长度非零的数组一定是可变的,返回给客户端之前,应该进行保护性拷贝,返回给其一个不可变视图。

3.慎用可变参数、重载,谨慎设计方法签名

原则为:参数不能过多,方法不宜过多,方法名应该清晰明了,参数类型优先使用接口而不是类。

慎用重载和可变参数,因为这样会使方法变得模糊,客户端在调用方法后所得到的结果往往出乎意料。例如:

System.out.println(Arrays.asList(myArray));

asList()方法的参数为可变参数,这使得myArray这个数组在传参时,会被整体当作参数数组的第一个元素传入,在将它包装到List<int[]>中,打印出来的是毫无意义的:

4.返回长度为零的数组或者集合而不是null

这个我在使用SonarLint时提醒过我,主要是为了避免客户端使用时曲折的处理方式,比如必须先要判断是不是null

以上是关于Effective Java中的方法部分的主要内容,如果未能解决你的问题,请参考以下文章

Effective Java 第三版——65. 接口优于反射

Effective Java 第三版——79. 避免过度同步

Effective Java 在工作中的应用总结

《Effective Java》------读后总结

《Effective Java》——读后总结

EFFECTIVE JAVA 第十章 并发