java程序的151个建议
文章平均质量分 75
你是我的天晴
wx:lexang
展开
-
java程序的151个建议-提倡异常封装,采用异常链传递异常
Java语言的异常处理机制可以确保程序的健壮性,提高系统的可用率,但是Java API提 供的异常都是比较低级的(这里的低级是指“低级别”的异常),只有开发人员才能看得懂, 才明白发生了什么问题。而对于终端用户来说,这些异常基本上就是天书,与业务无关,是纯计算机语言的描述,那该怎么办?这就需要我们对异常进行封装了。异常封装有三方面的 优点:(1) 提髙系统的友好性例如,打开一个文件,如原创 2022-01-14 17:23:42 · 160 阅读 · 0 评论 -
不同的列表选择不同的遍历方法
我们来思考这样一个案例:统计一个省的各科髙考平均值,比如数学平均分是多少,语文平均分是多少等,这是每年招生办都会公布的数据,我们来想想看该算法应如何实现。当 然使用数据库中的一个SQL语句就能求出平均值,不过这不再我们的考虑之列,这里还是使用纯;lava的算法来解决之,看代码:public static void main(String[]args) {//学生数量,80万int st原创 2022-01-14 16:36:33 · 140 阅读 · 0 评论 -
警惕数组的浅拷贝
有这样一个例子,第一个箱子里有赤橙黄绿青蓝紫7色气球,现在希望在第二个箱子中也放入7个气球,其中最后一个气球改为蓝色,也就是赤橙黄绿青蓝蓝7个气球,那我们很 容易就会想到第二个箱子中的气球可以通过拷贝第一个箱子中的气球来实现,毕竟有6个气 球是一样的嘛,来看实现代码:public class Balloon { //编号 private int id; //颜色 private原创 2015-11-01 13:35:43 · 637 阅读 · 0 评论 -
由点及面,一叶知秋——集合大家族
Java中的集合类实在是太丰富了,有常用的ArrayList、HashMap,也有不常用的Stack、 Queue,有线程安全的Vector、HashTable,也有线程不安全的LinkedList、TreeMap,有阻塞 式的ArrayBIockingQueue,也有非阻塞式的PriorityQueue等,整个集合家族非常庞大,而 且也是错综复杂,可以划分为以下几类:(1) List原创 2015-11-01 23:42:51 · 725 阅读 · 0 评论 -
Java的泛型是类型擦除的
Java泛型(Generic)的引入加强了参数类型的安全性,减少了类型的转换,它与C++ 中的模板(Templates)比较类似,但是有一点不同的是:Java的泛型在编译期有效,在运行 期被删除,也就是说所有的泛型参数类型在编译后都会被清除掉,我们来看一个例子,代码如下:public class Foo { public void arrayMethod(String[] strArra原创 2015-11-02 00:16:11 · 429 阅读 · 0 评论 -
不能初始化泛型参数和数组
泛型类型在编译期被擦除,我们在类初始化时将无法获得泛型的具体参数,比如这样的代码:class Foo{ private T t =new T(); private T[] tArray=new T[5]; private List list= new ArrayList();}这段代码有什么问题呢? t、tArray、list都是类变量,都是通过new声明了一个类型, 看起来非常原创 2015-11-02 00:37:22 · 3092 阅读 · 1 评论 -
多线程使用Vector或HashTable
Vector是ArrayList的多线程版本,HashTable是HashMap的多线程版本,这些概念我 们都很清楚,也被前辈嘱咐过很多次,但我们经常会逃避使用Vector和HashTable,因为用 得少,不熟嘛!只有在真正需要的时候才会想要使用它们,但问题是什么时候算真正需要呢?我们来看一个例子,看看使用线程安全的Vector是否可以解决问题,代码如下: //火车票列表 final原创 2015-11-01 23:28:11 · 1904 阅读 · 0 评论 -
集合运算时使用更优雅的方式
在初中代数中,我们经常会求两个集合的并集、交集、差集等,在Java中也存在着此 类运算,那如何实现呢? 一提到此类集合操作,大部分的实现者都会说:对两个集合进行遍历,即可求出结果。是的,遍历可以实现并集、交集、差集等运算,但这不是最优雅的处理方式。下面来看看如何进行更优雅、快速、方便的集合操作。(1) 并集也叫做合集,把两个集合加起来即可,这非常简单,代码如下:pub原创 2015-11-01 21:09:35 · 469 阅读 · 0 评论 -
不同的列表选择不同的遍历方法
我们来思考这样一个案例:统计一个省的各科髙考平均值,比如数学平均分是多少,语文平均分是多少等,这是每年招生办都会公布的数据,我们来想想看该算法应如何实现。当 然使用数据库中的一个SQL语句就能求出平均值,不过这不再我们的考虑之列,这里还是使用纯;lava的算法来解决之,看代码:public static void main(String[] args) { int num=80*10000;原创 2015-11-01 17:35:19 · 445 阅读 · 0 评论 -
多种最值算法,适时选择
对一批数据进行排序,然后找出其中的最大值或最小值,这是基本的数据结构知识。在Java中我们可以通过编写算法的方式,也可以通过数组先排序再取值的方式来实现。下面以求最大值为例,解释一下多种算法。(1) 自行实现,快速査找最大值先来看用快速査找法取最大值的算法,其代码如下: public static int max(Integer[] datas){ int max=datas[0]原创 2015-11-01 14:58:24 · 1407 阅读 · 0 评论 -
asList方法产生的List对象不可更改
上一个建议指出了 asList方法在转换基本类型数组时存在的问题,接着我们看一下 asList方法返回的列表有何特殊的地方,代码如下所示:public static void main(String[] args) { Week[] workDays={Week.Sun,Week.Mon,Week.Tue,Week.Wed,Week.Fri}; List list=Arrays.asLis原创 2015-11-01 15:24:13 · 1014 阅读 · 0 评论 -
性能考虑,数组是首选
数组在实际的系统开发中用得越来越少了,我们通常只有在阅读一些开源项目时才会看到它们的身影,在Java中它确实没有List、Set、Map这些集合类用起来方便,但是在基本 类型处理方面,数组还是占优势的,而且集合类的底层也都是通过数组实现的,比如对一个数据集求和这样的计算://对数组求和public static int sum(int[] datas){ for(int原创 2015-10-31 19:03:01 · 430 阅读 · 0 评论 -
推荐使用string直接量来赋值
一、分析 Java为了避免在一个系统中大量产生String对象,于是就设计了一个字符串池(也有叫做字符串常量池),在字符串池中所容纳的都是String字符串对象。 String创建规则:创建一个字符串时,首先没有检查池中是否有字面值相等的字符串。 如果有,则不再创建,直接返回池中该对象的引用。 如果没有则创建之,然后放到池中,并返回新建对象的引用。转载 2015-10-29 23:34:23 · 503 阅读 · 0 评论 -
覆写equals方法必须覆写hashCode方法
覆写equals方法必须覆写hashCode方法,这条规则基本上每个Javaer都知道,这也是JDK API上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢?本建议就来解释该问题,我们先来看如下代码:public static void main(String[] args) { // Person类的实例作为Map的key MapPerson, Ob转载 2015-10-29 22:58:38 · 1819 阅读 · 0 评论 -
在equals中使用getClass进行类型判断
本节我们继续讨论覆写equals的问题。这次我们编写一个员工Employee类继承Person类,这很正常,员工也是人嘛,而且在JEE中JavaBean有继承关系也很常见,代码如下:class Employee extends Person{ private int id; /*id的getter/setter方法省略*/ public Employee(S转载 2015-10-29 20:36:52 · 1799 阅读 · 0 评论 -
避开基本类型数组转换列表陷阱
我们在开发过程中经常会使用Arrays和Collections这两个工具类在数组和列表之间转 换,非常方便,但也有时候会出现一些奇怪的问题,来看如下代码: public static void main(String[] args) { int[] i={23,89,13,0,56}; List list=Arrays.asList(i); System.out.print原创 2015-11-01 15:04:27 · 482 阅读 · 0 评论 -
不要随便设置随机种子
随机数在太多的地方使用了,比如加密、混淆数据等,我们使用随机数是期望获得一个唯一的、不可仿造的数字,以避免产生相同的业务数据造成混乱。在Java项目中通常是通过Math.random方法和Random类来获得随机数的,我们来看一段代码:public class Client { public static void main(String[] args) {原创 2015-11-01 16:55:56 · 4880 阅读 · 1 评论 -
若有必要,使用变长数组
Java中的数组是定长的,一旦经过初始化声明就不可改变长度,这在实际使用中非常不方便,比如要对班级学生的信息进行统计,因为我们不知道一个班级会有多少学生(随 时都可能会有学生入学、退学或转学),所以需要有一个足够大的数组来容纳所有的学生,但问题是多大才算足够大? 1〇年前一台台式机64MB的内存已经很牛了,现在要是没有 2GB的内存你都不好意思跟别人交流计算机的配置,所以呀,这个足够大是相对于当时原创 2015-11-01 09:11:36 · 725 阅读 · 0 评论 -
不推荐覆写start方法
多线程比较简单的实现方式是继承Thread类,然后覆写run方法,在客户端程序中通过 调用对象的start方法即可启动一个线程,这是多线程程序的标准写法。不知道读者是否还能回想起自己的第一个多线程demo呢?估计一般是这样写的:class MultiThread extends Thread{ @Override public void start(){ //调用线在体原创 2015-11-13 13:15:28 · 671 阅读 · 0 评论 -
不使用stop方法停止线程,停止线程的最佳办法
线程启动完毕后,在运行时可能需要终止,Java提供的终止方法只有一个stop,但是我 不建议使用这个方法,因为它有以下三个问题:(1) stop方法是过时的从Java编码规则来说,已经过时的方法不建议采用。(2) stop方法会导致代码逻辑不完整stop方法是一种“恶意”的中断,一旦执行stop方法,即终止当前正在运行的线程,不 管线程逻辑是否完整,这是非常危险的。看如下的代码原创 2015-11-13 16:22:22 · 18928 阅读 · 1 评论 -
线程优先级只使用三个等级
线程的优先级(Priority)决定了线程获得CPU运行的机会,优先级越髙获得的运行机 会越大,优先级越低获得的机会越小。Java的线程有10个级别(准确地说是11个级别,级 别为〇的线程是JVM的,应用程序不能设置该级别),那是不是说级别是10的线程肯定比 级别为9的线程先运行呢?我们来看如下一个多线程类:public class TestPriorityThread implements原创 2015-11-17 12:42:48 · 6966 阅读 · 0 评论 -
使用线程异常处理器提升系统可靠性
我们要编写一个Socket应用,监听指定端口,实现数据包的接收和发送逻辑,这在早期系统间进行数据交互是经常使用的,这类接口通常需要考虑两个问题:一是避免线程阻塞, 保证接收的数据尽快处理;二是接口的稳定性和可靠性问题,数据包很复杂,接口服务的系统也很多,一旦守候线程出现异常就会导致Socket停止响应,这是非常危险的,那我们有什 么办法来避免吗?Java 1.5版本以后在Thread类中增加了原创 2015-11-17 14:19:28 · 658 阅读 · 0 评论 -
异步运算考虑使用Callable接口 有返回值的线程
多线程应用有两种实现方式,一种是实现Runnable接口,另一种是继承Thread类,这 两个方式都有缺点:run方法没有返回值,不能抛出异常(这两个缺点归根到底是Runable 接口的缺陷,Thread也是实现了 Runnable接口),如果需要知道一个线程的运行结果就需要用 户自行设计,线程类自身也不能提供返回值和异常。但是从Java 1.5开始引入了一个新的接口 Callable,它类似于R原创 2015-11-17 17:29:58 · 940 阅读 · 0 评论 -
Lock与synchronized是不一样的
很多编码者都会说,Lock类和synchronized关键字用在代码块的并发性和内存上时语义 是一样的,都是保持代码块同时只有一个线程具有执行权。这样的说法只对了一半,我们以一个任务提交给多个线程运行为例,来看看使用显式锁(Lock类)和内部锁(synchronized 关键字)有什么不同。首先定义一个任务:class Task{ public void doSomething(){ t原创 2015-11-17 23:17:18 · 1022 阅读 · 0 评论 -
提升Java性能的基本方法
Java从诞生之日起就被质疑:字节码在JVM中运行是否会比机器码直接运行的效率会 低很多?很多技术高手、权威网站都有类似的测试和争论,从而来表明Java比C (或C++) 更快或效率相同。此类话题我们暂且不表(这类问题的争论没完没了,也许等到我们退休的时候,还想找个活动脑筋的方式,此类问题就会是最好的选择),我们先从如何提髙Java的 性能方面入手,看看怎么做才能让Java程序跑得更快,效率更髙,原创 2015-11-18 23:52:50 · 2210 阅读 · 0 评论 -
严格限定泛型类型采用多重界限
从哲学上来说,很难描述一个具体的人,你可以描述它的长相、性格、工作等,但是人都是有多重身份的,估计只有使用多个And (与操作)将所有的描述串联起来才能描述一个 完整的人,比如我,上班时我是一个职员,下班了坐公交车我是一个乘客,回家了我是父母的孩子,是儿子的父亲……角色时刻在变换。那如果我们要使用Java程序来对一类人进行管 理,该如何做呢?比如在公交车费优惠系统中,对部分人员(如工资低于2500原创 2015-11-03 13:57:44 · 932 阅读 · 0 评论 -
建议采用的顺序是 List<T>、List<?>、List<Object>
List、List、1^这三者都可以容纳所有的对象,但使用的顺序应该是首选List,次之List,最后选择List,原因如下:(1) List是确定的某一个类型List表示的是List集合中的元素都为T类型,具体类型在运行期决定;List表示 的是任意类型,与List类似,而List则表示List集合中的所有元素为Object类 型,因为Object是所有类的父类,所以LiSt也可以容纳所原创 2015-11-02 22:15:50 · 3274 阅读 · 1 评论 -
警惕泛型是不能协变和逆变的
什么叫协变(covariance)和逆变(contravariance)? Wiki上是这样定义的:Within the type system of 阻 programming language,covariance and contravariance refers to the ordering of types from narrower to wider and their inte原创 2015-11-02 22:08:55 · 1086 阅读 · 0 评论 -
强制声明泛型的实际类型
Arrays工具类有一个方法asList可以把一个变长参数或数组转变为列表,但是它有一个 缺点:它所生成的List长度是不可改变的,而这在我们的项目开发中有时会很不方便。如果你期望生成的列表长度是可变,那就需要自己来写一个数组的工具类了,代码如下:class ArrayUtils{//把一个变长参数转变为列表,并且长度可变 public static List asList(T..原创 2015-11-02 21:17:21 · 598 阅读 · 0 评论 -
不同的场景使用不同的泛型通配符
Java泛型支持通配符(Wildcard),可以单独使用一个“? ”表示任意类,也可以使用 extends关键字表示某一个类(接口)的子类型,还可以使用super关键字表示某一个类(接 口)的父类型,但问题是什么时候该用extends,什么时候该用super呢?(1) 泛型结构只参与“读”操作则限定上界(extends关键字)阅读如下代码,想想看我们的业务逻辑操作是否还能继续:原创 2015-11-02 21:44:13 · 560 阅读 · 1 评论 -
覆写equals方法时不要识别不出自己,equals应该考虑null值情景
我们在写一个JavaBean时,经常会覆写equals方法,其目的是根据业务规则判断两个对象是否相等,比如我们写一个Person类,然后根据姓名判断两个实例对象是否相同,这在DAO(Data Access Objects)层是经常用到的。具体操作是先从数据库中获得两个DTO(Data Transfer Object,数据传输对象),然后判断它们是否是相等的,代码如下:class Person{转载 2015-10-29 20:36:01 · 1689 阅读 · 0 评论 -
避免对象的浅拷贝,推荐使用序列化实现对象的拷贝
我们知道一个类实现了Cloneable接口就表示它具备了被拷贝的能力,如果再覆写clone()方法就会完全具备拷贝能力。拷贝是在内存中进行的,所以在性能方面比直接通过new生成对象要快很多,特别是在大对象的生成上,这会使性能的提升非常显著。但是对象拷贝也有一个比较容易忽略的问题:浅拷贝(Shadow Clone,也叫做影子拷贝)存在对象属性拷贝不彻底的问题。我们来看这样一段代码:public转载 2015-10-29 00:06:59 · 1300 阅读 · 0 评论 -
构造函数尽量简化
我们知道在通过new关键字生成对象时必然会调用构造函数,构造函数的简繁情况会直接影响实例对象的创建是否繁琐。在项目开发中,我们一般都会制订构造函数尽量简单,尽可能不抛异常,尽量不做复杂算法等规范,那如果一个构造函数确实复杂了会怎么样?我们来看一段代码:public class Client { public static void main(String[] args) {转载 2015-10-19 23:03:47 · 615 阅读 · 0 评论 -
不要覆写静态方法
我们知道在Java中可以通过覆写(Override)来增强或减弱父类的方法和行为,但覆写是针对非静态方法(也叫做实例方法,只有生成实例才能调用的方法)的,不能针对静态方法(static修饰的方法,也叫做类方法),为什么呢?我们先看一个例子,代码如下:public class Client { public static void main(String[] args) {转载 2015-10-18 23:50:23 · 777 阅读 · 0 评论 -
优先选择基本类型
包装类型是一个类,它提供了诸如构造方法、类型转换、比较等非常实用的功能,而且在Java 5之后又实现了与基本类型之间的自动转换,这使包装类型如虎添翼,更是应用广泛了,在开发中包装类型已经随处可见,但无论是从安全性、性能方面来说,还是从稳定性方面来说,基本类型都是首选方案。我们来看一段代码:public class Client { public static void main(S转载 2015-10-18 20:59:31 · 456 阅读 · 0 评论 -
数组的真实类型必须是泛型类型的子类型
先说说ArrayList的toArrayArrayList提供了一个将List转为数组的一个非常方便的方法toArray。toArray有两个重载的方法:1.list.toArray();2.list.toArray(T[] a);对于第一个重载方法,是将list直接转为Object[] 数组;第二种方法是将list转化为你所需要类型的数组,当然我们用的时候会转化为与li原创 2015-11-03 19:10:07 · 1426 阅读 · 0 评论 -
构造函数尽量简化
我们知道在通过new关键字生成对象时必然会调用构造函数,构造函数的简繁情况会直接影响实例对象的创建是否繁琐。在项目开发中,我们一般都会制订构造函数尽量简单,尽可能不抛异常,尽量不做复杂算法等规范,那如果一个构造函数确实复杂了会怎么样?我们来看一段代码:publicclassClient{ publicstaticvoidmain(String[]args){原创 2022-01-14 16:23:48 · 210 阅读 · 0 评论 -
不要让类型默默转换
我们出一个小学生的题目给大家做做看,光速是每秒30万公里,根据光线旅行的时间,计算月亮与地球、太阳与地球之间的距离。代码如下:public class Client { //光速是30万公里/秒,常量 public static final int LIGHT_SPEED = 30 * 10000 * 1000; public static void main转载 2015-10-18 17:30:29 · 359 阅读 · 0 评论 -
用整数类型处理货币
在日常生活中,最容易接触到的小数就是货币,比如你付给售货员10元钱购买一个9.60元的零食,售货员应该找你0.4元也就是4毛钱才对,我们来看下面的程序:public class Client { public static void main(String[] args) { System.out.println(10.00-9.60) ; }转载 2015-10-18 17:20:00 · 770 阅读 · 0 评论 -
不要只替换一个类
我们经常在系统中定义一个常量接口(或常量类),以囊括系统中所涉及的常量,从而简化代码,方便开发,在很多的开源项目中已采用了类似的方法,比如在Struts2中,org.apache.struts2.StrutsConstants就是一个常量类,它定义了Struts框架中与配置有关的常量,而org.apache.struts2.StrutsStatics则是一个常量接口,其中定义了OGNL访问的关键字转载 2015-10-18 16:19:16 · 329 阅读 · 0 评论