- 浏览: 220199 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
zi_wu_xian:
顶5楼,POI操作word和excel还是太复杂了,并且针对d ...
使用POI操作Excel和Word -
贝塔ZQ:
poi操作word、excel代码好多啊,用插件试试吧,网上不 ...
使用POI操作Excel和Word -
wap816:
@CacheEvict(value = ...
SpringEL详解及应用 -
string2020:
List<Map<String,Map<St ...
开源工具 — Apache Commons Collections -
uniqueX:
mark!
并发编程 — 判断线程安全
前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间拜读了秦小波老师的《改善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
Java从4到5之间有着非常多的变化,那是一个质的飞跃,在Java5之后引入了注解(Annotation),枚举(Enum),枚举(Enum)更符合面向对象的语义性,为开发者带来诸多的便利,注解(Annotation)相信开发过SSH框架的读者对注解绝对不会陌生,而特别是Spring更是大量应用了注解充当配置文件,
1.推荐使用枚举定义常量
常量的声明是每个项目都不可缺少的,又或者是变相使用了数据字典的形式定义了常量,以往我们基本都使用类常量或接口常量的方式声明常量,但Java1.5以后,建议我们使用枚举(Enum)来声明常量,以下我们来看一下两种方式
public interface Test { int SPRING = 0; int Summer = 1; int Autumn = 2; int Winter = 3; }
public enum Test { SPRING, SUMMER, AUTUMN, WINTER }
枚举类型比接口常量声明的方式优势体现在哪里呢?
1.枚举类型声明比接口常量声明更简单
2.枚举类型其值为稳定的,使用起来更加安全和稳定,请看以下例子
public static void main(String[] args) { int num = 1; switch (num) { case TestInterface.spring: System.out.println("Spring"); break; case TestInterface.summer: System.out.println("Summer"); break; case TestInterface.autumn: System.out.println("Autumn"); break; case TestInterface.winter: System.out.println("Winter"); break; default: System.out.println("error"); } // Enum TestEnum enum1 = TestEnum.SUMMER; switch (enum1) { case SPRING: System.out.println(TestEnum.SPRING.name()); break; case SUMMER: System.out.println(TestEnum.SUMMER.name()); break; case AUTUMN: System.out.println(TestEnum.AUTUMN.name()); break; case WINTER: System.out.println(TestEnum.WINTER.name()); break; } }
从上面一段简短的代码就可以看出两者的区别,首先第一段使用接口常量,
若然此时我的num是10呢?能否传递到switch当中,答案当然是完全可以的,
而枚举呢?甚至不需要编写default,因为在case当中已经穷举了所有的枚举
类型,而枚举类型只的值只能限制与枚举所声明的,还有一点,当我想要把
0 = spring时,我可以怎么做?像作者一样写一个switch吧.而枚举类型只需
要简单的调用.name()即可获得枚举类型的名字,也就是SPRING
3.枚举类型具有内置方法,从上面已经可以看出枚举类型具有name方法获取
枚举的名字,当然还有values()方法返回1个枚举类内的枚举型,ordinal()
返回枚举类型的下标等等.
4.枚举类型可以自定义方法,每个枚举类中的枚举类型实际上就是枚举类的
一个对象,一个实例,对象当然可以拥有方法,构造方法,非静态方法等,但枚
举类型不能继承,枚举类型除非重构,否则是无法扩展的,在项目当中推荐使
用枚举代替接口常量
2.使用构造函数描述枚举项
当我们想要使用一个业务逻辑,当使用枚举值为SPRING,但想返回中文为春天时,我们可以怎么做的?此时枚举项的构造函数将会帮助你有效完成
public enum TestEnum { SPRING("春天"), SUMMER("夏天"), AUTUMN("秋天"), WINTER("冬天"); private String name; TestEnum(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
就像编写普通的构造函数一样编写枚举类的构造函数即可,但注意,枚举类型的构造函数是不能有public修饰的构造函数,构造函数都是隐含private,编译器自动处理,每个枚举值隐含都是由public static final修饰的,不需要添加这些修饰符。,此时当使用枚举时调用getName()方法即可获得春,夏,秋,冬,而使用接口常量要实现以上逻辑,2个字,麻烦
3.注意枚举的空值
我们注意,上述曾说过,枚举类型是枚举类的一个实例,对象,那既然是对象当然可以为null,所以在使用switch或枚举类型时,要注意空值的判断
4.在switch的default代码增加异常
上述也曾说过,在使用枚举时,switch当中可以不编写default,因为枚举类型是限定的,稳定的,只要在case当中穷举枚举的值就可以保证不会执行到default,但前提是在case中进行声明,这就涉及到switch和枚举的关系,是非常脆弱的,只要手工增加了多一个枚举,就必须在switch中编写case,当遇到这种情况时,在default中抛出异常或记录日志就变得重要
5.使用valueOf前必须进行检验
每个枚举类都拥有valueOf()的方法,用来将字符串类型的值转换成一个枚举类型,请观察以下代码
public static void main(String[] args) { String str = "Spring"; TestEnum enum1 = TestEnum.valueOf(str); if (enum1 == null) System.out.println("转换失败"); else System.out.println("转换成功"); // 很遗憾,程序运行结果抛出java.lang.IllegalArgumentException }
从上面可以看到.我们已经对enum1进行了空值判断,那为什么还会抛出异常呢?原因是异常在调用valueOf()方法时已经抛出,注意我们的枚举是SPRING,而不是Spring,因大小写区分导致失败,我们可以用以下方式来进行判断
public static void main(String[] args) { String str = "Spring"; TestEnum enum1 = null; for (TestEnum e : TestEnum.values()) { if (str.equals(e.getName())) { enum1 = TestEnum.valueOf(str); } } // 先进行判断即可解决异常参数问题 }
6.使用枚举工厂代替工厂
以下代码为工厂模式的传统实现
interface Car { } class FordCar implements Car { } class BuickCar implements Car { } class CarFactory { public static Car createCar(Class<? extends Car> c) { try { return (Car) c.newInstance(); } catch (Exception e) { e.printStackTrace(); } return null; } }
以上代码为实现工厂模式的其中一种,当然亦可以传递字符串通过反射创建等等,以下就来看一下使用枚举类型的实现
public enum CarFactory { FordCar { @Override public Car createCar() { return new FordCar(); } }, BuickCar { @Override public Car createCar() { return BuickCar(); } }; public abstract Car createCar(); }
枚举当中亦可定义抽象方法,通过抽象方法强制要求每个枚举项都需要实现该方法,而不同的枚举项返回不同的子类,从而实现了工厂方法,使用枚举类型实现工厂方法有以下三个优点
1.避免错误调用的发生,一般的工厂模式的生产方法都是接受字符串,int类
型,Class等,但这三种参数是具有宽度的,例如null,边界问题,或Car.class
等,而且出现这种问题编译时还是可以正常通过的,造成了不必要的错误
2.降低类之间的耦合,不管生产方法接受的是String,int或class,这些都不是
客户端必须的,而是工厂方法需要的限制,例如class,他必须要传递一个子
类型的class才能实例化该类型,这严重违背了迪米特原则,也就是最少知识
原则,一个对象应该对其他对象最少的了解
3.性能好,使用便捷,枚举类型是以int类型的计算为基础,这是Java中最基本
的操作,速度当然是非常快速的,至于使用便捷,从代码中就可以看出,我是
汽车工厂,我需要一辆别克汽车,完全具备面向对象应该拥有的语义性
7.枚举项的数量限制在64个以内
为什么要枚举类型要限制在64个以内呢?在看这个问题之前首先我们要知道,JDK为了帮助我们更方便的处理枚举类型,为我们提供了EnumSet和EnumMap两个集合,该集合的详细方法请参考JDK帮助文档,以下来看一段代码
public static void main(String[] args) { EnumSet<TestEnum> enumSet = EnumSet.allOf(TestEnum.class); // LargeTestEnum数量为>64 EnumSet<LargeTestEnum> enumSet2 = EnumSet.allOf(LargeTestEnum.class); System.out.println(enumSet.getClass()); // 输出为java.util.RegularEnumSet System.out.println(enumSet2.getClass()); // 输出为java.util.JumboEnumSet }
从以上代码可以看到,仅仅因为多出一个枚举类型就导致EnumSet的实现类不一样,这是因为JDK在遇到枚举类型小于等于64个的时候会创建java.util.RegularEnumSet,而遇到大于64时则会创建java.util.JumboEnumSet,这是因为底层JDK使用了Long类型进行了映射,我们都知道Long类型是64位的,而枚举类型又可以化为整数来储蓄,刚好64个枚举类型对应到Long类型的64位进行存储,而当大于64时,则需要使用java.util.JumboEnumSet来创建,使用了Long数组进行存储
======================我是枚举和注解的分割线====================
8.小心注解继承
请观察以下代码
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Inherited public @interface TestAnnotation { String test() default "Hello World"; }
以上代码就是声明了一个注解,其中该注解上的三个注解为原元注解,@Retention表示运行时的保留级别,@Target代表该注解可以被方式在什么地方,@Inherited代表该注解是否可以被继承,而需要注意的地方就是@Inherited,例如类A使用了增加了@Inherited的注解,类B继承类A,会将增加在类A的注解一并继承下来,这样做利有弊,利的地方是当为父类增加了注解就可以让子类自动继承,从而达到整齐,统一和方便管理,而弊的地方就是从代码阅读的层面上,只阅读子类代码无法了解到该注解,这是非常糟糕的设计,所以能不使用时尽量不要使用@Inherited
9.注解配合枚举使用威力更大
注解中声明的类型可以是枚举类型,这样配合使用将更加能表达语义
10.注意@Override版本问题
在Java5的编译环境是,若复写父类方法是,父类若然是接口,增加@Override则不能算是复写,会报出编译错误,而若然是Java6则进行了宽松处理,实现接口方法亦可以增加@Override,若然是Java6移植到Java5的环境上,就需要注意了
总结:
笔者在本文章中只从《改善Java程序的151建议》中提取部分进行归纳性叙述,推荐各位读者购买这本书,该书不仅从事例中学习,而且涉及到原理,底层的实现,不仅告诉你应该怎么做,还告诉你为什么要这样做.
评论
4 楼
ray_yui
2013-08-28
zjf201172653 写道
楼主:
枚举类型的构造函数是没有访问修饰符的,这句话有问题吧?
(1)枚举类不能有public修饰的构造函数,构造函数都是隐含private,编译器自动处理。
(2)每个枚举值隐含都是由public、static、final修饰的,不需要添加这些修饰符。
枚举类型的构造函数是没有访问修饰符的,这句话有问题吧?
(1)枚举类不能有public修饰的构造函数,构造函数都是隐含private,编译器自动处理。
(2)每个枚举值隐含都是由public、static、final修饰的,不需要添加这些修饰符。
非常感谢你的提醒,是我没有注意到这个问题..
3 楼
zjf201172653
2013-08-28
楼主:
枚举类型的构造函数是没有访问修饰符的,这句话有问题吧?
(1)枚举类不能有public修饰的构造函数,构造函数都是隐含private,编译器自动处理。
(2)每个枚举值隐含都是由public、static、final修饰的,不需要添加这些修饰符。
枚举类型的构造函数是没有访问修饰符的,这句话有问题吧?
(1)枚举类不能有public修饰的构造函数,构造函数都是隐含private,编译器自动处理。
(2)每个枚举值隐含都是由public、static、final修饰的,不需要添加这些修饰符。
2 楼
zeroman1212
2013-08-27
拜读,有空深入使用一下,在项目当中使用。
1 楼
aine_pan
2013-08-27
不得不提的《Effective Java》,作者是不是看过这本书?
不过写的不错!支持一下!
不过写的不错!支持一下!
发表评论
-
并发编程 — 实现线程安全
2015-08-12 09:03 2308并发编程系列文章: 初解线程池:http://r ... -
并发编程 — 优化小技巧
2015-08-10 23:54 0并发编程系列文章: 初解线程池:http://r ... -
并发编程 — 判断线程安全
2015-08-05 10:11 5557并发编程系列文章: ... -
并发编程 — volatile
2015-07-30 10:11 2201并发编程系列文章: 初解线程池:http://r ... -
数据库储存不确定实体
2014-07-08 09:52 2294相信在项目开发当中都曾经遇到过,有某些要储蓄到数 ... -
同步操作降低效率解惑
2014-06-30 10:20 3295相信在读者刚接触Java的时候,都曾经学习到线程 ... -
并发编程 — 并发数据结构
2014-06-24 09:58 6640并发编程系列文章: 初解线程池:http://r ... -
并发编程 — 并发数据类型
2014-06-16 10:03 5451并发编程系列文章: 初解线程池:http://r ... -
并发编程 — 详解线程池
2014-06-03 09:51 6014本文章需要对JDK5 Executor框架有所了解,请读者先 ... -
并发编程 — 初解线程池
2014-05-28 09:57 7556并发编程系列文章: 初解线程池:http://r ... -
线程池详解
2014-05-26 18:20 0本文章需要对JDK5 Executor框架有所了 ... -
高级字节码生成工具 — Javassist
2014-03-11 09:57 6426AOP系列文章: Spring AOP:http ... -
实现AOP — CGLIB
2014-03-06 09:50 3977AOP系列文章: Sp ... -
实现AOP — Spring AOP
2014-03-03 10:02 4269AOP系列文章: Spring AOP:http ... -
cglib
2014-01-11 19:11 0什么是CGLIB? CGLIB是一个强大的高性能 ... -
Java高质量代码之 — 杂
2013-09-16 09:53 4747前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间 ... -
Java高质量代码之 — 异常
2013-09-09 09:35 6743前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间 ... -
Java高质量代码之 — 泛型与反射
2013-08-29 09:36 18073前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间 ... -
Java高质量代码之 — 数组与集合(2)
2013-08-23 17:24 2908前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间 ... -
Java高质量代码之 — 数组与集合(1)
2013-08-21 12:24 7253前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间 ...
相关推荐
总结来说,枚举类和注解是Java中两个强大的特性,枚举类提供了一种规范的方式来定义和使用常量,而注解则为代码提供了元数据,用于代码的管理和自动化处理。熟练掌握这两个概念,能够提高代码质量,增强可维护性和可...
通过这些示例代码的学习,开发者可以更好地掌握Java的核心概念,并将其应用于实际项目中,提高开发效率和代码质量。记得实践是检验真理的唯一标准,理论学习的同时,务必动手实践,不断调试和完善代码。
总的来说,Java注解提供了一种强大的机制,允许程序员在代码中嵌入元数据,这些数据可以被工具和库解析,从而简化了开发过程,提高了代码质量和可维护性。随着Java版本的更新,更多的内置注解和API被添加,使得注解...
Java代码规范是编程界的一本重要...以上这些规范旨在帮助开发者写出高质量、易维护的Java代码,提高团队协作效率。通过阅读《java代码规范》这本书,你可以更深入地理解和实践这些原则,成为一名更优秀的Java程序员。
Java代码编程规范是确保代码可读性、可维护性和团队协作效率的重要指导原则。遵循一套良好的编程规范,可以使代码更加整洁、易于理解,减少出错的...遵循这些规范将帮助开发者编写出更高质量、更易于维护的Java代码。
Java作为世界上最流行的编程语言之一,其核心技术源代码是学习和理解Java编程的基石。这个压缩包文件包含了"卷一"和"卷二"两个部分,很可能是对Java核心技术的深入剖析,涵盖了基础到高级的主题。下面,我们将详细...
总结起来,枚举、注解和内部类是Java编程中提高代码质量和灵活性的重要工具。枚举用于表示固定集合的值,增强可读性和安全性;注解提供了元数据,便于代码管理和验证;内部类则允许我们在类之间建立更紧密的联系,...
这个库允许开发者通过简单的API来构建和编写高质量的Java源代码,极大地简化了在Java项目中自动生成代码的过程。`javapoet-master`是一个包含JavaPoet源码的压缩包,用于深入理解和学习如何使用这个库。 JavaPoet的...
最后,Java核心技术范例代码.zip可能包含Java核心库的各种应用场景,如集合框架(List、Set、Map等)、异常处理、IO流、反射、泛型、枚举、注解等。这些是Java开发的基础,深入学习可以提升编程效率和代码质量。 总...
Java 安全与质量编码规范的制定旨在提高 Java 应用系统的整体质量与安全水平,为指导开发团队编写高质量的代码编码,并在软件开发生命周期的早期提供质量和安全保障。 术语 * “正例”:正确的代码编写示例,可...
通过以上这些高级用法,你可以更加灵活地在Java项目中使用枚举,提高代码的质量和可读性。枚举不仅可以表示固定集合的常量,还可以实现复杂的逻辑,是Java编程中不可或缺的一部分。理解并熟练运用这些技巧,将使你在...
在软件开发过程中,Java作为一种广泛使用的编程语言,其代码的质量直接影响到软件的性能、可维护性和可扩展性。...遵循这些建议可以帮助Java开发者写出更高质量、更易于维护和扩展的代码,从而提高整个项目的成功率。
通过这个教程,学习者将能够逐步掌握Java编程的各个方面,从而能够独立开发高质量的Java应用程序。为了充分利用这些资源,建议按照章节顺序学习,并动手实践每一个示例,同时结合实际问题进行思考,这样能更好地吸收...
在Java开发过程中,自动生成代码是一项非常实用的功能,可以显著提高开发效率,减少重复劳动...通过理解并掌握这种技术,开发者可以更好地组织项目结构,减少手动编写基础代码的时间,从而更快地交付高质量的软件产品。
Java的高级特性主要涵盖泛型、枚举、增强for循环(也称为foreach循环)、注解(Annotation)以及可变参数等。这些特性极大地提升了Java语言的灵活性、安全性和可读性,是Java开发者必备的知识点。 1. **泛型**: ...
总之,阿里巴巴Java代码规约插件p3c通过类图解析,对代码进行全方位的质量把控,帮助开发者遵循最佳实践,编写更高质量、更易于维护的Java代码。在日常开发中,结合插件的提示,不断优化和完善类图设计,将有力提升...
10. **高级话题**:`ch13`可能涉及反射、泛型、枚举、注解等Java的高级特性,以及一些实用的API和设计模式。 通过这个教程的源代码,学习者可以动手实践每一个知识点,加深对Java编程的理解。同时,教师也可以利用...
2. **注释与文档**:良好的注释是代码可读性的关键。指南建议为每个类、接口和公共方法添加 Javadoc,对私有方法也应有适当注释,以便于团队协作和代码理解。 3. **异常处理**:推荐使用具体的异常类型,避免使用...