编写高质量代码:改善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程序员遇 ...
随机推荐
- Spring Boot+Jsp启动异常
No Java compiler available for configuration options compilerClassName 加入maven配置 <dependency> ...
- Kafka-Flume-elasticsearch
a1.sources = kafkaSource a1.channels = memoryChannel a1.sinks = elasticsearch a1.sources.kafkaSource ...
- ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
今天服务器遇到了一个很熟悉的问题, 输入 #mysql -u root -p ERROR 2002 (HY000):Can't connect to local MySQL server ...
- Delphi之TComponent类
TComponent类 TComponent类直接由TPersistent派生.TComponent的独特特征是它的属性能够在设计期间通过ObjectInspector来控制,能够拥有其他组件.非可视 ...
- centos无网络问题
- Error:Failed to resolve: com.android.support:appcompat-v7
repositories { maven { url "https://maven.google.com" } } implementation 'com.android.supp ...
- faster rcnn训练自己的数据集
采用Pascal VOC数据集的组织结构,来构建自己的数据集,这种方法是faster rcnn最便捷的训练方式
- .NET Core 2.0及.NET Standard 2.0 Description
NET Core 2.0的发布时间,.NET Core 2.0预览版及.NET Standard 2.0 Preview大概在5月中旬或下旬发布. .NET Core 2.0正式版本发布时间大约在Q3 ...
- 基于 vue+vue-router+vuex+axios+koa+koa-router 本地开发全栈项目
因为毕业设计要做基于Node服务器的项目,所以我就想着用刚学的vue作为前端开发框架,vue作为Vue.js应用程序的状态管理模式+库,axios基于promise用于浏览器和node.js的http ...
- [BZOJ 2083] [POI 2010] Intelligence test
Description 霸中智力测试机构的一项工作就是按照一定的规则删除一个序列的数字,得到一个确定的数列.Lyx很渴望成为霸中智力测试机构的主管,但是他在这个工作上做的并不好,俗话说熟能生巧,他打算 ...