码迷,mamicode.com
首页 > 编程语言 > 详细

Effective Java中的方法部分

时间:2018-04-25 18:57:47      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:不可变   视图   避免   pre   组件   中标   开始   sys   set   

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[]>中,打印出来的是毫无意义的:

[[I@70dea4e]

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

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

Effective Java中的方法部分

标签:不可变   视图   避免   pre   组件   中标   开始   sys   set   

原文地址:https://www.cnblogs.com/cedriccheng/p/8945950.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!