编写高质量代码:改善Java程序的151个建议 --[106~117]
编写高质量代码:改善Java程序的151个建议 --[106~117]
动态代理可以使代理模式更加灵活
interface Subject {
// 定义一个方法
public void request();
}
// 具体主题角色
class RealSubject implements Subject {
// 实现方法
@Override
public void request() {
// 实现具体业务逻辑
}
}
class SubjectHandler implements InvocationHandler {
// 被代理的对象
private Subject subject;
public SubjectHandler(Subject _subject) {
subject = _subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 预处理
System.out.println("预处理...");
//直接调用被代理的方法
Object obj = method.invoke(subject, args);
// 后处理
System.out.println("后处理...");
return obj;
}
}
动态代理使用场景:
public static void main(String[] args) {
//具体主题角色,也就是被代理类
Subject subject = new RealSubject();
//代理实例的处理Handler
InvocationHandler handler =new SubjectHandler(subject);
//当前加载器
ClassLoader cl = subject.getClass().getClassLoader();
//动态代理
Subject proxy = (Subject) Proxy.newProxyInstance(cl,subject.getClass().getInterfaces(),handler);
//执行具体主题角色方法
proxy.request();
}
不用显式创建代理类即实现代理的功能,例如可以在被代理的角色执行前进行权限判断,或者执行后进行数据校验。
使用反射增加装饰模式的普适性
反射让模板方法模式更强大
提倡异常封装
class MyException extends Exception {
// 容纳所有的异常
private List<Throwable> causes = new ArrayList<Throwable>();
// 构造函数,传递一个异常列表
public MyException(List<? extends Throwable> _causes) {
causes.addAll(_causes);
}
// 读取所有的异常
public List<Throwable> getExceptions() {
return causes;
}
}
具体调用如下
public void doStuff() throws MyException {
List<Throwable> list = new ArrayList<Throwable>();
// 第一个逻辑片段
try {
// Do Something
} catch (Exception e) {
list.add(e);
}
// 第二个逻辑片段
try {
// Do Something
} catch (Exception e) {
list.add(e);
}
// 检查是否有必要抛出异常
if (list.size() > 0) {
throw new MyException(list);
}
}
不要在finally块中处理返回值
在finally代码块中处理返回值,这是考试和面试中经常出现的题目。虽然可以以此来出考试题,但在项目中绝对不能再finally代码块中出现return语句,这是因为这种处理方式非常容易产生" 误解 ",会误导开发者。
finally块中处理返回值会产生的问题:
- 覆盖了try代码块中的return返回值
- 屏蔽异常
public static void doSomeThing(){
try{
//正常抛出异常
throw new RuntimeException();
}finally{
//告诉JVM:该方法正常返回
return;
}
}
public static void main(String[] args) {
try {
doSomeThing();
} catch (RuntimeException e) {
System.out.println("这里是永远不会到达的");
}
}
不要在构造函数中抛出异常
异常的机制有三种:
- Error类及其子类表示的是错误,它是不需要程序员处理也不能处理的异常,比如VirtualMachineError虚拟机错误,ThreadDeath线程僵死等。
- RunTimeException类及其子类表示的是非受检异常,是系统可能会抛出的异常,程序员可以去处理,也可以不处理,最经典的就是NullPointException空指针异常和IndexOutOfBoundsException越界异常。
- Exception类及其子类(不包含非受检异常),表示的是受检异常,这是程序员必须处理的异常,不处理则程序不能通过编译,比如IOException表示的是I/O异常,SQLException表示的数据库访问异常。
- 构造函数中抛出异常:
- 构造函数中抛出错误是程序员无法处理的
- 构造函数不应该抛出非受检异常
- 加重了上层代码编写者的负担
- 后续代码不会执行
- 构造函数尽可能不要抛出受检异常
- 导致子类膨胀
- 违背了里氏替换原则
- 子类构造函数扩展受限
使用Throwable获得栈信息
class Foo {
public static boolean method() {
// 取得当前栈信息
StackTraceElement[] sts = new Throwable().getStackTrace();
// 检查是否是methodA方法调用
for (StackTraceElement st : sts) {
if (st.getMethodName().equals("methodA")) {
return true;
}
}
throw new RuntimeException("除了methodA方法外,该方法不允许其它方法调用");
}
}
Throwable源码
public class Throwable implements Serializable {
private static final StackTraceElement[] UNASSIGNED_STACK = new StackTraceElement[0];
//出现异常记录的栈帧
private StackTraceElement[] stackTrace = UNASSIGNED_STACK;
//默认构造函数
public Throwable() {
//记录栈帧
fillInStackTrace();
}
//本地方法,抓取执行时的栈信息
private native Throwable fillInStackTrace(int dummy);
public synchronized Throwable fillInStackTrace() {
if (stackTrace != null || backtrace != null /* Out of protocol state */) {
fillInStackTrace(0);
stackTrace = UNASSIGNED_STACK;
}
return this;
}
}
在出现异常时(或主动声明一个Throwable对象时),JVM会通过fillInStackTrace方法记录下栈帧信息,然后生成一个Throwable对象,这样我们就可以知道类间的调用顺序,方法名称及当前行号等了。获得栈信息可以对调用者进行判断,然后决定不同的输出。
异常只为异常服务
异常只能用在非正常的情况下,不能成为正常情况下的主逻辑。
比如如下代码是不建议的:
//判断一个枚举是否包含String枚举项
public static <T extends Enum<T>> boolean Contain(Class<T> clz,String name){
boolean result = false;
try{
Enum.valueOf(clz, name);
result = true;
}catch(RuntimeException e){
//只要是抛出异常,则认为不包含
}
return result;
}
多使用异常,把性能问题放一边
如下业务逻辑比较清晰,正常代码和异常代码分离、能快速查找问题(栈信息快照)等,虽然性能比较差。
public void login(){
try{
//正常登陆
}catch(InvalidLoginException lie){
// 用户名无效
}catch(InvalidPasswordException pe){
//密码错误的异常
}catch(TooMuchLoginException){
//多次登陆失败的异常
}
}
编写高质量代码:改善Java程序的151个建议 --[106~117]的更多相关文章
- 博友的 编写高质量代码 改善java程序的151个建议
编写高质量代码 改善java程序的151个建议 http://www.cnblogs.com/selene/category/876189.html
- 编写高质量代码改善java程序的151个建议——导航开篇
2014-05-16 09:08 by Jeff Li 前言 系列文章:[传送门] 下个星期度过这几天的奋战,会抓紧java的进阶学习.听过一句话,大哥说过,你一个月前的代码去看下,慘不忍睹是吧.确实 ...
- 编写高质量代码改善java程序的151个建议——[1-3]基础?亦是基础
原创地址: http://www.cnblogs.com/Alandre/ (泥沙砖瓦浆木匠),需要转载的,保留下! Thanks The reasonable man adapts himse ...
- 编写高质量代码:改善Java程序的151个建议 --[117~128]
编写高质量代码:改善Java程序的151个建议 --[117~128] Thread 不推荐覆写start方法 先看下Thread源码: public synchronized void start( ...
- 编写高质量代码:改善Java程序的151个建议 --[78~92]
编写高质量代码:改善Java程序的151个建议 --[78~92] HashMap中的hashCode应避免冲突 多线程使用Vector或HashTable Vector是ArrayList的多线程版 ...
- 编写高质量代码:改善Java程序的151个建议 --[65~78]
编写高质量代码:改善Java程序的151个建议 --[65~78] 原始类型数组不能作为asList的输入参数,否则会引起程序逻辑混乱. public class Client65 { public ...
- 编写高质量代码:改善Java程序的151个建议 --[52~64]
编写高质量代码:改善Java程序的151个建议 --[52~64] 推荐使用String直接量赋值 Java为了避免在一个系统中大量产生String对象(为什么会大量产生,因为String字符串是程序 ...
- 编写高质量代码:改善Java程序的151个建议 --[36~51]
编写高质量代码:改善Java程序的151个建议 --[36~51] 工具类不可实例化 工具类的方法和属性都是静态的,不需要生成实例即可访 问,而且JDK也做了很好的处理,由于不希望被初始化,于是就设置 ...
- Github即将破百万的PDF:编写高质量代码改善JAVA程序的151个建议
在通往"Java技术殿堂"的路上,本书将为你指点迷津!内容全部由Java编码的最佳 实践组成,从语法.程序设计和架构.工具和框架.编码风格和编程思想等五大方面,对 Java程序员遇 ...
随机推荐
- CMake--变量
1.一般变量 1)CMake变量引用的方式 使用${}进行变量的引用.例如: ${PROJECT_NAME} #返回项目名称 在 IF 等语句中,是直接使用变量名而不通过${}取值. 2)cmake自 ...
- 利用js给datalist或select动态添加option选项
<!DOCTYPE html> <html> <head> <title>鼠标点击时加载</title> <script type=& ...
- bootstrap模态框关闭后清除模态框的数据
https://segmentfault.com/q/1010000008789123 bootstrap模态框第二次打开时如何清除之前的数据? 我用了bootstrap模态框的remote功能,在弹 ...
- day 7-13 数据库的数据类型
一. 数据类型 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己的宽度,但宽度是可选的 注意:int类型的宽度是显示宽度,并非是数据的存储宽度 详细的介绍:http:// ...
- h5简易手写板
............. 我该说点什么呢,开头居然不知道想说点什么!好吧不知道说什么,我们就来说说这个手写板吧,虽然这个手写板现在没什么用,但是.....,好像的确没什么用啊! 只是存粹哪里练手的的 ...
- Redis事物
redis事物定义: >Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化.按顺序地执行.事务在执行的过程中,不会被其他客户端发送来的命令请求所打断. >Redis事务的主要作 ...
- python设计模式第八天【装饰器模式】
1.定义 使用包装的释放扩展类的功能,但是不使用继承 2.使用场景 3.代码实现 #!/usr/bin/env python #! _*_ coding:UTF-8 _*_ def MyDecorat ...
- 解析xml文件 selectSingleNode取不到节点
今天在做批量生成XML的时候,碰到一个情况 解析xml文件 selectSingleNode一直返回NULL. XML的格式开头有一句这个<CE401Message xmlns="ht ...
- Lodop打印设计里的 打印项对齐
打印设计界面里,有四个对齐的图标:(1)第一个图标是左右对齐方式,该图标下有四种左右对齐方式.(2)第二个图标是上下对齐方式,该图标下有四种上下对齐方式.(3)第三个图标是等宽对齐,该图标下有三种等宽 ...
- SVG路径
前面的话 本文将详细介绍SVG路径 path字符串 路径(path)是一个非常强大的绘图工具,可以用path元素绘制矩形(直角矩形或者圆角矩形).圆形.椭圆.折线形.多边形,以及一些其他的形状,例如贝 ...