JAVA语言中的一些坑

1. 求长度各有千秋

你是否曾经在面试的时候,经常被问到:数组有没有 length() 方法?字符串有没有 length() 方法? 集合有没有 length() K a) 方法?

面对这个问题,那么不得不吐槽一下,Java 中获取长度的方式,设计着实有点乱,对刚入门的程序猿而言,那绝对是一脸的懵逼。

String[] array = {\"abc\", \"def\"};

String str = \"abcedf\";

List<String> list = new Array% S u F 0 i d j ?List<String>();

list.add(\v I"abc\");

list.add(\"def\");

System.out.pri@ L o D _ntln(\"数组的长度: \" +U Y z ! E r Z Q array.len` 0 . . ~gth);

System.out.println(\"字符串的长度: \" + str.length+ / d e());8 e T ]

System.v @out.println(\"k [ 1 F T j V O 4集合的长度: \" + li- n 1st.size());

  

正式科普一下,希望能够铭记` o d 4 z ~ t n m你心中。数组求长度用 length 属性;字符串求长度用 length() 方法;集合求长度用 siv M u u x 3 ? | yze() 方法。

2. 字符串截取有深意

对于程序猿来说,编程规范能够养成K Q 4 O B g P 0 良好的编程习惯,提高v 3 p g I I代码质量,减少沟通成本。阿里 Java 开发手册编程规约中记载,【强制】方法名、參数名、成员变量、Y h - L / m局部变量都统一使用 lowerCa; $ & L I ;melCase 风格,必须遵从驼峰形式。

看到这里,不得不提 String 中的 substring 方= s ^法,你是不是经常把“substring”写成k z f Y“subString”。本次这个命名不是吐槽的重点。主要想分享如下代码片段。

public claK v ^ 2 # Kss StringInterview {

publi 3 = + Ac static voidH ^ d j Z ` { main(String[] args) {

String str = \".....J / g 3.ab} $ 7 V ! vcdefgh..- ? g & P @ 5 @.....\";

String subStr = s/ 4 c $ s 3tr.sw 8 + m C * : |ubstring(1,3);

str = null;

System.out.println(s i P x a d k HsubSf u Y 4tr);

}

}

  

假如上述这段程z r , G E m # [ $序在 Java 1.6 中运行,代码中虽然强制使` t ! str 引用为空,本意是释放 str 占用的空间,但是这个时候,GC 是无法回收这个大的 char 数组的,因为还在被_ i e C O m W j su W : [ H GbStr 字符串内部引用着,虽然 subStr 只截取这个大数组的一小部分。当 str 是一个非常大字符串的时候,这种浪费是非常明显的,甚至会带来内存泄露问题。

深入 Java 1.6 中 substring 的设计一探究竟。

public Stri* j 3 m y ] Cng substring(int beginIndex, int endIndex) {

if (begiz ~ ! R PnIndex < 0) {

。。 。。 。。

}

if (endIndex > count) {

。。 。。 。。

}

if (beginIndex > endIn~ V V ~ {dex) {

。。 。。 。。

}

re% - #turn ((beginIndex == 0) && (endIndex == count)) ? this :

new String(offsw = Y ;et + beginIndex, endIndex - beginIndex, value);

}

  

上述方法调用的构造方法

String(int oq s S 7 b F g Pffset, int count, char value[k s E Y]) {

this.value = value;

this.offset = offset;

this.count = count;# : R

}

  

到此你应该拨云见日豁然开朗。当我们调用字符串 str 的 substriR : ( I J c ( % ing 得到字符串 subStr,其实这个操作,无非就是调整了一下 subStr 的 offset 和 count ,用到的内容W / A =还是 str 之前的 value 字符数组,并没有重新创建新的专属于 subStr 的内容字符数组。如果 subStr 的生命周期要长于 str 或者手动设置 str 为null,当垃圾回收进行后,str 被回收掉,subStr 没有回收掉,那么内存占用依旧存在,因为 subStr 持有 str 字符数组的引用。

正式科普一下,这个问题出现在 Java 1.6d i V ^,并且 Java 1.7 中已经修复。虽然已经修复,并不代表我们2 O x D f (就不需要了解,如果你正在求职路上,稍微了解一下,说不定会加分。

3. 一条 if 语句引发不满

先给各位抛一段 Java LinkedList 类的代码片段,一起吐槽吐槽。

public E getFirst() {

final Node<EM H | r V> f = first;

if (f == null)

throw new N- ` r ;oSuchEleme% U : K S HntException();

return f.item;

}

  

JDK 中 if 语句后只有一条语句,大部分都是这么实现的。原则上,if 语句如果后面跟着只有一句话,是可以* % O不加的。但是在我们实际开发中,有些现象却会让你匪夷所思,不信你看看下面的代码片段。

片段一:

if (f == null)

//抛出r g % = k R s ~异常,或者加一条打W 6 2印语句,加上此句注释逻辑就变了

throw new NoS; o s ~ f Kuchz y RElementException();

  

片段二:

public class Interview {

public static void main(String[] args) {

Class c = Inv 2 = - : h X ]terview.class;

try {

Object o = c.newInstan[ ] H e c | Mce();

if (o in8 U d i - ? , P Ystanceof Interview)

Interview tt = (Ir ` J $ nterview) o; //为什么会报错?请各位. 7 8 / ,解释原因

} catch (Exception e) {

e.printSr A W u ]tackTrace();

}

}

}

  

正式科普一下,看似a J n M N i P个简单的编码规范,背后隐藏了多少坑啊,所以为了良好的编程习惯,建议还是统~ g - .一加上大括号为好,良好的编码习惯是真重要啊。

4. 时间实现也找茬

Tiago Fernandez 做过一& b V ) : L f ( D次投票,选举最烂的 Java API,排第二的就是日期 AP% 7 X 7 1 [I(Date 和Calender)。一言不合就抛代码,如下片段是计算两个日期之间的天数。

public static void main(String[] args) {

Calendar begin =& B n Calendar.getInstance- . O();

begin.set(1990, Calendar.JUNE, 17);

Calendar enV U E g G 1 xd = Calendar.getInstance();

System.out.println(alculc ^ r UatedDays(begin, end));

System.out.println(alculated8 Q aDays(begin, end)); // 为什么显示 0?

}

public static long alculatv . x 9 qedDays(Calendar begin, CQ x D u U } X walendar end) {

long days = 0;

while (begin.E $ 6before(end)) {

begin.add(Calendar.DAY_OF_MONTHF 7 l h h R (, 1);

days++;

}

return days;

}

alculatedDays 方法,如果连续P ` G计算两个 Date 实例的话,第二次会取得 0,因为 Calendar 状态是可变D R h j / n的,考虑到重复计算的场合/ l 4 a 2,最好复制一个新的 Calendar,改造如下

public stati1 ? 9 . 4 -c long alculatedDays(C# O Z ^ zal7 P V k jendar begin, Calendar end) {

Calendar calenP 7 Y F & I 0 ^ 0dar = (Calendar) begin.clone(); // 复制

long days = 0;

while (ca8 | L ) L ^ & Tlend| X d 6 0ar.before(end)) {

calendar.add(Calendar.DAY_Og * M W L X #F_MONTH, 1);

days++;

}

return days;

}

  

不过万物都在向前进化,因为由于原y r 8 u来老旧的日期 API 一直被人诟病,所以 JDw Q U gK 1.8 中对日期的改动是特别大的,基本上是引入了一套全新易用的 API,各位有时间可以体验一下。

评论已经被关闭。

插入图片
返回顶部