当前位置 > 主页 > 万和大讲堂 >


南京Java培训资深讲师总结Java习惯用法

2016-05-03 11:03

  在Java编程中,有些知识 并不能仅通过语言规范或者标准API文档就能学到的。在本文中,南京万和Java培训资深讲师会尽量收集一些最常用的习惯用法,特别是很难猜到的用法。


  目录


  ■实现:


  ◎equals()

  ◎hashCode()

  ◎compareTo()

  ◎clone()


  ■应用:


  ◎StringBuilder/StringBuffer

  ◎Random.nextInt(int)

  ◎Iterator.remove()

  ◎StringBuilder.reverse()

  ◎Thread/Runnable

  ◎try-finally


  ■输入/输出:


  ◎从输入流里读取字节数据

  ◎从输入流里读取块数据

  ◎从文件里读取文本

  ◎向文件里写文本


  ■预防性检测:


  ◎数值

  ◎对象

  ◎数组索引

  ◎数组区间


  ■数组:


  ◎填充元素

  ◎复制一个范围内的数组元素

  ◎调整数组大小


  ■包装


  ◎个字节包装成一个int

  ◎分解成4个字节


  实现equals()



  ○参数必须是Object类型,不能是外围类。

  ○foo.equals(null) 必须返回false,不能抛NullPointerException。(南京万和Java培训提醒大家注意,null instanceof 任意类总是返回false,因此上面的代码可以运行。)

  ○基本类型域(比如,int)的比较使用 == ,基本类型数组域的比较使用Arrays.equals()。

  ○覆盖equals()时,记得要相应地覆盖 hashCode(),与 equals() 保持一致。

  ○参考:java.lang.Object.equals(Object)。


  实现hashCode()



  ○当x和y两个对象具有x.equals(y) == true ,你必须要确保x.hashCode() == y.hashCode()。

  ○根据逆反命题,如果x.hashCode() != y.hashCode(),那么x.equals(y) == false 必定成立。

  ○你不需要保证,当x.equals(y) == false时,x.hashCode() != y.hashCode()。但是南京万和Java培训提醒大家注意,如果你可以尽可能地使它成立的话,这会提高哈希表的性能。

  ○hashCode()最简单的合法实现就是简单地return 0;虽然这个实现是正确的,但是这会导致HashMap这些数据结构运行得很慢。

  ○参考:java.lang.Object.hashCode()。


  实现compareTo()



  ○总是实现泛型版本 Comparable,而不是实现原始类型Comparable。因为这样可以节省代码量和减少不必要的麻烦。

  ○只关心返回结果的正负号(负/零/正),它们的大小不重要。

  ○Comparator.compare()的实现与这个类似。

  ○参考:java.lang.Comparable。


  实现clone()



  ○使用 super.clone() 让Object类负责创建新的对象。

  ○基本类型域都已经被正确地复制了。同样,南京万和Java培训提醒大家注意,我们不需要去克隆String和BigInteger等不可变类型。

  ○手动对所有的非基本类型域(对象和数组)进行深度复制(deep copy)。

  ○实现了Cloneable的类,clone()方法永远不要抛CloneNotSupportedException。因此,需要捕获这个异常并忽略它,或者使用不受检异常(unchecked exception)包装它。

  ○不使用Object.clone()方法而是手动地实现clone()方法是可以的也是合法的。

  ○参考:java.lang.Object.clone()、java.lang.Cloneable()。


  使用StringBuilder或StringBuffer



  ○不要像这样使用重复的字符串连接:s += item ,因为它的时间效率是O(n^2)。

  ○使用StringBuilder或者StringBuffer时,可以使用append()方法添加文本和使用toString()方法去获取连接起来的整个文本。

  ○优先使用StringBuilder,因为它更快。StringBuffer的所有方法都是同步的,而你通常不需要同步的方法。

  ○参考:java.lang.StringBuilder、java.lang.StringBuffer。


  生成一个范围内的随机整数



  ○总是使用Java API方法去生成一个整数范围内的随机数。

  ○南京万和Java培训提醒大家注意,不要试图去使用 Math.abs(rand.nextInt()) % n 这些不确定的用法,因为它的结果是有偏差的。此外,它的结果值有可能是负数,比如当rand.nextInt() == Integer.MIN_VALUE时就会如此。

  ○参考:java.util.Random.nextInt(int)。


  使用Iterator.remove()



  ○remove()方法作用在next()方法最近返回的条目上。每个条目只能使用一次remove()方法。

  ○参考:java.util.Iterator.remove()。


  返转字符串



  ○这个方法可能应该加入Java标准库。

  ○参考:java.lang.StringBuilder.reverse()。


  启动一条线程


  下面的三个例子使用了不同的方式完成了同样的事情。


  实现Runnnable的方式:


  继承Thread的方式:



  匿名继承Thread的方式:



  ○不要直接调用run()方法。总是调用Thread.start()方法,这个方法会创建一条新的线程并使新建的线程调用run()。

  ○参考:java.lang.Thread, java.lang.Runnable。


  使用try-finally


  I/O流例子:


  锁例子:



  ○如果try之前的语句运行失败并且抛出异常,那么finally语句块就不会执行。但无论怎样,在这个例子里不用担心资源的释放。


  ○如果try语句块里面的语句抛出异常,那么程序的运行就会跳到finally语句块里执行尽可能多的语句,然后跳出这个方法(除非这个方法还有另一个外围的finally语句块)。


  从输入流里读取字节数据



  ○read()方法要么返回下一次从流里读取的字节数(0到255,包括0和255),要么在达到流的末端时返回-1。

  ○参考:java.io.InputStream.read()。

  从输入流里读取块数据



  ○南京万和Java培训提醒大家注意要记住的是,read()方法不一定会填满整个buf,所以你必须在处理逻辑中考虑返回的长度。

  ○参考: java.io.InputStream.read(byte[])、java.io.InputStream.read(byte[], int, int)。


  从文件里读取文本



  ○BufferedReader对象的创建显得很冗长。这是因为Java把字节和字符当成两个不同的概念来看待(这与C语言不同)。

  ○你可以使用任何类型的InputStream来代替FileInputStream,比如socket。

  ○当达到流的末端时,BufferedReader.readLine()会返回null。

  ○要一次读取一个字符,使用Reader.read()方法。

  ○你可以使用其他的字符编码而不使用UTF-8,但最好不要这样做。

  ○参考:java.io.BufferedReader、java.io.InputStreamReader。


  向文件里写文本



  ○Printwriter对象的创建显得很冗长。这是因为Java把字节和字符当成两个不同的概念来看待(这与C语言不同)。

  ○就像System.out,你可以使用print()和println()打印多种类型的值。

  ○你可以使用其他的字符编码而不使用UTF-8,但南京万和Java培训提醒大家注意最好不要这样做。

  ○参考:java.io.PrintWriter、java.io.OutputStreamWriter。


  预防性检测(Defensive checking)数值



  ○不要认为输入的数值都是正数、足够小的数等等。要显式地检测这些条件。

  ○一个设计良好的函数应该对所有可能性的输入值都能够正确地执行。要确保所有的情况都考虑到了并且不会产生错误的输出(比如溢出)。


  预防性检测对象



  ○不要认为对象参数不会为空(null)。要显式地检测这个条件。


  预防性检测数组索引



  ○不要认为所以给的数组索引不会越界。要显式地检测它。


  预防性检测数组区间



  ○不要认为所给的数组区间(比如,从off开始,读取len个元素)是不会越界。要显式地检测它。


  填充数组元素


  使用循环:



  (优先)使用标准库的方法:


  Arrays.fill(a, (byte)123);


  ○参考:java.util.Arrays.fill(T[], T)。


  参考:java.util.Arrays.fill(T[], int, int, T)。


  复制一个范围内的数组元素


  使用循环:



  (优先)使用标准库的方法:


  System.arraycopy(a, 3, b, 6, 8);


  参考:java.lang.System.arraycopy(Object, int, Object, int, int)。


  调整数组大小


  使用循环(扩大规模):



  使用循环(减小规模):



  (优先)使用标准库的方法:



  参考:java.util.Arrays.copyOf(T[], int)。

  参考:java.util.Arrays.copyOfRange(T[], int, int)。


  把4个字节包装(packing)成一个int



  把int分解(Unpacking)成4个字节



  总是使用无符号右移操作符(>>>)对位进行包装(packing),不要使用算术右移操作符(>>)。


  文章比较长,但却很实在,看完之后相信你定会有所收获,南京万和Java培训中心作为江苏地区成立最早、规模最大的专业IT教育培训机构,23年来已培养了各类专业IT技术人才超过10w+。后续会为小伙伴们提供更多的IT技术干货,让小伙伴们能够少走弯路。

最近开班 more>
  • Python基础班
  • Java全栈开发
  • 前端基础班
  • 软件测试
  • 云原生精英班
  • 云网预科班
  • CISP
  • HCIE-Datacom(HCIA,HCIP基础)
  • HCIP-Datacom(HCIA基础)
  • HCIA-Datacom(0基础)
  • HCIE-Datacom(HCIA,HCIP基础)
  • HCIP-Datacom(HCIA基础)
  • HCIA-Datacom(0基础)
  • OCM 12C
  • OCP 19C
  • RHCE 9.0
  • 随时开课
  • 12月26日
  • 随时开课
  • 12月4日
  • 12月16日
  • 12月9日
  • 12月21日
  • 1月6日
  • 12月30日
  • 12月16日
  • 12月21日
  • 12月7日
  • 12月7日
  • ——
  • 随时开课
  • 12月16日
    • 姓 名 :
    • 电 话 :
    • 课 程 :

技术交流群

  • Java大数据交流群560819979加入
  • Python技术交流群595083299加入
  • Oracle技术交流群595119011加入
  • Web前端技术交流群604697610加入
  • Huawei技术交流群482919361加入
  • Redhat技术交流群587875348加入
  • UI设计技术交流群511649801加入
  • Cisco技术交流群596886705加入
  • IT运维技术交流群605888381加入