【effective Java读书笔记】方法(二)

来源:互联网 发布:基本遗传算法 编辑:程序博客网 时间:2024/05/20 00:38

【effective Java读书笔记】方法(二)

前言:

越发喜欢写读书笔记了,写完之后,后续的工作中,平时写代码,就会比较深刻的记起来,“原来这个地方可以这么用”。

《第40条至41条》

正文:

一、谨慎设计方法签名,其中值得一提的是:避免过长的参数列表。

对了,话说方法签名应该很熟悉吧:参数类型、参数个数、参数顺序。

避免过长的参数列表的三种方法:

1、方法分解成多个方法;

书中举例:在子列表中查找元素的第一个索引和最后一个索引。(java.util.List接口)

public class ListApply {public static void main(String[] args) {List<String> strs = new ArrayList<>();// TODO 提供数据for (int i = 0; i < 20; i++) {strs.add("test"+i);}List<String> subStrs= strs.subList(3, 13);System.out.println(subStrs.indexOf(subStrs.get(0)));System.out.println(subStrs.lastIndexOf(subStrs.get(subStrs.size()-1)));}}

执行结果:

0

9

原本提供这样一个方法需要三个参数,子列表、子列表第一个索引、子列表的最后一个索引。

第8行,List接口提供subList方法,获得子列表;

第9行,根据

subStrs.get(0)

获取第一个对象,通过indexOf方法获得第一个对象出现的第一次的index;

第10行,根据

subStrs.get(subStrs.size()-1))

获取最后一个对象,通过lastIndexOf获取最后一个对象出现的最后一次的index;

2、创建辅助类;

辅助类,顾名思义,就是用来作为辅助工具的类。

举个例子:

public class HelpClass {public static class Help{public static int add(int x,int y){return x+y;};public static int min(int x,int y){return x-y;};}public static void main(String[] args) {int x =3;int y =2;System.out.println("3+2=?");System.out.println(HelpClass.Help.add(x, y));System.out.println("3-2=?");System.out.println(HelpClass.Help.min(x, y));}}
执行结果:

3+2=?

5

3-2=?

1

其中:

Help就是辅助类,原本一个这样的计算,需要传递三个入参:第一个数,第二个数,算数操作符。

现在添加辅助类后,只需要添加两个入参。(以上代码用枚举写更佳)

枚举代码改进如下:(使用起来是否更佳优雅,具体为什么这么写,有什么优点,看我这篇文章吧)

public class HelpClass {public static enum Opre{ADD("+"){@Overridepublic int apply(int x, int y) {return x+y;}},MIN("-"){@Overridepublic int apply(int x, int y) {return x-y;}};public final String oper;Opre(String oper) {this.oper = oper;}public abstract int apply(int x,int y);}public static void main(String[] args) {int x =3;int y =2;System.out.println("3+2=?");System.out.println(HelpClass.Opre.ADD.apply(x, y));System.out.println("3-2=?");System.out.println(HelpClass.Opre.MIN.apply(x, y));}}

3、从对象构建到方法调用都采用Build模式。

直接举例:

public class User {private String name;private String addr;private int age;public String getName() {return name;}public String getAddr() {return addr;}public int getAge() {return age;}@Overridepublic String toString() {return "User [name=" + name + ", addr=" + addr + ", age=" + age + "]";}public static class Builder{private User user = new User();public Builder setName(String name){user.name = name;return this;}public Builder setAddr(String addr){user.addr = addr;return this;}public Builder setAge(int age){user.age = age;return this;}public User build(){return user;}}}
使用如下:

public class Test {@org.junit.Testpublic void test() {Builder builder = new Builder();User user =builder.setName("bear").setAge(14).setAddr("beijing").build();System.out.println(user);}}
执行结果如下:

User [name=bear, addr=beijing, age=14]

当然这个方法显著的减少了参数。使用起来也比较方便。

二、慎用重载

关键点出来的就是重载和覆盖的区别:书中提及“对于重载方法的选择是静态的,对于覆盖方法的选择是动态的”。

1、先看一个书中重载的例子:

public class OverRideTest {public static String classify(Set<?> s){return "Set";}public static String classify(List<?> lst){return "List";}public static String classify(Collection<?> c){return "Collection";}public static void main(String[] args) {Collection<?>[] collections = {new HashSet<String>(),new ArrayList<String>(),new HashMap<String,String>().values()};for (Collection<?> c:collections) {System.out.println(classify(c));}}}
乍看之下,有点懵!这结果是不是应该Set,List,Collection;

而实际结果呢?

Collection

Collection

Collection

原因其实很简单,重载嘛,挑选最合适的。

public static String classify(Collection<?> c){return "Collection";}

而且重载方法调用是在编译时决定的。那么一旦选定就不能改了。无异议是否?

2、再看一个覆盖的例子:

代码如下

public class Test2 {public static void main(String[] args) {Wine[] wines = { new Wine(), new RedWine(), new YellowWine() };for (Wine wine : wines) {System.out.println(wine.name());}}}class Wine {String name() {return "wine";}}class RedWine extends Wine {String name() {return "RedWine";}}class YellowWine extends Wine {String name() {return "YellowWine";}}

执行结果:

wine

RedWine

YellowWine


3、慎用重载的例子:

书中这个例子显得很是经典:

public class SetList {public static void main(String[] args) {Set<Integer> set = new TreeSet<>();List<Integer> list = new ArrayList<Integer>();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);}}
看上去以为结果会是

[-3, -2, -1]

[-3, -2, -1]

实际结果却是:

[-3, -2, -1][-2, 0, 2]

原因是什么?第一个Set与我们预期相同。Set添加和删除都会先装箱,再添加删除。

第二个List添加时装箱,但是删除的时候重载了,导致remove第几个位置的,而不是删除某个指定的对象。










原创粉丝点击