方法
笔记:
method:
1、检查参数的有效性
考虑方法参数的限制,并将这些限制写到文档中,并在方法开头出,通过显式的检查来实施限制。私有方法使用assert断言实施限制。
2、必要时进行保护性拷贝
假设类的客户端会尽其所能来破坏这个类的约束条件,因此你必须保护性地设计程序。
对于构造器的每个可变参数进行保护性拷贝是必要的;
保护性拷贝是在检查参数的有效性之前进行的,并且有效性检查是针对拷贝之后的对象,而不是针对原始的对象;
对于参数类型可以不被信任方子类化的参数,请不要使用clone方法进行保护性拷贝
使它返回内部域的保护性拷贝即可
参数的保护性拷贝并不仅仅针对不可变类。每当编写方法或者构造器时,如果它要允许客户提供的对象进入到内部数据结构中,则有必要考虑一下,客户提供的对象是否有可能是可变的。如果是,就要考虑你的类是否能够容忍对象进入数据结构之后发生变化。如果答案是否定的,就必须对该对象进行保护性拷贝,并且让拷贝之后的对象而不是原始对象进入到数据结构中。
只要有可能,都应该使用不可变的对象作为对象内部的组件,这样就不必再为保护性拷贝而操心。
3、谨慎设计方法签名
谨慎地选择方法的名称
不要过于追求提供便利的方法
避免过长的参数列表。目标是四个参数,或者更少。
缩短过长参数列表方法:
将方法分解成多个方法,每个方法只需要这些参数的一个子集;
创建辅助类,用来保存参数的分组;
从对象创建到方法调用都采用builder模式
对于参数类型,要优先使用接口而不是类
对于boolean参数,要优先使用两个元素的枚举类型
4、慎用重载
要调用哪个重载方法是在编译时做出决定的
对于被覆盖的方法的选择是动态的,依据是被调用方法所在对象的运行时类型
避免胡乱使用重载机制
安全而保守的策略是,永远不要导出两个具有相同参数数目的重载方法,参考ObjectOutputStream的writeBoolean(boolean)等方法
5、慎用可变参数
可变参数接受0个或者多个指定类型的参数。可变参数机制通过先创建一个数组,数组的大小为在调用位置所传递的参数数量,然后将参数值传到数组中,最后将数组传递给方法
不必改造具有final数组参数的每个方法,只当确实是在数量不定的值上执行调用时才使用可变参数
6、返回零长度的数组或者集合,而不是null
返回类型为数组或集合的方法没理由返回null,而不是返回一个零长度的数组或者集合
7、为所有导出的API元素编写文档注释
为了正确地编写API文档,必须在每个被导出的类、接口、构造器、方法和域声明之前增加一个文档注解
方法的文档注释应该简洁地描述出它和客户端之间的约定
有关代码:
package chapter6; import java.math.BigInteger; import java.util.*; /** * @author zhen * @Date 2018/10/8 10:12 */ public class CollectionClassifier { // public static String classify(Set<?> s) { // return "Set"; // } // // public static String classify(List<?> s) { // return "List"; // } // // public static String classify(Collection<?> s) { // return "UnKnow Collection"; // } public static String classify(Collection<?> c) { return c instanceof Set ? "Set" : c instanceof List ? "List" : "UnKnow Collection"; } public static void main(String[] args) { Collection<?>[] collections = { new HashSet<String>(), new ArrayList<BigInteger>(), new HashMap<String, String>().values() }; for(Collection<?> c : collections){ System.out.println(classify(c)); } } }
package chapter6; import java.math.BigInteger; /** * @author zhen * @Date 2018/10/8 9:15 */ public class Demo { /** * * @param m the modulus, which must be positive * @return this mod m * @throws ArithmeticException if m is less than or equal to 0 */ public BigInteger mod(BigInteger m) { if (m.signum() <= 0) { throw new ArithmeticException("Modulus <= 0:" + m); } return null; } private static void sort(long a[], int offset, int length) { assert a != null; assert offset >= 0 && offset <= a.length; assert length >= 0 && length <= a.length - offset; // Do the computation } static int sum(int ... args) { int sum = 0; for(int arg : args) { sum += arg; } return sum; } //如果客户端调用这个方法时,并没有传递参数进去,它就会再运行时而不是编译时失败。 //这段代码很不美观,你必须在args中包含显式的有效性检查,除非将min初始化为Integer.MAX_VALUE,否则将无法使用for-each循环,这样的代码也不美观 static int min(int ... args) { if (args.length == 0) { throw new IllegalArgumentException("Too few arguments"); } int min = args[0]; for(int i = 1; i < args.length; i++){ if (args[i] < min) { min = args[i]; } } return min; } }
package chapter6; import java.util.Date; /** * @author zhen * @Date 2018/10/8 9:31 */ public final class Period { private final Date start; private final Date end; /** * * @param start * @param end * @throws IllegalArgumentException if start is after end * @throws NullPointerException if start or end is null */ public Period(Date start, Date end) { if (start.compareTo(end) > 0) { throw new IllegalArgumentException(start + " after " + end); } this.start = new Date(start.getTime()); this.end = new Date(end.getTime()); } public Date start() { return new Date(start.getTime()); } public Date end() { return new Date(end.getTime()); } // Remainder omitted }
package chapter6; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; /** * @author zhen * @Date 2018/10/8 15:52 */ public class SetList { public static void main(String[] args) { Set<Integer> set = new TreeSet<>(); List<Integer> list = new ArrayList<>(); for(int i = -3; i < 3; i++){ set.add(i); list.add(i); } for (int i = 0; i < 3; i ++) { set.remove(i); list.remove(i); } System.out.println(set + " " + list); } }

浙公网安备 33010602011771号