编写高质量代码:改善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程序员遇 ...
随机推荐
- ResultHandler的用法
ResultHandler,顾名思义,对返回的结果进行处理,最终得到自己想要的数据格式或类型.也就是说,可以自定义返回类型.下面通过一个例子讲解它的使用方法: 创建Goods实体类: public c ...
- spring AOP源码分析(一)
对于springAOP的源码分析,我打算分三部分来讲解:1.配置文件的解析,解析为BeanDefination和其他信息然后注册到BeanFactory中:2.为目标对象配置增强行为以及代理对象的生成 ...
- bootstrap modal垂直居中(简单封装)
1.使用modal 弹出事件方法: 未封装前: <!DOCTYPE html> <html lang="en"> <head> <meta ...
- 在浏览器上安装 Vue Devtools工具
Vue.js devtools是基于google chrome浏览器的一款调试vue.js应用的开发者浏览器扩展,可以在浏览器开发者工具下调试代码. 1)首先在github下载devtools源码,地 ...
- 建议1---理解Pythonic的概念
对于Pythonic的概念,众人都有自己的看法,但大家心中都认同一个更具体的指南,即Tim Peters的<The Zen of Python>.在这一篇充满禅意的诗篇中,有几点非常深入人 ...
- IWMS后台上传文章,嵌入音频文件代码
<object width="260" height="69" classid="clsid:6bf52a52-394a-11d3-b153-0 ...
- No module named 'ConfigParser'
系统: CentOS-6.4-x86_64 Python : Python 3.4.5 和 Python 3.5.2 安装 MySQL-python ,结果出错: ImportError: No mo ...
- PHP涉及到的英文单调
slashes [slæʃeis]:斜线 uppercase ['ʌpəˌkeɪs]:大写字母,简写uc strip [strɪp]:去掉 trim [trɪm]:整理(修剪) explode [ɪk ...
- jsp页面给字体加颜色
jsp页面给字体加颜色<span style="color:red">要加颜色的部分</span>
- hdu1839(最小生成树)
题意:字面意思: 思路:就是多了一个前提,有些点之间可能有边,有两个处理方法,一个是有边的,这条边权值归零,另一个是,先一次循环用并查集过一遍: 代码:(用的是第一种方法) #include<i ...