Java高质量代码之 — 杂_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Java高质量代码之 — 杂

Java高质量代码之 — 杂

 2013/9/16 12:46:27  ray_yui  程序员俱乐部  我要评论(0)
  • 摘要:前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间拜读了秦小波老师的《改善Java程序的151建议》,感觉廓然开朗,注意到了很多平时在编写代码中并不会注意的问题,甚至感觉自己对Java只是略懂皮毛,不足以登大雅之堂,特此与读者分享读书笔记,以下内容摘自《改善Java程序的151建议》一书和笔者的理解Java高质量代码系列文章面向对象篇:http://ray-yui.iteye.com/blog/1926984数据类型篇:http://ray-yui.iteye
  • 标签:Java 代码

前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间拜读了秦小波老师的《改善Java程序的151建议》,感觉廓然开朗,注意到了很多平时在编写代码中并不会注意的问题,甚至感觉自己对Java只是略懂皮毛,不足以登大雅之堂,特此与读者分享读书笔记,以下内容摘自《改善Java程序的151建议》一书和笔者的理解


Java高质量代码系列文章
      面向对象篇:http://ray-yui.iteye.com/blog/1926984
      数据类型篇:http://ray-yui.iteye.com/blog/1927251
          字符串篇:http://ray-yui.iteye.com/blog/1927647
      数组与集合(1):http://ray-yui.iteye.com/blog/1928170
      数组与集合(2):http://ray-yui.iteye.com/blog/1930155
      枚举注解:http://ray-yui.iteye.com/blog/1931408
      泛型与发射:http://ray-yui.iteye.com/blog/1933127
                  异常:http://ray-yui.iteye.com/blog/1938946
                      杂:http://ray-yui.iteye.com/blog/1942591

1.莫让常量蜕变为变量
     请观察以下代码

class="java">
public class Test {

	public static final int CONST = new Random().nextInt();
}


     在上面代码中如此声明常量,常量将会根据Random返回的随机数而作出改变,这种常量的定义方式是极不可取的,不应该将常量的值在运行期间修改

2.三元caozuofu.html" target="_blank">操作符类型务必一致
      请观察以下代码

public class Test {

	public static void main(String[] args) {
		int i = 80;
		String str1 = String.valueOf(i < 100 ? 90 : 100);
		String str2 = String.valueOf(i < 100 ? 90 : 100.0);
		System.out.println(str1.equals(str2));
		// 输出为false
	}
}


      按惯性的理解,变量i的值小于100,应该str1和str2都只取三元运算符中的一个值,也就是90,但从上面的例子当中,看出并不是如此,这是因为Java是强类型,编译器在编译时必须要确定值的类型,条件为真时返回int,条件为假时返回float,编译器是不允许的,所有通过转换,将三元运算表达式的返回值转换为类型返回较大者

3.别让null值和空值威胁变长方法
      在Java5以后,我们可以使用变长方法,请看以下代码

public class Test {

	public static void test(String str, Integer... test) {

	}

	public static void test(String str, String... test) {

	}

	public static void main(String[] args) {
		test("Hello", null);
	}
}


      通过以上方式就可以声明为变长方法,变长参数必须在方法接受参数的最后声明,一个方法只能拥有一个变长参数,若然使用上面的代码,读者会发现编译不通过的现象,这是因为编译器无法明确究竟正在调用哪个test方法,所以在使用变长参数时需要注意,尽量不要出现上面代码中的坏味道代码,若然业务真需求如此,我们可以使用以下方式进行代替

public class Test {

	public static void test(String str, Integer... test) {

	}

	public static void test(String str, String... test) {

	}

	public static void main(String[] args) {
		String str = null;
		test("Hello", str);
	}
}

4.养成良好习惯,显式声明UID
      在javaEE编程当中,对象需要进行网络传输,所以我们应该继承serializable接口,而EJB更是强制要求实现该接口,在我们使用IDE进行开发,没有显式声明UID,eclipse会马上送你一个黄色警告,其实UID的作用就是在JVM序列化时,会比较数据流中的UID与类中的UID是否相同,若然相同则表明类没有发生改变,这是一种非常好的机制,可以保证对象即使在网络或磁盘中'翻滚'一次,仍然能保持'出淤泥而不染'

5.使用序列化类私有方法解决部分属性持久化
      我们都知道,在序列化到磁盘或数据库当中时,static和transient是不会被记录到序列化当中的,但若然我们业务需要将某些变量不对外泄露,但又需要保持到数据库或分布式当中时,可以使用如下代码

public class Test implements Serializable {

	private static final long serialVersionUID = -6201315277372663567L;

	private Integer num;
	private Integer num2;
	private String str;

	private void writeObject(ObjectOutputStream oos) throws IOException {
		oos.defaultWriteObject();
		oos.writeInt(num);
	}

	private void readObject(ObjectInputStream ois) throws IOException,
			ClassNotFoundException {
		ois.defaultReadObject();
		num = ois.readInt();
		num2 = 0;
	}
	// 省略 get/set
}


      通过以上代码,在反序列时,num2变量的值会等于0,从而安全的将信息进行隐藏,Java在调用objectOutputStream类把一个对象转换成流数据时,会通过反射检查被序列化的类是否有writeObject方法,并检查是否符合私有,无返回值等方法签名,若有则会委托方法进行对象序列化,而defaultWriteObject则是惯例写在第一句,代表按默认规则写入对象,而writeInt则是一个队列,先进先出.读取时同理

6.避免在循环中读取数据库
      在项目当中,归功与Hibernate的功劳令到我们获取数据库中数据的手续变得非常简单,导致我们在某些时候的编码当中,忽略了使用HQL等手段获取数据,而是在循环当中使用简单的get方法来获取,这导致了产生N+1的问题,若然数据关连较多而且懒加载设置不合理时,效率将会异常减慢,从而导致性能瓶颈的出现,在编写代码特别是在循环当中操作时,要格外注意

7.使用ThreadLocal时需要注意释放
      请观察以下代码

public class Test {

	ThreadLocal<String> test = new ThreadLocal<String>();

	public String getTest() {
		String str = test.get();
		if (str == null) {
			test.set("");
		}
		return str;
	}

	public void setTest(String str) {
		test.set(str);
	}

	public void removeTest() {
		test.remove();
	}
}


      在JavaEE等Web开发当中ThreadLocal的应用非常之多,因为它能将变量提升为线程级别,而恰好我们的Web是基于请求/响应的模式,每次请求就是一个线程,其实原理简单来说可以是将某变量放入了线程的ThreadLocalMap,从而将变量提升为线程级别,关于更多原理请查阅其他文章,而我们需要注意的是removeTest方法,remove方法是JDK1.5后新增的,用来解决ThreadLocal释放资源的问题避免内存溢出,但JDK1.4时就已经提供了自动释放来解决这个问题,为什么1.5还需要增加remove方法?这是因为我们Web程序需要容器,而容器需要提供性能一般都采用线程池,导致线程循环再用不能释放,违背了JDK1.4中新增的线程销毁时自动释放,导致ThreadLocal的变量残留,所以在开发当中要注意remove从而释放资源


总结:
      笔者在本文章中只从《改善Java程序的151建议》中提取部分进行归纳性叙述,推荐各位读者购买这本书,该书不仅从事例中学习,而且涉及到原理,底层的实现,不仅告诉你应该怎么做,还告诉你为什么要这样做.
发表评论
用户名: 匿名