很多java程序员都还是很好奇匿名内部类到底有什么卵用,为什么要有这种奇怪的设计。那么今天编程菜鸟为你解答。
从重构的角度来看,匿名内部类可以使你少些一些重复代码,案列如下:
首先我们来看一个代码,计算一个方法执行了多少秒! 其实大多数人都会写。像这样:
public static void test() {
long start = System.currentTimeMillis();
//执行打印的业务逻辑 for (int i = 0; i < 10; i++) {
System.out.println(i);
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
这只是打印的业务逻辑,然而我们也想要统计其它方法的执行时间,那么也需要把除去业务的那几行代码一一复制过去吗?那样太傻了,实际情况中除去业务代码可能非常的长,并且会要是遇到需求变更或者那几行代码出错了都得重新再复制一遍。那样不是得不偿失吗!
能不能将业务代码直接抽取成一段参数呢?很遗憾做不到!
不过可以将这段代码抽取成一个类,或者一个接口的方法。像这样:
public static void test(MyService myService) {
long start = System.currentTimeMillis();
//执行打印的业务逻辑 myService.invoke();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
看到没有,我将这段代码抽取成了MyService的invoke()方法,MyService长这样:
public interface MyService {
public void invoke();
}
那么调用的时候就可以这样写了:
public static void main(String[] args) {
test(new MyService() {
@Override
public void invoke() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
});
}
这样只要在调用的时候将MyService的invoke方法重写,就能实现各种业务逻辑并统计执行的时间啦。并且我们也不用再写前后那一段统计时间的重复代码了,因为它已经封装进test方法里面了!
有人会问这样有必要吗?只是实现了一个计时功能, 假设这段代码不是计时,而是其它更长更复杂但是不会变动的代码,那么你会觉得这么写是值得的。
然而有人会质问这样写起来是不是太丑了!java8中可以用lambda替换匿名内部类,所以你要是用的java8的话可以还这么写:
public static void main(String[] args) {
test(() -> {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
});
}
这样是不是简单得多了呢!是的,不过请注意:lambda表达只能替换
只有一个抽象方法的接口,只有一个抽象方法的接口,只有一个抽象方法的接口,重要的事情说三遍:如果我在MyService中又添加了一个抽象方法invoke2(),那么编译是不通过的.但是如果我想添加一个default修饰符的方法,又可以了,具体原因我就不多解释了,有兴趣的自己可以百度一下 (java8还有一些内置的函数接口可以直接拿来用,这样就可以不用自己再写一些多余的接口了)。
其实说白了,如果你觉得需要将一段非常长的方法中抽取出一个或者多个可能会变动的代码片段,你就可以重构为接口的一个个方法,待调用的时候用匿名内部类重写方法就可以了。
其实jdbc的获取连接以及关闭资源这一块是所有方法通用的,大家不妨尝试用我的方法练练手如何将这两个步骤省略掉,只留下核心的业务逻辑。