Java100例常见错误及解决方案

经常编写 Java 程序,经常有一些细节大家可能没怎么注意,这里整理、收集汇总了一些我们编程中常见的问题。供大家在学习中参考。
范例 001:Abstract method 必须以分号结尾,且不带花括号
abstractclassName{
privateStringname;
publicabstractbooleanisStupidName(Stringname){}
}
这有何错误?
答案:错。Abstract method 必须以分号结尾,且不带花括号。
范例 002:局部变量前不能放置任何访问修饰符
publicclassSomething{
voiddoSomething(){
privateStrings=“”;
intl=s.length();
}
}
有错吗?
答案:错。局部变量前不能放置任何访问修饰符(private,public,和 protected)。final 可以用来修饰局部变量
(final 如同 abstract 和 strictfp,都是非访问修饰符,strictfp 只能修饰 class 和 method 而非 variable)。
范例 003:abstract 的 methods 不能以 private 修饰
abstractclassSomething{
privateabstractStringdoSomething();
}
这好像没什么错吧?
答案:错。abstract 的 methods 不能以 private 修饰。abstract 的 methods 就是让子类
implement(实现)具体细节的,怎么可以用 private 把 abstract
method 封锁起来呢?(同理,abstractmethod 前不能加 final)。
范例 004:intx 被修饰错误
publicclassSomething{
publicintaddOne(finalintx){
2 / 54
return++x;
}
}
这个比较明显。
答案:错。intx 被修饰成 final,意味着 x 不能在addOnemethod 中被修改。
范例 005:关于 final 的问题
publicclassSomething{
publicstaticvoidmain(String[]args){
Othero=newOther();
newSomething().addOne(o);
}
publicvoidaddOne(finalOthero){
o.i++;
}
}
classOther{
publicinti;
}
和上面的很相似,都是关于 final 的问题,这有错吗?
答案:正确。在 addOnemethod 中,参数 o 被修饰成 final。如果在 addOnemethod 里我们
修改了 o 的 reference
(比如:o=newOther()😉,那么如同上例这题也是错的。但这里修改的是 o 的 membervairable
(成员变量),而 o 的 reference 并没有改变。
范例 006:易错举例
classSomething{
inti;
publicvoiddoSomething(){
System.out.println(“i=”+i);
}
}
有什么错呢?看不出来啊。
答案:正确。输出的是"i=0"。inti 属於 instantvariable(实例变量,或叫成员变量)。
instantvariable 有 defaultvalue。int 的 defaultvalue 是 0。
范例 007:多用了一个 final
classSomething{
finalinti;
3 / 54
publicvoiddoSomething(){
System.out.println(“i=”+i);
}
}
和上面一题只有一个地方不同,就是多了一个 final。这难道就错了吗?
答案:错。finalinti 是个 final 的 instantvariable(实例变量,或叫成员变量)。final 的
instantvariable 没有 defaultvalue,必须在 constructor(构造器)结束之前被赋予一个明确的值。
可以修改为"finalinti=0;“。
范例 008:main 里 calldo Something 使用错误
publicclassSomething{
publicstaticvoidmain(String[]args){
Somethings=newSomething();
System.out.println(“s.doSomething()returns”+doSomething());
}
publicStringdoSomething(){
return"Dosomething…”;
}
}
看上去很完美。
答案:错。看上去在 main 里 calldoSomething 没有什么问题,毕竟两个 methods 都在同一
个 class 里。但仔细看,main 是 static 的。staticmethod 不能直接 callnon-staticmethods。可改
成"System.out.println(“s.doSomething()returns”+s.doSomething());"。同理,staticmethod 不能访
问 non-staticinstantvariable。
范例 009:易被当错的命名
此处,Something 类的文件名叫 OtherThing.java
classSomething{
privatestaticvoidmain(String[]something_to_do){
System.out.println(“Dosomething…”);
}
}
这个好像很明显。
答案:正确。从来没有人说过 Java 的 Class 名字必须和其文件名相同。但 publicclass 的
名字必须和文件名相同。
范例 010:未明确的 x 调用
interfaceA{
intx=0;
4 / 54
}
classB{
intx=1;
}
classCextendsBimplementsA{
publicvoidpX(){
System.out.println(x);
}
publicstaticvoidmain(String[]args){
newC().pX();
}
}
答案:错误。在编译时会发生错误(错误描述不同的 JVM 有不同的信息,意思就是未明
确的 x 调用,两个 x 都匹配(就象在同时 importjava.util 和 java.sql 两个包时直接声明 Date
一样)。对于父类的变量,可以用 super.x 来明确,而接口的属性默认隐含为 publicstaticfinal.
所以可以通过 A.x 来明确。
范例 011:Ball 类的 Play()方法问题
interfacePlayable{
voidplay();
}
interfaceBounceable{
voidplay();
}
interfaceRollableextendsPlayable,Bounceable{
Ballball=newBall(“PingPang”);
}
classBallimplementsRollable{
privateStringname;
publicStringgetName(){
returnname;
}
publicBall(Stringname){
this.name=name;
}
publicvoidplay(){
ball=newBall(“Football”);
System.out.println(ball.getName());
}
}
这个错误不容易发现。
答案:错。“interfaceRollableextendsPlayable,Bounceable"没有问题。interface 可继承多个
interfaces,所以这里没错。问题出在 interfaceRollable 里的"Ballball=newBall(“PingPang”);”。
5 / 54
6 / 54
任何在 interface 里 声 明 的 interfacevariable( 接口变量,也可称成员变量 ) ,默认为
publicstaticfinal 。 也 就 是 说 “Ballball=newBall(“PingPang”);” 实 际 上 是
“publicstaticfinalBallball=newBall(“PingPang”);” 。 在 Ball 类 的 Play() 方法中,
"ball=newBall(“Football”);"改变了 ball 的 reference,而这里的 ball 来自 Rollableinterface,
Rollableinterface 里的 ball 是 publicstaticfinal 的,final 的 object 是不能被改变 reference 的。
因此编译器将在"ball=newBall(“Football”);"这里显示有错。
范例 012:字符串连接误用
错误的写法:

  1. Strings=“”;
  2. for(Personp:persons){
  3. s+=“,”+p.getName();
  4. }
  5. s=s.substring(2);//removefirstcomma
    正确的写法:
  6. StringBuildersb=newStringBuilder(persons.size()*16);//wellestimatedbuffe
    r
  7. for(Personp:persons){
  8. if(sb.length()>0)sb.append(“,”);
  9. sb.append(p.getName);
  10. }
    范例 013:错误的使用 StringBuffer
    错误的写法:
  11. StringBuffersb=newStringBuffer();
  12. sb.append(“Name:”);
  13. sb.append(name+‘\n’);
  14. sb.append(“!”);
  15. Strings=sb.toString();
    问题在第三行,appendchar 比 String 性能要好,另外就是初始化 StringBuffer 没有指定
    size,导致中间 append 时可能重新调整内部数组大小。如果是 JDK1.5 最好用 StringBuilder
    取代 StringBuffer,除非有线程安全的要求。还有一种方式就是可以直接连接字符串。缺点
    就是无法初始化时指定长度。
    正确的写法:
  16. StringBuildersb=newStringBuilder(100);
  17. sb.append(“Name:”);
  18. sb.append(name);
  19. sb.append(“\n!”);
  20. Strings=sb.toString();
    或者这样写:
  21. Strings=“Name:”+name+“\n!”;
    范例 014:测试字符串相等性
    错误的写法:
  22. if(name.compareTo(“John”)==0)…
  23. if(name==“John”)…
  24. if(name.equals(“John”))…
  25. if(“”.equals(name))…
    上面的代码没有错,但是不够好。compareTo 不够简洁,==原义是比较两个对象是否一样。另外比较字符是否为空,最好判断它的长度。
    正确的写法:
  26. if(“John”.equals(name))…
  27. if(name.length()==0)…
  28. if(name.isEmpty())…
    范例 015:数字转换成字符串
    错误的写法:
  29. “”+set.size()
  30. newInteger(set.size()).toString()
    正确的写法:
  31. String.valueOf(set.size())
    范例 016:利用不可变对象(Immutable)
    错误的写法:
  32. zero=newInteger(0);
    7 / 54
  33. returnBoolean.valueOf(“true”);
    正确的写法:
  34. zero=Integer.valueOf(0);
  35. returnBoolean.TRUE;
    范例 017:请使用 XML 解析器
    错误的写法:
  36. intstart=xml.indexOf(“”)+“”.length();
  37. intend=xml.indexOf(“”);
  38. Stringname=xml.substring(start,end);
    正确的写法:
  39. SAXBuilderbuilder=newSAXBuilder(false);
  40. Documentdoc=doc=builder.build(newStringReader(xml));
  41. Stringname=doc.getRootElement().getChild(“name”).getText();
    范例 018:请使用 JDom 组装 XML
    错误的写法:
  42. Stringname=…
  43. Stringattribute=…
  44. Stringxml=“”
  45. +“<nameatt=”“+attribute+”“>”+name+“”
  46. +“”;
    正确的写法:
  47. Elementroot=newElement(“root”);
  48. root.setAttribute(“att”,attribute);
  49. root.setText(name);
  50. Documentdoc=newDocumet();
  51. doc.setRootElement(root);
  52. XmlOutputterout=newXmlOutputter(Format.getPrettyFormat());
  53. Stringxml=out.outputString(root);
    8 / 54
    范例 019:XML 编码陷阱
    错误的写法:
  54. Stringxml=FileUtils.readTextFile(“my.xml”);
    因为 xml 的编码在文件中指定的,而在读文件的时候必须指定编码。另外一个问题不
    能一次就将一个 xml 文件用 String 保存,这样对内存会造成不必要的浪费,正确的做法用
    InputStream 来边读取边处理。为了解决编码的问题,最好使用 XML 解析器来处理。
    范例 020:未指定字符编码
    错误的写法:
  55. Readerr=newFileReader(file);
  56. Writerw=newFileWriter(file);
  57. Readerr=newInputStreamReader(inputStream);
  58. Writerw=newOutputStreamWriter(outputStream);
  59. Strings=newString(byteArray);//byteArrayisabyte[]
  60. byte[]a=string.getBytes();
    这样的代码主要不具有跨平台可移植性。因为不同的平台可能使用的是不同的默认字
    符编码。
    正确的写法:
  61. Readerr=newInputStreamReader(newFileInputStream(file),“ISO-8859-1”);
  62. Writerw=newOutputStreamWriter(newFileOutputStream(file),“ISO-8859-1”);
  63. Readerr=newInputStreamReader(inputStream,“UTF-8”);
  64. Writerw=newOutputStreamWriter(outputStream,“UTF-8”);
  65. Strings=newString(byteArray,“ASCII”);
  66. byte[]a=string.getBytes(“ASCII”);
    范例 021:未对数据流进行缓存
    错误的写法:
  67. InputStreamin=newFileInputStream(file);
  68. intb;
  69. while((b=in.read())!=-1){
  70. }

上面的代码是一个 byte 一个 byte 的读取,导致频繁的本地 JNI 文件系统访问,非常低
效,因为调用本地方法是非常耗时的。最好用 BufferedInputStream 包装一下。曾经做过一个
测试,从/dev/zero 下读取 1MB,大概花了 1s,而用 BufferedInputStream 包装之后只需要 60ms,
性能提高了 94%!这个也适用于 outputstream 操作以及 socket 操作。
正确的写法:

  1. InputStreamin=newBufferedInputStream(newFileInputStream(file));
    范例 022:无限使用 heap 内存
    错误的写法:
  2. byte[]pdf=toPdf(file);
    这里有一个前提,就是文件大小不能讲 JVM 的 heap 撑爆。否则就等着 OOM 吧,尤其是在高并发的服务器端代码。最好的做法是采用 Stream 的方式边读取边存储(本地文件或
    database)。
    正确的写法:
  3. Filepdf=toPdf(file);
    另外,对于服务器端代码来说,为了系统的安全,至少需要对文件的大小进行限制。
    范例 023:不指定超时时间
    错误的代码:
  4. Socketsocket=…
  5. socket.connect(remote);
  6. InputStreamin=socket.getInputStream();
  7. inti=in.read();
    这种情况在工作中已经碰到不止一次了。个人经验一般超时不要超过 20s。这里有一个问题,connect 可以指定超时时间,但是 read 无法指定超时时间。但是可以设置阻塞(block)
    时间。
    正确的写法:
  8. Socketsocket=…
  9. socket.connect(remote,20000);//failafter20s
  10. InputStreamin=socket.getInputStream();
  11. socket.setSoTimeout(15000);
  12. inti=in.read();

另外,文件的读取(FileInputStream,FileChannel,FileDescriptor,File)没法指定超时时间,而且 IO 操作均涉及到本地方法调用,这个更操作了 JVM 的控制范围,在分布式文件系统中,对 IO 的操作内部实际上是网络调用。一般情况下操作 60s 的操作都可以认为已经超时了。
为了解决这些问题,一般采用缓存和异步/消息队列处理。
范例 024:频繁使用计时器
错误代码:

  1. for(…){

  2. longt=System.currentTimeMillis();

  3. longt=System.nanoTime();

  4. Dated=newDate();

  5. Calendarc=newGregorianCalendar();

  6. }
    每次 new 一个 Date 或 Calendar 都会涉及一次本地调用来获取当前时间(尽管这个本地调用相对其他本地方法调用要快)。如果对时间不是特别敏感,这里使用了 clone 方法来新建一个 Date 实例。这样相对直接 new 要高效一些。
    正确的写法:

  7. Dated=newDate();

  8. for(Eentity:entities){

  9. entity.doSomething();

  10. entity.setUpdated((Date)d.clone());

  11. }
    如果循环操作耗时较长(超过几 ms),那么可以采用下面的方法,立即创建一个 Timer,然后定期根据当前时间更新时间戳,在我的系统上比直接 new 一个时间对象快 200 倍:

  12. privatevolatilelongtime;

  13. Timertimer=newTimer(true);

  14. try{

  15. time=System.currentTimeMillis();

  16. timer.scheduleAtFixedRate(newTimerTask(){

  17. publicvoidrun(){

  18. time=System.currentTimeMillis();

  19. }

  20. },0L,10L);//granularity10ms

  21. for(Eentity:entities){

  22. entity.doSomething();

  23. entity.setUpdated(newDate(time));

  24. }

  25. }finally{

  26. timer.cancel();

  27. }
    范例 025:捕获所有的异常
    错误的写法:

  28. Queryq=…

  29. Personp;

  30. try{

  31. p=(Person)q.getSingleResult();

  32. }catch(Exceptione){

  33. p=null;

  34. }
    这是 EJB3 的一个查询操作,可能出现异常的原因是:结果不唯一;没有结果;数据库无法访问,而捕获所有的异常,设置为 null 将掩盖各种异常情况。
    正确的写法:

  35. Queryq=…

  36. Personp;

  37. try{

  38. p=(Person)q.getSingleResult();

  39. }catch(NoResultExceptione){

  40. p=null;

  41. }
    范例 026:忽略所有异常
    错误的写法:

  42. try{

  43. doStuff();

  44. }catch(Exceptione){

  45. log.fatal(“Couldnotdostuff”);

  46. }

  47. doMoreStuff();
    这个代码有两个问题,一个是没有告诉调用者,系统调用出错了.第二个是日志没有出错
    原因,很难跟踪定位问题。
    正确的写法:
    12 / 54

  48. try{

  49. doStuff();

  50. }catch(Exceptione){

  51. thrownewMyRuntimeException(“Couldnotdostuffbecause:”+e.getMessage,e);

  52. }
    范例 027:重复包装 RuntimeException
    错误的写法:

  53. try{

  54. doStuff();

  55. }catch(Exceptione){

  56. thrownewRuntimeException(e);

  57. }
    正确的写法:

  58. try{

  59. doStuff();

  60. }catch(RuntimeExceptione){

  61. throwe;

  62. }catch(Exceptione){

  63. thrownewRuntimeException(e.getMessage(),e);

  64. }

  65. try{

  66. doStuff();

  67. }catch(IOExceptione){

  68. thrownewRuntimeException(e.getMessage(),e);

  69. }catch(NamingExceptione){

  70. thrownewRuntimeException(e.getMessage(),e);

  71. }
    范例 028:不正确的传播异常
    错误的写法:

  72. try{

  73. }catch(ParseExceptione){

  74. thrownewRuntimeException();

  75. thrownewRuntimeException(e.toString());

  76. thrownewRuntimeException(e.getMessage());

  77. thrownewRuntimeException(e);
    13 / 54

  78. }
    主要是没有正确的将内部的错误信息传递给调用者.第一个完全丢掉了内部错误信息,
    第二个错误信息依赖 toString 方法,如果没有包含最终的嵌套错误信息,也会出现丢失,而且可
    读性差.第三个稍微好一些,第四个跟第二个一样。
    正确的写法:

  79. try{

  80. }catch(ParseExceptione){

  81. thrownewRuntimeException(e.getMessage(),e);

  82. }
    范例 029:用日志记录异常
    错误的写法:

  83. try{

  84. }catch(ExceptionAe){

  85. log.error(e.getMessage(),e);

  86. throwe;

  87. }catch(ExceptionBe){

  88. log.error(e.getMessage(),e);

  89. throwe;

  90. }
    一般情况下在日志中记录异常是不必要的,除非调用方没有记录日志。
    范例 030:异常处理不彻底
    错误的写法:

  91. try{

  92. is=newFileInputStream(inFile);

  93. os=newFileOutputStream(outFile);

  94. }finally{

  95. try{

  96. is.close();

  97. os.close();

  98. }catch(IOExceptione){

  99. /wecan’tdoanything/

  100. }

  101. }
    14 / 54
    is 可能 close 失败,导致 os 没有 close
    正确的写法:

  102. try{

  103. is=newFileInputStream(inFile);

  104. os=newFileOutputStream(outFile);

  105. }finally{

  106. try{if(is!=null)is.close();}catch(IOExceptione){/wecan’tdoanything/}

  107. try{if(os!=null)os.close();}catch(IOExceptione){/wecan’tdoanything/}

  108. }
    范例 031:捕获不可能出现的异常
    错误的写法:

  109. try{

  110. …doriskystuff…

  111. }catch(SomeExceptione){

  112. //neverhappens

  113. }

  114. …dosomemore…
    正确的写法:

  115. try{

  116. …doriskystuff…

  117. }catch(SomeExceptione){

  118. //neverhappenshopefully

  119. thrownewIllegalStateException(e.getMessage(),e);//crashearly,passingalli
    nformation

  120. }

  121. …dosomemore…
    范例 032:transient 的误用
    错误的写法:

  122. publicclassAimplementsSerializable{

  123. privateStringsomeState;

  124. privatetransientLoglog=LogFactory.getLog(getClass());

  125. publicvoidf(){

  126. log.debug(“enterf”);


  127. 15 / 54

  128. }

  129. }
    这里的本意是不希望 Log 对象被序列化.不过这里在反序列化时,会因为 log 未初始化,
    导致 f()方法抛空指针,正确的做法是将 log 定义为静态变量或者定位为具备变量。
    正确的写法:

  130. publicclassAimplementsSerializable{

  131. privateStringsomeState;

  132. privatestaticfinalLoglog=LogFactory.getLog(A.class);

  133. publicvoidf(){

  134. log.debug(“enterf”);

  135. }

  136. }

  137. publicclassAimplementsSerializable{

  138. privateStringsomeState;

  139. publicvoidf(){

  140. Loglog=LogFactory.getLog(getClass());

  141. log.debug(“enterf”);

  142. }

  143. }
    范例 033:不必要的初始化
    错误的写法:

  144. publicclassB{

  145. privateintcount=0;

  146. privateStringname=null;

  147. privatebooleanimportant=false;

  148. }
    这里的变量会在初始化时使用默认值:0,null,false,因此上面的写法有些多此一举。
    正确的写法:

  149. publicclassB{

  150. privateintcount;

  151. privateStringname;

  152. privatebooleanimportant;

  153. }
    16 / 54
    17 / 54
    范例 034:最好用静态 final 定义 Log 变量

  154. privatestaticfinalLoglog=LogFactory.getLog(MyClass.class);
    这样做的好处有三:
     可以保证线程安全
     静态或非静态代码都可用
     不会影响对象序列化
    范例 035:选择错误的类加载器
    错误的代码:

  155. Classclazz=Class.forName(name);

  156. Classclazz=getClass().getClassLoader().loadClass(name);
    这里本意是希望用当前类来加载希望的对象,但是这里的 getClass()可能抛出异常,特别
    在一些受管理的环境中,比如应用服务器,web 容器,JavaWebStart 环境中,最好的做法是使用当
    前应用上下文的类加载器来加载。
    正确的写法:

  157. ClassLoadercl=Thread.currentThread().getContextClassLoader();

  158. if(cl==null)cl=MyClass.class.getClassLoader();//fallback

  159. Classclazz=cl.loadClass(name);
    范例 036:反射使用不当
    错误的写法:

  160. ClassbeanClass=…

  161. if(beanClass.newInstance()instanceofTestBean)…
    这里的本意是检查 beanClass 是否是 TestBean 或是其子类,但是创建一个类实例可能没
    那么简单,首先实例化一个对象会带来一定的消耗,另外有可能类没有定义默认构造函数.正
    确的做法是用 Class.isAssignableFrom(Class)方法。
    正确的写法:

  162. ClassbeanClass=…

  163. if(TestBean.class.isAssignableFrom(beanClass))…
    18 / 54
    范例 037:不必要的同步
    错误的写法:

  164. Collectionl=newVector();

  165. for(…){

  166. l.add(object);

  167. }
    Vector 是 ArrayList 同步版本。
    正确的写法:

  168. Collectionl=newArrayList();

  169. for(…){

  170. l.add(object);

  171. }
    范例 038:错误的选择 List 类型
    根据下面的表格数据来进行选择
    ArrayList LinkedList
    add(append) O(1)or~O(log(n))ifgrowing O(1)
    insert(middle) O(n)or~O(n*log(n))ifgrowing O(n)
    remove(middle) O(n)(alwaysperformscompletecopy) O(n)
    iterate O(n) O(n)
    getbyindex O(1) O(n)
    范例 039:HashMapsize 陷阱
    错误的写法:

  172. Mapmap=newHashMap(collection.size());

  173. for(Objecto:collection){

  174. map.put(o.key,o.value);

  175. }
    这里可以参考 guava 的 Maps.newHashMapWithExpectedSize 的实现.用户的本意是希望
    给 HashMap 设置初始值,避免扩容(resize)的开销.但是没有考虑当添加的元素数量达到
    HashMap 容量的 75%时将出现 resize。
    19 / 54
    正确的写法:

  176. Mapmap=newHashMap(1+(int)(collection.size()/0.75));
    范例 040:对 Hashtable,HashMap 和 HashSet 了解不够
    这里主要需要了解 HashMap 和 Hashtable 的内部实现上,它们都使用 Entry 包装来封装
    key/value,Entry 内部除了要保存 Key/Value 的引用,还需要保存 hash 桶中 nextEntry 的应用,因
    此对内存会有不小的开销 , 而 HashSet 内部实现其实就是一个 HashMap. 有时候
    IdentityHashMap 可以作为一个不错的替代方案.它在内存使用上更有效(没有用 Entry 封装,
    内部采用 Object[]).不过需要小心使用.它的实现违背了 Map 接口的定义.有时候也可以用
    ArrayList 来替换 HashSet.
    这一切的根源都是由于 JDK 内部没有提供一套高效的 Map 和 Set 实现。
    范例 041:对 List 的误用
    建议下列场景用 Array 来替代 List:
     list 长度固定,比如一周中的每一天
     对 list 频繁的遍历,比如超过 1w 次
     需要对数字进行包装(主要 JDK 没有提供基本类型的 List)
    比如下面的代码。
    错误的写法:

  177. Listcodes=newArrayList();

  178. codes.add(Integer.valueOf(10));

  179. codes.add(Integer.valueOf(20));

  180. codes.add(Integer.valueOf(30));

  181. codes.add(Integer.valueOf(40));
    正确的写法:

  182. int[]codes={10,20,30,40};
    错误的写法:

  183. //horriblyslowandamemorywasteriflhasafewthousandelements(tryityourself!)

  184. Listl=…;

  185. for(inti=0;i<l.size()-1;i++){

  186. Mergeableone=l.get(i);

  187. Iteratorj=l.iterator(i+1);//memoryallocation!

  188. while(j.hasNext()){

  189. Mergeableother=l.next();

  190. if(one.canMergeWith(other)){

  191. one.merge(other);

  192. other.remove();

  193. }

  194. }

  195. }
    正确的写法:

  196. //quitefastandnomemoryallocation

  197. Mergeable[]l=…;

  198. for(inti=0;i<l.length-1;i++){

  199. Mergeableone=l[i];

  200. for(intj=i+1;j<l.length;j++){

  201. Mergeableother=l[j];

  202. if(one.canMergeWith(other)){

  203. one.merge(other);

  204. l[j]=null;

  205. }

  206. }

  207. }
    实际上 Sun也意识到这一点,因此在 JDK中,Collections.sort()就是将一个 List 拷贝到一个
    数组中然后调用 Arrays.sort 方法来执行排序。
    范例 042:用数组来描述一个结构
    错误用法:

  208. /**

  209. *@returns[1]:Location,[2]:Customer,[3]:Incident

  210. */

  211. Object[]getDetails(intid){…
    这里用数组+文档的方式来描述一个方法的返回值.虽然很简单,但是很容易误用,正确的
    做法应该是定义个类。
    正确的写法:

  212. DetailsgetDetails(intid){…}

  213. privateclassDetails{

  214. publicLocationlocation;

  215. publicCustomercustomer;

  216. publicIncidentincident;
    20 / 54

  217. }
    范例 043:对方法过度限制
    错误用法:

  218. publicvoidnotify(Personp){

  219. sendMail(p.getName(),p.getFirstName(),p.getEmail());

  220. }

  221. classPhoneBook{

  222. Stringlookup(StringemployeeId){

  223. Employeeemp=…

  224. returnemp.getPhone();

  225. }

  226. }
    第一个例子是对方法参数做了过多的限制,第二个例子对方法的返回值做了太多的限
    制。
    正确的写法:

  227. publicvoidnotify(Personp){

  228. sendMail§;

  229. }

  230. classEmployeeDirectory{

  231. Employeelookup(StringemployeeId){

  232. Employeeemp=…

  233. returnemp;

  234. }

  235. }
    范例 044:对 POJO 的 setter 方法画蛇添足
    错误的写法:

  236. privateStringname;

  237. publicvoidsetName(Stringname){

  238. this.name=name.trim();

  239. }

  240. publicvoidStringgetName(){
    21 / 54

  241. returnthis.name;

  242. }
    有时候我们很讨厌字符串首尾出现空格,所以在 setter 方法中进行了 trim 处理,但是这样
    做的结果带来的副作用会使 getter 方法的返回值和 setter 方法不一致,如果只是将 JavaBean
    当做一个数据容器,那么最好不要包含任何业务逻辑.而将业务逻辑放到专门的业务层或者控
    制层中处理。
    正确的做法:

  243. person.setName(textInput.getText().trim());
    范例 045:日历对象(Calendar)误用
    错误的写法:

  244. Calendarcal=newGregorianCalender(TimeZone.getTimeZone(“Europe/Zurich”));

  245. cal.setTime(date);

  246. cal.add(Calendar.HOUR_OF_DAY,8);

  247. date=cal.getTime();
    这里主要是对 date,time,calendar 和 timezone 不了解导致.而在一个时间上增加 8 小时,跟
    timezone 没有任何关系,所以没有必要使用 Calendar,直接用 Date 对象即可,而如果是增加天数
    的话,则需要使用 Calendar,因为采用不同的时令制可能一天的小时数是不同的(比如有些DST
    是 23 或者 25 个小时)
    正确的写法:

  248. date=newDate(date.getTime()+8L3600L1000L);//add8hrs
    范例 046:TimeZone 的误用
    错误的写法:

  249. Calendarcal=newGregorianCalendar();

  250. cal.setTime(date);

  251. cal.set(Calendar.HOUR_OF_DAY,0);

  252. cal.set(Calendar.MINUTE,0);

  253. cal.set(Calendar.SECOND,0);

  254. DatestartOfDay=cal.getTime();
    这里有两个错误,一个是没有没有将毫秒归零,不过最大的错误是没有指定 TimeZone,不
    过一般的桌面应用没有问题,但是如果是服务器端应用则会有一些问题,比如同一时刻在上海
    和伦敦就不一样,因此需要指定的 TimeZone.
    22 / 54
    正确的写法:

  255. Calendarcal=newGregorianCalendar(user.getTimeZone());

  256. cal.setTime(date);

  257. cal.set(Calendar.HOUR_OF_DAY,0);

  258. cal.set(Calendar.MINUTE,0);

  259. cal.set(Calendar.SECOND,0);

  260. cal.set(Calendar.MILLISECOND,0);

  261. DatestartOfDay=cal.getTime();
    范例 047:时区(TimeZone)调整的误用
    错误的写法:

  262. publicstaticDateconvertTz(Datedate,TimeZonetz){

  263. Calendarcal=Calendar.getInstance();

  264. cal.setTimeZone(TimeZone.getTimeZone(“UTC”));

  265. cal.setTime(date);

  266. cal.setTimeZone(tz);

  267. returncal.getTime();

  268. }
    这个方法实际上没有改变时间,输入和输出是一样的.关于时间的问题可以参考这篇文
    章:http://www.odi.ch/prog/design/datetime.php这里主要的问题是Date对象并不包含TimeZone
    信息.它总是使用 UTC(世界统一时间).而调用 Calendar 的 getTime/setTime 方法会自动在当前
    时区和 UTC 之间做转换。
    范例 048:Calendar.getInstance()的误用
    错误的写法:

  269. Calendarc=Calendar.getInstance();

  270. c.set(2009,Calendar.JANUARY,15);
    Calendar.getInstance()依赖 local 来选择一个 Calendar 实现,不同实现的 2009 年是不同的,
    比如有些 Calendar 实现就没有 January 月份。
    正确的写法:

  271. Calendarc=newGregorianCalendar(timeZone);

  272. c.set(2009,Calendar.JANUARY,15);
    23 / 54
    范例 049:Date.setTime()的误用
    错误的写法:

  273. account.changePassword(oldPass,newPass);

  274. Datelastmod=account.getLastModified();

  275. lastmod.setTime(System.currentTimeMillis());
    在更新密码之后,修改一下最后更新时间,这里的用法没有错,但是有更好的做法:直接传
    Date 对象.因为 Date 是 ValueObject,不可变的.如果更新了 Date 的值,实际上是生成一个新的
    Date 实例.这样其他地方用到的实际上不在是原来的对象,这样可能出现不可预知的异常.当
    然这里又涉及到另外一个 OO设计的问题,对外暴露 Date 实例本身就是不好的做法(一般的做
    法是在 setter 方法中设置 Date 引用参数的 clone 对象).另外一种比较好的做法就是直接保存
    long 类型的毫秒数。
    正确的做法:

  276. account.changePassword(oldPass,newPass);

  277. account.setLastModified(newDate());
    范例 050:SimpleDateFormat 非线程安全误用
    错误的写法:

  278. publicclassConstants{

  279. publicstaticfinalSimpleDateFormatdate=newSimpleDateFormat(“dd.MM.yyyy”);

  280. }
    SimpleDateFormat不是线程安全的.在多线程并行处理的情况下,会得到非预期的值.这个
    错误非常普遍!如果真要在多线程环境下公用同一个 SimpleDateFormat,那么做好做好同步
    (cacheflush,lockcontention),但是这样会搞得更复杂,还不如直接 new 一个实在。
    范例 051:使用全局参数配置常量类/接口

  281. publicinterfaceConstants{

  282. Stringversion=“1.0”;

  283. StringdateFormat=“dd.MM.yyyy”;

  284. StringconfigFile=“.apprc”;

  285. intmaxNameLength=32;

  286. StringsomeQuery=“SELECT*FROM…”;

  287. }
    很多应用都会定义这样一个全局常量类或接口,但是为什么这种做法不推荐?因为这些
    24 / 54
    常量之间基本没有任何关联,只是因为公用才定义在一起.但是如果其他组件需要使用这些全
    局变量,则必须对该常量类产生依赖,特别是存在 server 和远程 client 调用的场景。
    比较好的做法是将这些常量定义在组件内部.或者局限在一个类库内部。
    范例 052:忽略造型溢出(castoverflow)
    错误的写法:

  288. publicintgetFileSize(Filef){

  289. longl=f.length();

  290. return(int)l;

  291. }
    这个方法的本意是不支持传递超过 2GB 的文件.最好的做法是对长度进行检查,溢出时
    抛出异常。
    正确的写法:

  292. publicintgetFileSize(Filef){

  293. longl=f.length();

  294. if(l>Integer.MAX_VALUE)thrownewIllegalStateException(“intoverflow”);

  295. return(int)l;

  296. }
    另一个溢出 bug 是 cast 的对象不对,比如下面第一个 println.正确的应该是下面的那个。

  297. longa=System.currentTimeMillis();

  298. longb=a+100;

  299. System.out.println((int)b-a);

  300. System.out.println((int)(b-a));
    范例 052:对 float 和 double 使用==操作
    错误的写法:

  301. for(floatf=10f;f!=0;f-=0.1){

  302. System.out.println(f);

  303. }
    上面的浮点数递减只会无限接近 0 而不会等于 0,这样会导致上面的 for进入死循环.通常
    绝不要对 float 和 double 使用操作.而采用大于和小于操作.如果 java 编译器能针对这种情
    况给出警告.或者在 java 语言规范中不支持浮点数类型的
    操作就最好了。
    正确的写法:
    25 / 54

  304. for(floatf=10f;f>0;f-=0.1){

  305. System.out.println(f);

  306. }
    范例 054:用浮点数来保存 money
    错误的写法:

  307. floattotal=0.0f;

  308. for(OrderLineline:lines){

  309. total+=line.price*line.count;

  310. }

  311. doublea=1.14*75;//85.5 将表示为 85.4999…

  312. System.out.println(Math.round(a));//输出值为 85

  313. BigDecimald=newBigDecimal(1.14);//造成精度丢失
    这个也是一个老生常谈的错误.比如计算 100 笔订单,每笔 0.3 元,最终的计算结果是
    29.9999971.如果将 float 类型改为 double 类型,得到的结果将是 30.000001192092896.出现这种
    情况的原因是,人类和计算的计数方式不同.人类采用的是十进制,而计算机是二进制.二进制
    对于计算机来说非常好使,但是对于涉及到精确计算的场景就会带来误差.比如银行金融中的
    应用。
    因此绝不要用浮点类型来保存 money数据.采用浮点数得到的计算结果是不精确的.即使
    与 int 类型做乘法运算也会产生一个不精确的结果.那是因为在用二进制存储一个浮点数时
    已经出现了精度丢失.最好的做法就是用一个 string 或者固定点数来表示.为了精确,这种表示
    方式需要指定相应的精度值.BigDecimal 就满足了上面所说的需求.如果在计算的过程中精度
    的丢失超出了给定的范围,将抛出 runtimeexception.
    正确的写法:

  314. BigDecimaltotal=BigDecimal.ZERO;

  315. for(OrderLineline:lines){

  316. BigDecimalprice=newBigDecimal(line.price);

  317. BigDecimalcount=newBigDecimal(line.count);

  318. total=total.add(price.multiply(count));//BigDecimalisimmutable!

  319. }

  320. total=total.setScale(2,RoundingMode.HALF_UP);

  321. BigDecimala=(newBigDecimal(“1.14”)).multiply(newBigDecimal(75));//85.5ex
    act

  322. a=a.setScale(0,RoundingMode.HALF_UP);//86

  323. System.out.println(a);//correctoutput:86

  324. BigDecimala=newBigDecimal(“1.14”);
    26 / 54
    范例 055:不使用 finally 块释放资源
    错误的写法:

  325. publicvoidsave(Filef)throwsIOException{

  326. OutputStreamout=newBufferedOutputStream(newFileOutputStream(f));

  327. out.write(…);

  328. out.close();

  329. }

  330. publicvoidload(Filef)throwsIOException{

  331. InputStreamin=newBufferedInputStream(newFileInputStream(f));

  332. in.read(…);

  333. in.close();

  334. }
    上面的代码打开一个文件输出流,操作系统为其分配一个文件句柄,但是文件句柄是一
    种非常稀缺的资源,必须通过调用相应的 close 方法来被正确的释放回收.而为了保证在异常
    情况下资源依然能被正确回收,必须将 其放在 finallyblock 中.上面 的代 码中使用了
    BufferedInputStream 将 filestream 包装成了一个 bufferstream,这样将导致在调用 close 方法时
    才会将 bufferstream 写入磁盘.如果在 close 的时候失败,将导致写入数据不完全.而对于
    FileInputStream 在 finallyblock 的 close 操作这里将直接忽略。
    如果BufferedOutputStream.close()方法执行顺利则万事大吉,如果失败这里有一个潜在的
    bug(http://bugs.sun.com/view_bug.do?bug_id=6335274):在 close 方法内部调用 flush 操作的时
    候,如果出现异常,将直接忽略.因此为了尽量减少数据丢失,在执行 close 之前显式的调用 flush
    操作。
    下面的代码有一个小小的瑕疵:如果分配 filestream 成功,但是分配 bufferstream 失败
    (OOM 这种场景),将导致文件句柄未被正确释放.不过这种情况一般不用担心,因为 JVM 的 gc
    将帮助我们做清理。

  335. //codeforyourcookbook

  336. publicvoidsave()throwsIOException{

  337. Filef=…

  338. OutputStreamout=newBufferedOutputStream(newFileOutputStream(f));

  339. try{

  340. out.write(…);

  341. out.flush();//don’tloseexceptionbyimplicitflushonclose

  342. }finally{

  343. out.close();

  344. }

  345. }

  346. publicvoidload(Filef)throwsIOException{

  347. InputStreamin=newBufferedInputStream(newFileInputStream(f));

  348. try{

  349. in.read(…);
    27 / 54

  350. }finally{

  351. try{in.close();}catch(IOExceptione){}

  352. }

  353. }
    数据库访问也涉及到类似的情况:

  354. CargetCar(DataSourceds,Stringplate)throwsSQLException{

  355. Carcar=null;

  356. Connectionc=null;

  357. PreparedStatements=null;

  358. ResultSetrs=null;

  359. try{

  360. c=ds.getConnection();

  361. s=c.prepareStatement(“selectmake,colorfromcarswhereplate=?”);

  362. s.setString(1,plate);

  363. rs=s.executeQuery();

  364. if(rs.next()){

  365. car=newCar();

  366. car.make=rs.getString(1);

  367. car.color=rs.getString(2);

  368. }

  369. }finally{

  370. if(rs!=null)try{rs.close();}catch(SQLExceptione){}

  371. if(s!=null)try{s.close();}catch(SQLExceptione){}

  372. if(c!=null)try{c.close();}catch(SQLExceptione){}

  373. }

  374. returncar;

  375. }
    范例 056:finalize 方法误用
    错误的写法:

  376. publicclassFileBackedCache{

  377. privateFilebackingStore;

  378. protectedvoidfinalize()throwsIOException{

  379. if(backingStore!=null){

  380. backingStore.close();

  381. backingStore=null;

  382. }

  383. }

  384. }
    28 / 54
    这个问题 EffectiveJava 这本书有详细的说明.主要是 finalize 方法依赖于 GC 的调用,其调
    用时机可能是立马也可能是几天以后,所以是不可预知的.而JDK的 API文档中对这一点有误
    导:建议在该方法中来释放 I/O 资源。
    正确的做法是定义一个 close 方法,然后由外部的容器来负责调用释放资源。

  385. publicclassFileBackedCache{

  386. privateFilebackingStore;

  387. publicvoidclose()throwsIOException{

  388. if(backingStore!=null){

  389. backingStore.close();

  390. backingStore=null;

  391. }

  392. }

  393. }
    在 JDK1.7(Java7)中已经引入了一个 AutoClosable 接口.当变量(不是对象)超出了
    try-catch 的资源使用范围,将自动调用 close 方法。

  394. try(Writerw=newFileWriter(f)){//implementsClosable

  395. w.write(“abc”);

  396. //wgoesoutofscopehere:w.close()iscalledautomaticallyinANYcase

  397. }catch(IOExceptione){

  398. thrownewRuntimeException(e.getMessage(),e);

  399. }
    范例 057:Thread.interrupted 方法误用
    错误的写法:

  400. try{

  401. Thread.sleep(1000);

  402. }catch(InterruptedExceptione){

  403. //ok

  404. }

  405. or

  406. while(true){

  407. if(Thread.interrupted())break;

  408. }
    这里主要是 interrupted 静态方法除了返回当前线程的中断状态,还会将当前线程状态复
    位。
    正确的写法:
    29 / 54
    30 / 54

  409. try{

  410. Thread.sleep(1000);

  411. }catch(InterruptedExceptione){

  412. Thread.currentThread().interrupt();

  413. }

  414. or

  415. while(true){

  416. if(Thread.currentThread().isInterrupted())break;

  417. }
    范例 058:在静态变量初始化时创建线程
    错误的写法:

  418. classCache{

  419. privatestaticfinalTimerevictor=newTimer();

  420. }
    Timer 构造器内部会 new 一个 thread,而该 thread 会从它的父线程(即当前线程)中继承各
    种属性。比如 contextclassloader,threadlocal 以及其他的安全属性(访问权限)。而加载当前类
    的线程可能是不确定的,比如一个线程池中随机的一个线程。如果你需要控制线程的属性,
    最好的做法就是将其初始化操作放在一个静态方法中,这样初始化将由它的调用者来决定。
    正确的做法:

  421. classCache{

  422. privatestaticTimerevictor;

  423. publicstaticsetupEvictor(){

  424. evictor=newTimer();

  425. }

  426. }
    范例 059:已取消的定时器任务依然持有状态
    错误的写法:

  427. finalMyClasscallback=this;

  428. TimerTasktask=newTimerTask(){

  429. publicvoidrun(){

  430. callback.timeout();

  431. }

  432. };

  433. timer.schedule(task,300000L);

  434. try{

  435. doSomething();

  436. }finally{

  437. task.cancel();

  438. }
    上面的 task 内部包含一个对外部类实例的应用,这将导致该引用可能不会被 GC 立即回
    收.因为 Timer 将保留 TimerTask 在指定的时间之后才被释放.因此 task 对应的外部类实例将
    在 5 分钟后被回收。
    正确的写法:

  439. TimerTasktask=newJob(this);

  440. timer.schedule(task,300000L);

  441. try{

  442. doSomething();

  443. }finally{

  444. task.cancel();

  445. }

  446. staticclassJobextendsTimerTask{

  447. privateMyClasscallback;

  448. publicJob(MyClasscallback){

  449. this.callback=callback;

  450. }

  451. publicbooleancancel(){

  452. callback=null;

  453. returnsuper.cancel();

  454. }

  455. publicvoidrun(){

  456. if(callback==null)return;

  457. callback.timeout();

  458. }

  459. }
    范例 060:
    “数组下标越界异常”
    这是代码在尝试访问不在数组的索引取值范围内的元素时会显示的运行时错误消息。
    如下所示的代码会触发此异常:
    String[] name = {
    “tom”,
    “dick”,
    “harry”
    };
    for (int i = 0; i <= name.length; i++) {
    System.out.print(name[i] + ‘\n’);
    31 / 54
    }
    如下是另外一个例子:
    int[] list = new int[5];
    list[5] = 33; // illegal index, maximum index is 4
    数组的索引是从零开始的,并且比数组长度小了 1。通常,在定义数组索引的限制时,
    要使用“<”而不是“<=”。
    范例 061:
    “访问字符串中不在字符串范围内的字符”
    当代码尝试访问字符串中不在字符串范围内的字符串片段时,就会出现此问题。这种
    情况通常会发生在代码尝试创建一个字符串的子字符串,可是传入的参数值不符合字符串长
    度限制的时候。如下就是这类问题的一个例子:
    public class StringCharAtExample {
    public static void main(String[] args) {
    String str = “Java Code Geeks!”;
    System.out.println("Length: " + str.length());
    //The following statement throws an exception, because
    //the request index is invalid.
    char ch = str.charAt(50);
    }
    }
    像数组的索引一样,字符串的索引是从零开始的。索引字符串时,最后一个字符的索
    引值比字符串的长度小 1。 “StringIndexOutOfBoundsException”这个错误消息一般都意味
    着索引正在尝试访问不存在于字符串中的字符。
    范例 062:
    “使用没有经过赋值的对象引用”
    当程序尝试使用没有经过赋值的对象引用时,就会发生“NullPointerException”。
    // A Java program to demonstrate that invoking a method
    // on null causes NullPointerException
    import java.io.;
    class GFG
    {
    public static void main (String[] args)
    {
    // Initializing String variable with null value
    String ptr = null;
    // Checking if ptr.equals null or works fine.
    try
    32 / 54
    33 / 54
    {
    // This line of code throws NullPointerException
    // because ptr is null
    if (ptr.equals(“gfg”))
    System.out.print(“Same”);
    else
    System.out.print(“Not Same”);
    }
    catch(NullPointerException e)
    {
    System.out.print(“NullPointerException Caught”);
    }
    }
    }
    Java 程序经常出现如下状况:
     语句引用一个值为空的对象。
     尝试去访问已经定义但是还没有分配过引用的类。
    范例 063:
    “找不到类的文件”
    “NoClassDefFoundError”会发生在解释器找不到在主方法使用到了的类的文件的时
    候。如下是 DZone 的示例:
    如果你对如下程序执行编译:
    class A
    {
    // some code
    }
    public class B
    {
    public static void main(String[] args)
    {
    A a = new A();
    }
    }
    它会生成两个 .class 文件:A.class 和 B.class。删除 A.class 文件并且运行 B.class 文
    件,就会得到 NoClassDefFoundError 错误消息:
    Exception in thread “main” java.lang.NoClassDefFoundError: A
    at MainClass.main(MainClass.java:10)
    Caused by: java.lang.ClassNotFoundException: A
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    34 / 54
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    如果存在如下问题,就会发生这样的问题:
     该文件不在正确的目录。
     类的名称必须与文件的名称相同(不包括文件扩展名),且名称是区分大小写的。
    范例 064:
    “方法在类里面没有定义”
    当 Java 软件尝试调用类的方法而该方法在类里面没有定义时,就会出现这样的错误消
    息:
    Error: Could not find or load main class wiki.java
    当声明中有错别字的时候,一般就会出现“NoSuchMethodFoundError”这样的错误。
    范例 065:
    “请求了一个不可用的安全方案提供方”
    当请求了一个不可用的安全方案提供方(Security Provider)的时候,就会引发
    “NoSuchProviderException”:
    javax.mail.NoSuchProviderException
    如果你在尝试找出“NoSuchProviderException”为什么会发生的原因,请进行如下检查:
     JRE 配置。
     配置中的 Java 主目录配置。
     使用的哪个 Java 环境。
     安全方案提供方选项。
    范例 066:访问的系统资源被拒绝
    AccessControlException 表示请求访问的系统资源(比如文件系统或这网络)被拒绝了,
    例如本例中的 JBossDeveloper:
    ERROR Could not register mbeans java.security.
    AccessControlException: WFSM000001: Permission check failed (permission “(”
    javax.management.MBeanPermission" “org.apache.logging.log4j.core.jmx.
    LoggerContextAdmin#-
    [org.apache.logging.log4j2:type=51634f]” “registerMBean”)" in code source "
    (vfs:/C:/wildfly-10.0.0.Final/standalone/deployments/mySampleSecurit
    yApp.war/WEB-INF/lib/log4j-core-2.5.
    jar )" of “null”)
    35 / 54
    范例 067:
    “转换规则限制发生中断”
    “ArrayStoreException”会发生在向 Java 的数组中转换元素受到转换规则限制而发生
    中断的时候。例如,这个来自于 JavaScan.com 的这个例子就表现了发生这种问题的程序:
    /
    … START … /
    public class JavaArrayStoreException {
    public static void main(String…args) {
    Object[] val = new Integer[4];
    val[0] = 5.8;
    }
    }
    /
    … END … */
    输出结果如下:
    Exception in thread “main” java.lang.ArrayStoreException: java.lang.Double
    at ExceptionHandling.JavaArrayStoreException.main(JavaArrayStoreException.j
    ava:7)
    数组在被初始化的时候,需要声明允许进入数组的对象的种类。因此数组的每个元素
    都得是相同类型的对象。
    范例 068:
    “Bad Magic Number”
    这个错误消息的意思是网络上的类定义文件可能出问题了。如下是服务器端的错误消
    息示例:
    Java™ Plug-in: Version 1.3.1_01
    Using JRE version 1.3.1_01 Java HotSpot™ Client VM
    User home directory = C:\Documents and Settings\Ankur
    Proxy Configuration: Manual Configuration
    Proxy: 192.168.11.6:80
    java.lang.ClassFormatError: SalesCalculatorAppletBeanInfo (Bad magic numbe
    r)
    at java.lang.ClassLoader.defineClass0(Native Method)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.security.SecureClassLoader.defineClass(Unknown Source)
    at sun.applet.AppletClassLoader.findClass(Unknown Source)
    at sun.plugin.security.PluginClassLoader.access$201(Unknown Source)
    at sun.plugin.security.PluginClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.plugin.security.PluginClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.applet.AppletClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.beans.Introspector.instantiate(Unknown Source)
    at java.beans.Introspector.findInformant(Unknown Source)
    at java.beans.Introspector.(Unknown Source)
    at java.beans.Introspector.getBeanInfo(Unknown Source)
    at sun.beans.ole.OleBeanInfo.(Unknown Source)
    at sun.beans.ole.StubInformation.getStub(Unknown Source)
    at sun.plugin.ocx.TypeLibManager$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.plugin.ocx.TypeLibManager.getTypeLib(Unknown Source)
    at sun.plugin.ocx.TypeLibManager.getTypeLib(Unknown Source)
    at sun.plugin.ocx.ActiveXAppletViewer.statusNotification(Native Method)
    at sun.plugin.ocx.ActiveXAppletViewer.notifyStatus(Unknown Source)
    at sun.plugin.ocx.ActiveXAppletViewer.showAppletStatus(Unknown Source)
    at sun.applet.AppletPanel.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
    “bad magic number”错误消息发生时,可能存在如下这些情况:
     类文件的前四个字节不是十六进制数字 CAFEBABE。
     类文件是以 ASCII 模式而不是二进制模式上传的。
     Java 程序是在编译之前运行的。
    范例 069:
    “数据流停止工作或处于关闭状态”
    这样的错误消息表示来自于文件或网络套接字的数据流已停止工作或在另一端已经处
    于关闭状态。
    Exception in thread “main” java.net.SocketException: Broken pipe
    at java.net.SocketOutputStream.socketWrite0(Native Method)
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:9

at java.net.SocketOutputStream.write(SocketOutputStream.java:115)
at java.io.DataOutputStream.write
数据管道中断发生的原因一般包括如下这些
 磁盘的暂存空间已经耗尽。
 RAM 可能被堵塞了。
 数据流可能已经损坏了。
 读取管道的进程可能已经关闭了。
36 / 54
范例 070:
“使用错误的参数来启动 Java”
当 Java 代码尝试使用错误的参数来启动 Java 时,一般会产生这样的错误消息:
Error: Could not create the Java Virtual Machine
Error: A fatal exception has occurred. Program will exit.
它通常是由于代码中的声明中或者为其分配适当的内存时有错误而引起的。
范例 071:
“在错误的目录中寻找类文件”
“class file contains wrong class”问题一般会发生在 Java 代码尝试在错误的目录中寻找
类文件的时候,产生类似于如下所示的错误消息:
MyTest.java:10: cannot access MyStruct
bad class file: D:\Java\test\MyStruct.java
file does not contain class MyStruct
Please remove or make sure it appears in the correct subdirectory of the cl
asspath.
MyStruct ms = new MyStruct();
^
要修复此问题,如下提示可以提供一些帮助:
 确保源文件的名称和类的名称匹配——包括大小写。
 检查包的说明语句是否正确或者缺失。
 确保源文件位于正确的目录。
范例 072:
“对象转换到一个错误的类型”
“ClassCastException” 消息表示 Java 代码正尝试将对象转换到一个错误的类型。在
下面这个来自于 Java 概念日有所进(Java Concept of the Day)的实例中, 运行着这样的程
序:
package com;
class A
{
int i = 10;
}
class B extends A
{
int j = 20;
}
class C extends B
{
int k = 30;
37 / 54
38 / 54
}
public class ClassCastExceptionDemo
{
public static void main(String[] args)
{
A a = new B(); //B type is auto up casted to A type
B b = (B) a; //A type is explicitly down casted to B type.
C c = © b; //Here, you will get class cast exception
System.out.println(c.k);
}
}
这会导致如下错误:
Exception in thread “main” java.lang.ClassCastException: com.B cannot be ca
st to com.C
at com.ClassCastExceptionDemo.main(ClassCastExceptionDemo.java:23)
Java 代码会创建一个类和子类的层级结构。为了避免 “ClassCastException” 错误,
请确保新的类型归属于正确的类或者它的父类。如果使用了泛型的话,这些错误就可以在编
译时被捕获到。
范例 073:
“一个链接错误”
“ClassFormatError” 消息指代的是一个链接错误,发生在一个类文件不能被读取或者
解释为一个类文件的时候。
Caused by: java.lang.ClassFormatError: Absent Code attribute in method tha
t is
not native or abstract in class file javax/persistence/GenerationTy
pe
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$000(Unknown Source)
at java.net.URLClassLoader 1. r u n ( U n k n o w n S o u r c e ) a t j a v a . s e c u r i t y . A c c e s s C o n t r o l l e r . d o P r i v i l e g e d ( N a t i v e M e t h o d ) a t j a v a . n e t . U R L C l a s s L o a d e r . f i n d C l a s s ( U n k n o w n S o u r c e ) a t j a v a . l a n g . C l a s s L o a d e r . l o a d C l a s s ( U n k n o w n S o u r c e ) a t s u n . m i s c . L a u n c h e r 1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher 1.run(UnknownSource)atjava.security.AccessController.doPrivileged(NativeMethod)atjava.net.URLClassLoader.findClass(UnknownSource)atjava.lang.ClassLoader.loadClass(UnknownSource)atsun.misc.LauncherAppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
关于“ClassFormatError”错误为什么会发生,有几种可能:
 类文件是以 ASCII 模式而不是二进制模式来上传的。
 网页服务器是以二进制而非 ASCII 来发送类文件的。
39 / 54
 可能有类路径错误阻止了代码找到类文件。
 如果类被加载了两次,第二次就会导致这个异常被抛出来。
 使用了一个老版本的 Java 运行时。
范例 074:
“一个链接错误”
“ClassNotFoundException” 只会发生于运行时——意味着本存在于编译时可是在运行
时却丢失了。这是一个链接错误。
非常类似于 “NoClassDefFoundError”,如下情况就有可能让这样的问题发生:
 文件不在正确的目录。
 类的名称必须跟文件的名称保持一致(不包括扩展名)。名称对大小写是敏感的。
范例 075:
“初始化错误中的异常”
这个 Java 问题会在静态初始化有问题时发生。当 Java 代码稍后要用到这个类时, 将
会发生“NoClassDefFoundError” 错误.
java.lang.ExceptionInInitializerError
at org.eclipse.mat.hprof.HprofIndexBuilder.fill(HprofIndexBuilder.java:5
4)
at org.eclipse.mat.parser.internal.SnapshotFactory.parse(SnapshotFactory.
java:193)
at org.eclipse.mat.parser.internal.SnapshotFactory.openSnapshot(SnapshotF
actory.java:106)
at com.squareup.leakcanary.HeapAnalyzer.openSnapshot(HeapAnalyzer.java:13
4)
at com.squareup.leakcanary.HeapAnalyzer.checkForLeak(HeapAnalyzer.java:8
7)
at com.squareup.leakcanary.internal.HeapAnalyzerService.onHandleIntent(He
apAnalyzerService.java:56)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.j
ava:65)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.os.HandlerThread.run(HandlerThread.java:61)
Caused by: java.lang.NullPointerException: in == null
at java.util.Properties.load(Properties.java:246)
at org.eclipse.mat.util.MessageUtil.(MessageUtil.java:28)
at org.eclipse.mat.util.MessageUtil.(MessageUtil.java:13)
… 10 more
要修复此问题还需要更多的信息。在代码中使用 getCause() 可以返回导致被返回的错
误发生的异常对象。
范例 076:
“非法封锁”
“IllegalBlockSizeException” 会发生在解密时消息长度不是 8 位的倍数的时候。
@Override
protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, Inva
lidKeyException {
try {
byte[] encoded = key.getEncoded();
return engineDoFinal(encoded, 0, encoded.length);
} catch (BadPaddingException e) {
IllegalBlockSizeException newE = new IllegalBlockSizeException();
newE.initCause(e);
throw newE;
}
}
“IllegalBlockSizeException” 可能由如下状况所导致:
 使用的加解密算法不一致。
 被解密的消息在传递过来的途中被截断或者产生了乱码。
范例 077:
“加密数据操作异常”
“BadPaddingException”会发生于解密时填充块被用来创建一个可以用 8 位的倍数来
40 / 54
计算长度的消息的时候。
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*…)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*…)
at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*…)
at javax.crypto.Cipher.doFinal(DashoA13*…)
被加密的数据是二进制的,因此不要尝试着在一个字符串中去存储它,或者也有可能
是加密期间数据没有进行恰当的填充。
范例 078:
“不兼容变更错误”
“IncompatibleClassChangeError” 是链接错误 LinkageError 的一种形式,会在一个基
类在其子类已经编译过了之后发生了概念时发生。
Exception in thread “main” java.lang.IncompatibleClassChangeError: Implemen
ting class
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$000(Unknown Source)
at java.net.URLClassLoader 1. r u n ( U n k n o w n S o u r c e ) a t j a v a . s e c u r i t y . A c c e s s C o n t r o l l e r . d o P r i v i l e g e d ( N a t i v e M e t h o d ) a t j a v a . n e t . U R L C l a s s L o a d e r . f i n d C l a s s ( U n k n o w n S o u r c e ) a t j a v a . l a n g . C l a s s L o a d e r . l o a d C l a s s ( U n k n o w n S o u r c e ) a t s u n . m i s c . L a u n c h e r 1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher 1.run(UnknownSource)atjava.security.AccessController.doPrivileged(NativeMethod)atjava.net.URLClassLoader.findClass(UnknownSource)atjava.lang.ClassLoader.loadClass(UnknownSource)atsun.misc.LauncherAppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
at net.sf.cglib.core.DebuggingClassWriter.toByteArray(DebuggingClassWriter.
java:73)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStra
tegy.java:26)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.j
ava:216)
at net.sf.cglib.core.KeyFactoryKaTeX parse error: Unexpected character: '' at position 317: …发生时,有能发生了如下状况: ̲ 忘记了在主方法的 stati…ResponseOutInvoker$1.invoke(DispatchProviderHelper.java:206)
at com.atlassian.plugins.rest.common.interceptor.impl.DispatchProviderHe
lper$1.intercept(DispatchProviderHelper.java:90)
at com.atlassian.plugins.rest.common.interceptor.impl.DefaultMethodInvoc
ation.invoke(DefaultMethodInvocation.java:61)
at com.atlassian.plugins.rest.common.expand.interceptor.ExpandIntercepto
r.intercept(ExpandInterceptor.java:38)
at com.atlassian.plugins.rest.common.interceptor.impl.DefaultMethodInvoc
ation.invoke(DefaultMethodInvocation.java:61)
at com.atlassian.plugins.rest.common.interceptor.impl.DispatchProviderHe
lper.invokeMethodWithInterceptors(DispatchProviderHelper.java:98)
at com.atlassian.plugins.rest.common.interceptor.impl.DispatchProviderHe
lper.access 100 ( D i s p a t c h P r o v i d e r H e l p e r . j a v a : 28 ) a t c o m . a t l a s s i a n . p l u g i n s . r e s t . c o m m o n . i n t e r c e p t o r . i m p l . D i s p a t c h P r o v i d e r H e l p e r 100(DispatchProviderHelper.java:28) at com.atlassian.plugins.rest.common.interceptor.impl.DispatchProviderHe lper 100(DispatchProviderHelper.java:28)atcom.atlassian.plugins.rest.common.interceptor.impl.DispatchProviderHelperResponseOutInvoker._dispatch(DispatchProviderHelper.java:202)

Caused by: javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpect
ed error: java.security.InvalidAlgorithmParameterException: the trustAnchor
s parameter must be non-empty

Caused by: java.lang.RuntimeException: Unexpected error: java.security.Inva
lidAlgorithmParameterException: the trustAnchors parameter must be non-empt
y

Caused by: java.security.InvalidAlgorithmParameterException: the trustAncho
rs parameter must be non-empty
如下情况有可能会导致这样的问题发生:
 服务器或者客户端上的证书已经过期了。
 服务器上的端口已经被重设成另外的一个。
可以读一读这里关于在 Java 软件中什么会导致“SSLException” 错误发生的讨论。
范例 084:
“资源异常”
“MissingResourceException” 会在某个资源丢失时发生。如果资源已经处于正确的类
路径之下的话,那就一般是因为一个属性配置文件并没有被恰当的进行了配置。这里有一个
示例:
45 / 54
java.util.MissingResourceException: Can’t find bundle for base name localem
sgs_en_US, locale en_US
java.util.ResourceBundle.throwMissingResourceException
java.util.ResourceBundle.getBundleImpl
java.util.ResourceBundle.getBundle
net.sf.jasperreports.engine.util.JRResourcesUtil.loadResourceBundle
net.sf.jasperreports.engine.util.JRResourcesUtil.loadResourceBundle
范例 085:
“NoRealCalExExt 异常”
“NoInitialContextException”会在 Java 应用程序想要执行命名操作可是不能创建一个
链接的时候发生.
[java] Caused by: javax.naming.NoInitialContextException: Need to specify c
lass name in environment or system property, or as an applet parameter, o
r in an application resource file: java.naming.factory.initial
[java] at javax.naming.spi.NamingManager.getInitialContext(NamingManage
r.java:645)
[java] at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.
java:247)
[java] at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialCon
text.java:284)
[java] at javax.naming.InitialContext.lookup(InitialContext.java:351)
[java] at org.apache.camel.impl.JndiRegistry.lookup(JndiRegistry.java:5
1)
这 会 是 一 个 解 决 起 来 比 较 复 杂 的 问 题 , 不 过 还 是 有 一 些 可 能 的 问 题 会 导 致
“NoInitialContextException” 错误消息的产生:
 应用程序可能没有正常的证书来建立连接。
 代码也许没有确认 JNDI 所需要的实现。
 InitialContext 类可能没有正确的属性来进行配置。
范例 086:
“迭代异常”
“NoSuchElementException” 会在一个迭代 (比如一个 for 循环)尝试去访问已经没有
了的下一个 元素时发生。
public class NoSuchElementExceptionDemo{
public static void main(String args[]) {
Hashtable sampleMap = new Hashtable();
Enumeration enumeration = sampleMap.elements();
enumeration.nextElement(); //java.util.NoSuchElementExcepiton her
e because enumeration is empty
}
46 / 54
}
Output:
Exception in thread “main” java.util.NoSuchElementException: Hashtable Enum
erator
at java.util.Hashtable$EmptyEnumerator.nextElement(Hashtable.java:1
084)
at test.ExceptionTest.main(NoSuchElementExceptionDemo.java:23)
“NoSuchElementException” 可以被如下这些方法抛出:
 Enumeration::nextElement()
 NamingEnumeration::next()
 StringTokenizer::nextElement()
 Iterator::next()
范例 087:
“对象不存在”
该 Java 软件错误消息会在一个应用程序尝试去访问一个对象中的某个域,可是指定域
在类中不复存在时发生.
public NoSuchFieldError()
该错误一般会在编译器中被捕获,但如果一个类的定义在编译和运行之间被修改了话,
也会被捕获到。
范例 088:“数字格式异常”
该 Java 软件错误消息会在应用程序尝试将一个字符串转换成一个数值类型, 而该数
值并非一个有效的数字字符串时发生。
package com.devdaily.javasamples;
public class ConvertStringToNumber {
public static void main(String[] args) {
try {
String s = “FOOBAR”;
int i = Integer.parseInt(s);
// this line of code will never be reached
System.out.println("int value = " + i);
}
catch (NumberFormatException nfe) {
nfe.printStackTrace();
}
}
}
当存在如下状况时 “NumberFormatException” 会被抛出:
47 / 54
 数值中前面或后面的空格。
 符号不在数值的前头。
 数值有逗号。
 本地化逻辑可能不会将其识别为一个有效的数值。
 数值太大,给定的数值类型装不下。
范例 089:
“超时异常”
该 Java 软件错误消息会在有一个阻塞操作超时的时候发生:
private void queueObject(ComplexDataObject obj) throws TimeoutException, In
terruptedException {
if (!queue.offer(obj, 10, TimeUnit.SECONDS)) {
TimeoutException ex = new TimeoutException(“Timed out waiting for p
arsed elements to be processed. Aborting.”);
throw ex;
}
}
范例 090:“… 可预料的”
当编码出现遗漏时,就会发生这类错误。可能是缺失了一个括号或者分号。
private static double volume(String solidom, double alturam, double areaBas
em, double raiom) { double vol;
if (solidom.equalsIgnoreCase(“esfera”){
vol=(4.0/3)Math.piMath.pow(raiom,3);
}
else {
if (solidom.equalsIgnoreCase(“cilindro”) {
vol=Math.pi*Math.pow(raiom,2)*alturam;
}
else {
vol=(1.0/3)Math.piMath.pow(raiom,2)*alturam;
}
}
return vol;
}
这种错误消息常常不会准确的定位到错误发生的位置。为了找到错误,建议:
 确保所有的左括号有对应匹配的右括号。
48 / 54
49 / 54
 (使用 IDE,译者注)在代码行前的提示中检查。这种 Java 软件错误不要由编译
器来关注,应该把更后面的工作交给它。
 有时候一个字符,比如一个左括号不应该写在 Java 代码的开始处。这样造成的结
果是开发者不会写右括号去凑成一对。
范例 091:“未封闭的 String 表达式”
“未封闭的 String 表达式”错误消息发生在 Sting 表达式结束时没有引号标记,错误
消息将在发生错误的同一行提示出来。一个 String 表达式在源码中是一个值。
public abstract class NFLPlayersReference {
private static Runningback[] nflplayersreference;
private static Quarterback[] players;
private static WideReceiver[] nflplayers;
public static void main(String args[]){
Runningback r = new Runningback(“Thomlinsion”);
Quarterback q = new Quarterback(“Tom Brady”);
WideReceiver w = new WideReceiver(“Steve Smith”);
NFLPlayersReference[] NFLPlayersReference;
Run();// { NFLPlayersReference = new NFLPlayersReferenc
e [3];
nflplayersreference[0] = r;
players[1] = q;
nflplayers[2] = w;
for ( int i = 0; i < nflplayersreference.length; i++ ) {
System.out.println(“My name is " + " nflplayersreference[i].get
Name());
nflplayersreference[i].run();
nflplayersreference[i].run();
nflplayersreference[i].run();
System.out.println(“NFL offensive threats have great running ab
ilities!”);
}
}
private static void Run() {
System.out.println(“Not yet implemented”);
}
}
通常情况下,错误发生在:
 String 表达式结束时没有使用引号标记。这种错误只要在 String 表达式结束是使
用引号就能简单的改正
50 / 54
 String 表达式超过一行时。长的 String 表达式可以被拆分成多个表达式,然后用
“+” 连接起来。
 引号是 String 表达式中的元素又没有使用下划线“\”进行转义。
范例 092:“非法的表达式开头”
出现“非法表达式开头”错误的原因有很多。但它最终归类于一个不太有用的错误消
息之一。有些开发者说这是由糟糕的代码造成的。
通常,创建表达式是用于生成新值或为变量赋值。编译器期望找到一个表达式,但找
不到它,因为语法不符合预期。在下面这些语句中可以找到此错误。
} // ADD IT HERE
public void newShape(String shape) {
switch (shape) {
case “Line”:
Shape line = new Line(startX, startY, endX, endY);
shapes.add(line);
break;
case “Oval”:
Shape oval = new Oval(startX, startY, endX, endY);
shapes.add(oval);
break;
case “Rectangle”:
Shape rectangle = new Rectangle(startX, startY, endX, endY);
shapes.add(rectangle);
break;
default:
System.out.println(“ERROR. Check logic.”);
}
}
} // REMOVE IT FROM HERE
}
范例 093:“找不到符号”
这是一个非常常见的问题,因为 Java 中的所有标识符都需要在使用之前进行声明。当
编译代码时,编译器并不理解标识符的含义。
在你遇到“找不到符号”消息时可能有很多种原因:
 标识符声明时的拼写可能与代码中使用时的拼写不同。
 该变量从未被声明。
 该变量使用的位置与其声明的作用域不同。
 类并未被导入。
范例 094:“公共类 XXX 应该在文件中出现”
“公共类 XXX 应该在文件中出现”这个消息出现在类 XXX 和 Java 程序文件名不一
致时。源代码只有在类名和 Java 文件名一样时才会被编译。:
package javaapplication3;
public class Robot {
int xlocation;
int ylocation;
String name;
static int ccount = 0;
public Robot(int xxlocation, int yylocation, String nname) {
xlocation = xxlocation;
ylocation = yylocation;
name = nname;
ccount++;
}
}
public class JavaApplication1 {
public static void main(String[] args) {
robot firstRobot = new Robot(34,51,“yossi”);
51 / 54
52 / 54
System.out.println(“numebr of robots is now " + Robot.ccount);
}
}
要修复这种情况:
 类名和文件名一样。
 确保这两个名字的大小写一致。
范例 095:“不兼容类型”
“不兼容的类型”是在赋值语句中尝试将变量与类型表达式匹配时触发的逻辑错误。
通常是在代码尝试将文本字符写入到整数中时出现,反之亦然。 这不是 Java 语法错误。
test.java:78: error: incompatible types
return stringBuilder.toString();
^
required: int
found: String
1 error
当编译器给出“不兼容的类型”消息时,确实没有一个简单的修复方案:
 有可以转换类型的函数。
 开发人员可能需要按照代码的预期修改之。
范例 096:“无效的方法声明;需求返回类型”
此错误表示方法签名中没有明确说明方法的返回类型。
public class Circle
{
private double radius;
public CircleR(double r)
{
radius = r;
}
public diameter()
{
double d = radius * 2;
return d;
}
}
53 / 54
有几种方式会触发“无效的方法声明; 需求返回类型“错误:
 忘记说明返回类型
 如果方法没有返回值,那么需要用“void”表示方法签名中的返回类型。
 构造函数名称不需要说明返回类型。 但是,如果构造函数名称中出现错误,那么编
译器会将构造函数视为没有指定类型的方法。
范例 097:“类 Y 中的方法 X 不能应用于给定类型”
此错误消息是 Java 中最有用的错误消息之一。 它解释了方法签名是如何调用错误参
数的。
RandomNumbers.java:9: error: method generateNumbers in class RandomNumber
s cannot be applied to given types;
generateNumbers();
required: int[]
found:generateNumbers();
reason: actual and formal argument lists differ in length
方法在被调用时期望获取在方法声明中定义的某些参数。 检查方法声明、谨慎调用方
法,以确保声明和调用的参数是兼容的。
范例 098:“缺少返回语句”
当一个方法缺少返回语句时,会发生“缺少返回语句”错误。 每一个有返回值的方法
(非 void 类型)必须有一句字面上的语句用以返回返回值,以便在方法外调用该值。
public String[] OpenFile() throws IOException {
Map<String, Double> map = new HashMap();
FileReader fr = new FileReader(“money.txt”);
BufferedReader br = new BufferedReader(fr);
try{
while (br.ready()){
String str = br.readLine();
String[] list = str.split(” “);
System.out.println(list);
}
} catch (IOException e){
System.err.println(“Error - IOException!”);
}
}
下面列举了一些编译器抛出“缺少返回语句”的消息的原因:
 返回语句被错误地省略了
 一个方法没有返回任何值,但是在方法签名中没有声明为 void 类型
范例 099:Java.Lang.ILLL 语言异常
这个异常的解释是"方法的参数错误”,很多 j2me 的类库中的方法在一些情
况下都会引发这样的错误,比如音量调节方法中的音量参数如果写成负数就会出现这个异
常,再比如 g.setcolor(int red,int green,int blue)这个方法中的三个值,如果有超过255的也
会出现这个异常,因此一旦发现这个异常,我们要做的,就是赶紧去检查一下方法调用中的
参数传递是不是出现了错误。
范例 100:Java.Lang.ILLCALL Access 异常
这个异常的解释是"没有访问权限”,当应用程序要调用一个类,但当前的方
法即没有对该类的访问权限便会出现这个异常。对程序中用了 package 的情况下要注意这个
异常。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值