`
trydofor
  • 浏览: 149002 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

码工魄之JAVA方法修炼之道

阅读更多
码工魄之Method修炼之道
作者:臭豆腐[trydofor.com]
日期:2009-12-03
授权:署名-非商业-保持一致 1.0 协议
声明:拷贝、分发、呈现和表演本作品,请保留以上全部信息。

 

文档目录
1. Method构成
在程序开发中,Method译作:方法、函数。本文主要讨论Java中的方法。

从语法结构上看,一个高质量的方法应该包括以下部分。[ST]
  • 注释,说明使用方法或特殊用途,如javadoc注释或@Annotation。
  • 修饰符,限定作用域,可见性等,如public,static等。
  • 返回值,正常结束的情况。
  • 方法名,简明扼要的名字,如 getter,setter等。
  • 参数列表,方法的参数。
  • 异常列表,异常结束的情况。
  • 方法主体,代码实现部分。

从数据流向上看,方法一般包括了一个输入流(参数列表)和一个输出流。
输出流要么是正常输出流(返回值),要么是异常输出流(异常列表)。

2. 大师总结
“Effective Java 第2版”的第七章,专门讲了方法,提到的经验有。[EJ]
  • 第38条:检查参数的有效性。
  • 第39条:必要时进行保护性拷贝。
  • 第40条:谨慎设计方法签名。
  • 第41条:慎用重载(overload)。
  • 第42条:慎用可变参数。
  • 第43条:返回零长度数组或者集合,而不是null。
  • 第44条:为所有导出的API元素编写文档注释。

3. 低级经验
大师总结的第38,40,43条最为受用,应该是作为必备技能。
立足于国情行情,在代码堆中堆代码的时候,我们还要注意以下的低级经验。
根本目的是为了提高代码的可读性,便于理解和维护。

3.1. MM01-保证方法的一致性
一致性包括两个:说明,名称,行为三者间的一致;各返回值分支意义的一致。
为了方便理解,虚构一个五毒俱全的方法,该方法要求:

<text> 方法要求 
/** 
* 返回一个拷贝列表,元素为list中从0(包括 )到 length(不包括)。
* 如果指定列表为null或length小于等于0,则返回空列表。
* 如果length大于等于指定列表长度,则拷贝包括所有元素。
* 
* @param list 指定列表,即数据源。
* @param length 指定长度。
* @return 一个拷贝列表,元素为list中从0(包括 )到 length(不包括)。
*/

<java> bad copyOf 
001
002
003
004
005
006
007
008
public <E> List<E> copyOf(List<E> list,int length){
   if(list == null || length<=0) return new LinkedList();
   if(length<list.size()){
       return list.subList(0, length);
   }else{
       return list;
   }
}

从方法名和要求上看,该方法的返回值是一个拷贝,对该拷贝的操作,不会影响到源list。
方法有三个返回值分支(return),其中,只有第一个分支不影响源list。
像下面这样修改回好些。(少了return,多了if-else,见仁见智的吧)

<java> new copyOf 
001
002
003
004
005
006
007
008
009
010
011
public <E> List<E> copyOf(List<E> list,int length){
   List<E> result = new LinkedList<E>();
   if(list == null || length<=0){
       // empty
   }else if(length<list.size()){
       result.addAll(list.subList(0, length));
   }else{
       result.addAll(list);
   }
   return result;
}

3.2. MM02-精简方法体的体积
方法体积过大会影响理解和阅读,个人认为超过三屏的方法会影响阅读,该考虑精简了。
但不需要阅读和深入理解的代码,如自动生成的,套路相同的代码堆不需要精简。

功能强的大方法,可以提升为类,再封装成数据和方法。
功能杂的大方法,可以打散为若干小方法的组合。
大的if-else,switch-case块,可以提炼成小方法的组合。[RP,98]
<java> 组合小方法 
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
public void add(Object element){
   if(!readOnly){
       int newSize = size + 1;
       if(newSize > elements.length){
           Object[] newElements = new Object[elements.length + 10];
           for(int i=0; i < size;i++)
               newElements[i] = elements[i];
           elements = newElements;
       }
       elements[size++] = element;
   }
}
// 重构为下面这样。
public void add(Object element){
   if(readOnly) return;
   if(atCapacity()) grow();
   addElement(element);
}

3.3. MM03-保持简洁的返回值分支
提前return有利于流程控制,但过多的或过于分散的return分支不利于阅读和维护。
减少return分支的可以使用 if-else,switch-case块。(缺点,参看第 MM02条)

总之,减少返回值分支的根本目的在于提高代码的可读性和维护性。

3.4. MM04-必要时进行输出检查(返回值检查)
一个健壮的方法应该保证,如果输入正确,那么就要输出正确。
输入检查,即“第38条:检查参数的有效性。”用来保证输入正确,
可是输入正确,输出就一定能够正确么,能够和预期的一致么?
输出检查就是为了提供这样一道防线,对非预期的情况给予纠正或报错。

假设,某人写了addAbs方法,从字面上看下面方法没有问题,绝对值相加一定非负。
<java> add abs 
001
002
003
public long addAbs(int a,int b){
   return Math.abs(a)+Math.abs(b);
}
但是,该方法可以返回负值(相见Math.abs API),于是修改成了下面这样。
<java> add abs 
001
002
003
004
005
public long addAbsCheck(int a,int b){
   long r = Math.abs(a)+Math.abs(b);
   if(r<0) throw new IllegalStateException("|"+a+"|+|"+b+"|="+r);
   return r;
}
可以看到,此时的输出检查要比输入检查节省和安全。
(如果再多一个参数(int c)该如何写,如果数组呢?)

3.5. MM05-为危险方法写好注释
什么样的方法属于危险方法?
  • 非线程安全或兼容的,但有可能用在多线程环境下。
  • 消耗高或调用重要资源的方法,比如,连接网络或大量占用内存等。
  • 修改传入参数。
  • 方法逻辑高深或不易理解。
  • 返回值可能会因非输入参数而改变的。
    比如依赖于类变量A,而A又不具备线程安全性。

对于作者来说,危险方法一定要写好注释,以使调用者知其变数。
对于调用者来说,不知变数的方法,可以调用一次完成的,
尽量不要使用第二次,尤其某些貌似getter的方法。

<java> getter 
001
002
003
004
005
006
007
008
009
010
011
012
013
014
// product.getBarcode() 
// 用来得到一个商品的条码,商品固定则条码固定。

// 危险代码
List<Goods> lg = store.getGoods();
for (Goods goods : lg) {
   goods.setBarcode(product.getBarcode());
}
// 安全代码
Barcode bc = product.getBarcode();
List<Goods> lg = store.getGoods();
for (Goods goods : lg) {
   goods.setBarcode(bc);
}

4. 参考资料
  • ST Sun的Java指南
  • EJ Effective Java 第2版(ISBN 978-7-111-25583-3,机械工业出版社)
  • RP 模式与重构(ISBN 978-7-115-15336-4,人民邮电出版社)
6
1
分享到:
评论
4 楼 yuantong 2009-12-05  
Barcode bc = product.getBarcode();
List<Goods> lg = store.getGoods();
for (Goods goods : lg) {
   goods.setBarcode(bc);
}
3 楼 xindianshang 2009-12-05  
学习了哈~谢谢分享~
2 楼 trydofor 2009-12-05  
fujohnwang 写道
呵呵, 好,返璞归真了

c++之爹说,把问题搞复杂,就是为了提供程序员门槛,提高待遇。
现在门槛太低了,没必要搞那么复杂了。
1 楼 fujohnwang 2009-12-05  
呵呵, 好,返璞归真了

相关推荐

    java 工程师修炼之道

    《Java工程师修炼之道》可以看作一本Java 工程师的入职指南,也可以看作一本串联Java 后端技能点的参考手册。通过精心编排的内容,刚入门的Java 工程师能够体系化地学习相关开发技能,有经验的Java 工程师能够查漏...

    《单元测试之道Java版:使用JUnit》PDF 下载

    《单元测试之道Java版:使用JUnit》PDF 下载

    读书笔记:Java工程师修炼之道 梳理Java知识体系沓实架构基础.zip

    读书笔记:Java工程师修炼之道 梳理Java知识体系沓实架构基础

    java生成一维码

    在Java编程环境中,生成一维码(如常见的条形码)是常见的需求,尤其是在物流、库存管理和产品追踪等领域。本文将深入探讨如何使用Java来生成一维码,并结合提供的资源进行详细讲解。 首先,要理解一维码是一种将...

    Java三种生成条形码的源码(barcode4j、jbarcode、google-zxing)

    以下是关于使用Java生成条形码的三个主要方法的详细解释:barcode4j、jbarcode和google-zxing。 1. **barcode4j**: Barcode4J是一个开源的Java库,基于Apache 2.0许可,专门用于生成各种类型的条形码。它使用XML...

    java检测并自动获取usb扫码枪设备输入

    在Java编程环境中,为了在Windows 7或XP(32位和64位)系统下检测并自动获取USB扫码枪设备输入,我们需要实现一个能够监听USB设备连接,并处理扫码枪扫描到的条形码数据的解决方案。这个过程涉及到几个关键的技术点...

    Java实现条形码打印

    目前比较通用的用Java实现条形码打印的集成插件主要有:barbecue和barcode4j. 但是用barbecue,条形码可以显示出来,可是下面对应数字却不能显示出来,当然可以自己手动加上去,不过那就不是一张图片里面的了,并且...

    java给word文档插入水印并设置保护密码

    在Java编程环境中,处理Word文档是一项常见的任务,特别是在开发OA(办公自动化)系统时。本文将详细介绍如何使用Java为Word文档插入水印以及设置保护密码,以确保文档的安全性。 首先,我们需要一个能够操作...

    java实现zebra打印条形码

    Java库会提供对应的类或方法来生成这些条形码。在生成条形码时,需要根据实际需求选择合适的类型,并设置相应的编码规则。 5. **图像处理**:生成的条形码通常是以图像的形式存在,Java的`java.awt.image`包提供了...

    JAVA读取USB扫描枪

    在Java编程环境中,读取USB扫描枪的数据是一项实用的技术,特别是在物流、仓储、零售等领域,用于快速录入条形码或二维码信息。以下将详细介绍如何在Java中实现这一功能。 首先,理解USB扫描枪的工作原理是关键。...

    java生成条形码的Demo

    Java生成条形码的Demo是一种在Java环境中实现条形码生成的应用示例。条形码在各种领域,如零售、物流、库存管理等,都扮演着重要的角色,它能够快速准确地识别商品信息。本Demo旨在帮助开发者了解如何在Java项目中...

    java实现字符转换成十六进制的ASCII码

    在Java编程语言中,将字符转换为十六进制表示的ASCII码是一项常见的任务,尤其是在处理字符串数据时。本文将深入探讨如何实现这个功能,并通过一个具体的示例代码`StringToAscii.java`进行演示。 首先,我们需要...

    java中main方法发送httpPost请求

    这可以通过`java.net.URL`类的`openConnection()`方法实现: ```java URL url = new URL("http://target.com/api"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); ``` 2. **...

    Zxing java识别条形码例子

    本篇文章将深入讲解如何使用Java和Zxing库来实现条形码的识别。 首先,我们需要在项目中引入Zxing库。如果你的项目是Maven工程,可以在pom.xml文件中添加以下依赖: ```xml &lt;groupId&gt;com.google.zxing&lt;/groupId&gt;...

    Java解压带密码的RAR文件

    Java解压RAR文件,压缩包内包含源码、Jar包、依赖包和示例程序,也可以从http://code.google.com/p/java-unrar/downloads/list这里下载支持密码的unrar项目(包括源码和jar包),其依赖包也很容易搜到。

    java摄像头读取二维码(整个java项目)

    2. **ZXing(Zebra Crossing)库**:该项目使用了ZXing库(Google开源的二维码解码库),它支持多种编码格式,包括QR码、条形码等。ZXing库提供了`com.google.zxing`包下的多个类,如`Reader`、`MultiFormatReader`...

    java游戏之华容道

    在这个专题中,我们将聚焦于“Java游戏之华容道”。华容道,源于中国的传统智力玩具,是一款策略性的单人游戏,目标是通过移动棋子让曹操从起点到达终点。在Java平台上实现这个游戏,我们可以学到很多关于图形用户...

    Java代码实现中文与ASCII互相转换

    Java自定义实现本地语言与ASCII之间的互相转换。可在开发项目中直接调用的工具类。

    java源码包---java 源码 大量 实例

    Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字  Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象...

    JAVA_API1.6文档(中文)

    java.awt.im.spi 提供启用可以与 Java 运行时环境一起使用的输入方法开发的接口。 java.awt.image 提供创建和修改图像的各种类。 java.awt.image.renderable 提供用于生成与呈现无关的图像的类和接口。 java.awt....

Global site tag (gtag.js) - Google Analytics