现在的位置: 首页 > 综合 > 正文

java学习脚印 : 错误列表 Errorlist finally块的问题(finally block does not complete normally)

2014年01月09日 ⁄ 综合 ⁄ 共 9184字 ⁄ 字号 评论关闭

java学习脚印 : 错误列表 Errorlist

写在前面

     这是学习或者使用java过程中碰到的错误的一个归纳表,随着实践进行,这个列表将持续更新。

1.Eclipse给出警告“finally block does not complete normally”

可参考 : chh_jiang的专栏 finally块的问题(finally block does not complete
normally)

这里也转载过来:

当finall块中包含return语句时,Eclipse会给出警告“finally block does not complete normally”,原因分析如下:

1、不管try块、catch块中是否有return语句,finally块都会执行。

2、finally块中的return语句会覆盖前面的return语句(try块、catch块中的return语句),所以如果finally块中有return语句,Eclipse编译器会报警告“finally block does not complete normally”。


3、如果finally块中包含了return语句,即使前面的catch块重新抛出了异常,则调用该方法的语句也不会获得catch块重新抛出的异常,而是会得到finally块的返回值,并且不会捕获异常。

结论,应避免在finally块中包含return语句。如果你在前面的语句中包含了return语句或重新抛出了异常,又在finally块中包含了return语句,说明你概念混淆,没有理解finally块的意义。


2.三目条件运算符不能取代一般的if语句

条件表达式不能取代一般的if语句,仅当if语句中内嵌的语句为赋值语句(且两个分支都给同一变量赋值)时才能代替if语句.例如:

if(a%2==0)
    printf("even/n");
else
    printf("odd/n");
不能写成:

(a%2==0)?printf("even/n"):printf("odd/n");

但可以用下面语句代替:

printf("%s/n",(a%2==0?"even":"odd");


3.Jadclipse 插件安装不出现Jadclipse选项

Jadclipse 是一款反编译插件,可以按照:
http://www.mkyong.com/java/java-decompiler-plugin-for-eclipse/ 
   上的步骤安装,一般可以安装成功。

linux下安装不成功,除了clean参数重启外,可能还有一个原因:权限问题。

将拷贝的jar文件权限修改: sudo chown user:   sudo chmod u+x  后可以再试,应该成功了。

 4. java不同版本类间序列化出错,java.io.InvalidClassException

例如,错误信息如下,

Exception in thread "main" java.io.InvalidClassException: com.learningjava.Shape; local class incompatible: stream classdesc serialVersionUID = -2375324835839981909, local class serialVersionUID = -2375324835839981999


这是因为对类进行更新后,类之间的版本不兼容造成的,当类之间还有兼容可能性时,可以将更新后的类的序列化号码改为之前类的序列号,即可解决;当然如果更新后的类与之前完全没有兼容性了,这种方法不一定可行。


5. Error loading stylesheet: Parsing an XSLT stylesheet failed.

可能出错原因:

1)没有正确的xsl命名空间,例如xsl书写错误,

xmlns:xsl="http://www.w3.org/1999/xsl/Transform"

应该写为大写的: 

xmlns:xsl="http://www.w3.org/1999/XSL/Transform".(XML大小写敏感)

2)xsl代码中出现配对错误,例如没有关闭相应的标签,如没有</xsl:for-each>。


这里推荐xsl一个有力工具,xsltproc,这个工具使用的典型命令如下:

xsltproc -o output.html  Note.xsl Note3.xml

可以通过显式的错误信息准确定位,然后排除错误。

ubuntu用户,可到http://www.ubuntuupdates.org/package/core/saucy/main/base/xsltproc下载,其他用户可到相关网站搜索后安装。

另外关于更多使用xsl来样式化xml的工具可以参考:

《Process an XML document using an XSLT stylesheet》  这篇文章,里面有丰富介绍。

6. XML Parsing Error: junk after document element.

xml规定,xml文件必须有一个根元素,一般这个错误是由没有定义根元素引起,例如如下代码:

<?xml version="1.0" encoding="UTF-8"?>
<table>
   <tr>
   <td>Apples</td>
   <td>Bananas</td>
   </tr>
</table>
<table>
   <name>African Coffee Table</name>
   <width>80</width>
   <length>120</length>
</table>

这里解析是把前一个table作为根元素了,因此会提示后一个table以后的代码为垃圾元素。添加一个根元素即可解决问题。

解决这类低级错误的原则就是遵照xml的要求,编写风格良好的xml文档。

xml基本规范:

1)所有 XML 元素都须有关闭标签;
2)XML 标签对大小写敏感;
3)XML 必须正确地嵌套;
4)XML 文档必须有根元素;
5)在 XML 中,一些拥有特殊意义的字符用实体引用来代替;

7.与迭代相关的错误

这里列举两个与迭代相关的错误。

错误类型1:  试图使用不合适的迭代器,在迭代过程中修改元素值。

如下代码示例几种迭代方式,只有一种迭代方式能够在字符串上使用trim方法去掉头部和尾部的空格。

package com.learningjava;

import java.util.*;
/**
 * this program try more ways to traverse a List
 * @author wangdq
 * 2013-11-2
 */
public class CollectionsDemo6 {
	public static void main(String[] args) {
		String[] ads = new String[]{" what ", " you ", " see ", " is ",
				" what " ," you "," get "};
		List<String>  list= Arrays.asList(ads);
		System.out.println("before: "+list);
		TrimList_version3(list);//change version to observe result
		System.out.println("after:  "+list);
	}
	
	//version1 not work
	//Limitations: cannot be used to add, remove, or modify elements.
	public static void TrimList_version1 (List<String> list) {
		for(String s:list) {
			// change to the temporary variable
			// will not affect the value in the container
			s = s.trim();
		}
	}
	//version2 not work
	//Limitations: cannot be used to modify elements.
	public static void TrimList_version2 (List<String> list) {
		for(Iterator<String> it = list.iterator();it.hasNext();) {
			it.next().trim();
		}
	}
	//version3 work
	//Limitations: none.
	public static void TrimList_version3 (List<String> list) {
		for(ListIterator<String> listIt = list.listIterator();listIt.hasNext();) {
			listIt.set(listIt.next().trim());
		}
	}
	
}

只有方式三,输出结果去除了字符串头部和尾部的空格如下:

before: [ what ,  you ,  see ,  is ,  what ,  you ,  get ]
after:  [what, you, see, is, what, you, get]
其他两种方式视图修改局部变量,来达到修改列表中字符串的目的是行不通的。

错误类型2 :迭代过程中涉及到动态修改操作,导致数据变化,静态的迭代方式引起错误。

例如,我们想去除简单XML  DOM 树中的空白字符结点,有如下方法:

//This code will not work to remove whitespace text node
public static int removeWhiteSpaceTextElement_failed(Node node) {
	
	int count = 0;
	if(node == null)
		return 0;
	System.out.println("visting :"+node.getNodeName());
	if(node.getNodeType() == Node.ELEMENT_NODE) 
	{   
		NodeList childList = node.getChildNodes(); 
		//iterate childList
        //here we can not guarantee the node order after remove element
		//so this incur errors
		for(int ix = 0;ix<childList.getLength();ix++) {
			count += removeWhiteSpaceTextElement_failed(childList.item(ix));
		}
	} else if(node.getNodeType() == Node.TEXT_NODE) {
		Text textNode = (Text)node;
		String data = textNode.getData().trim();
		if(data.isEmpty()) {
			//remove whitespace textNode
			//System.out.println("remove "+textNode.getNodeName());
			textNode.getParentNode().removeChild(textNode);
			count++;
		}
	}
	return count;
}

    

    根据XML DOM规范,NodeList对象将保持自身的动态更新,也就是说删除结点后会反映到它的数据结构上。在这段代码中,迭代过程中如果删除了结点,却仍然继续使用先前保存的索引,那么就会引用到错误的结点上,导致该方法失效。

下面是改进的代码:


 /**
     * remove whitespace textnode
     * note,here we only consider the  ELEMENT_NODE and TEXT_NODE
     * @param node the node needed to purify by removing whitespace textnode
     * @return the nums of whitespace textnode that had been removed
     */
    public static int removeWhiteSpaceTextElement(Node node) {
    	
    	int count = 0;
    	if(node == null)
    		return 0;
    	//System.out.println("visting :"+node.getNodeName());
		if(node.getNodeType() == Node.ELEMENT_NODE) 
		{   
			//iterate child node
			for(Node childNode = node.getFirstChild(); childNode!=null;){
			    Node nextChild = childNode.getNextSibling();
			    // Do something with childNode, including move or delete...
			    count += removeWhiteSpaceTextElement(childNode);
			    childNode = nextChild;
			}
		} else if(node.getNodeType() == Node.TEXT_NODE) {
			Text textNode = (Text)node;
			String data = textNode.getData().trim();
			if(data.isEmpty()) {
				//remove whitespace textNode
				//System.out.println("remove "+textNode.getNodeName());
				textNode.getParentNode().removeChild(textNode);
				count++;
			}
		}
		return count;
    }

这两种与迭代相关的错误,值得我们思考。什么时候使用哪种迭代方式要灵活运用。


8.与刷新缓冲区相关的错误

    在操作文件时,使用带有缓冲的输出器,例如PrintWriter,即是没有调用flush或者传递给构造函数autoflush以true标志的话,文件也还是保存了,控制台还是输出了内容,例如如下代码:

PrintWriter filewriter = new PrintWriter(new FileOutputStream("1.txt"));
			filewriter.println("Hello! Enter BYE to exit.");
			filewriter.close();//will flush the buffer
			
			PrintWriter consolewriter = new PrintWriter(System.out);
			consolewriter.println("Hello! Enter BYE to exit.");
			consolewriter.close();//will flush the buffer

这里,我们依赖了close()方法刷新缓冲区的特性,如果你去掉close()方法调用,然后退出程序,在我的ubuntu系统中文件就没有写入任何东西,控制台也没有输出任何内容。


我们要注意缓冲区刷新问题,不要依赖于close()的刷新特性,因为有时候需要在关闭流之前就看到输出内容,尤其在网络应用程序中。

    例如,编写一个最简单的EchoServer程序,它用来回显客户端的输入内容,关键语句如下:

                        //create ServerSocket
			ServerSocket server = new ServerSocket(8100);
			//wait until a client connect to this port
			Socket incoming = server.accept();
			System.out.println("connection success.");
			//get i/o stream
			InputStream in = incoming.getInputStream();
			OutputStream out = incoming.getOutputStream();
			Scanner input = new Scanner(in);
			//attention,here we have to set autoflush
			PrintWriter writer = new PrintWriter(out,true);
			writer.println("Hello! Enter BYE to exit.");
			boolean done = false;
			while(!done && input.hasNextLine()) {
				String line = input.nextLine();
				//echo the what the client say
				writer.println("echo: "+line);
				if(line.trim().toUpperCase().equals("BYE")) {
					done = true;
				}
			}

   这里,如果没有向PrintWriter传递自动刷新的true值或者没有调用flush()方法,那么客户端输入内容后,将始终无法看到任何回显内容。

9. java.lang.UnsatisfiedLinkError: no HelloNative in java.library.path

使用java本地方法时没有找到共享库时会提示此错误。

解决方法:

1) 将当前目录添加到系统库路径中去,执行命令:

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

2)设置java.library.path属性:

java -Djava.library.path=. HelloNativeTest

可参考:

http://www.cnblogs.com/lovesaber/archive/2013/04/01/2993375.html


10. exception in thread main java.lang.NoClassDefFoundError wrong name

可参见
http://blog.csdn.net/xifeijian/article/details/8831916
.

11.Exception in thread "main" java.util.MissingResourceException: Can't find bundle for base name MessagesBundle, locale en_US

编译运行java tutorial 上国际化第一个程序,其中定位包的代码如下:

 messages = ResourceBundle.getBundle("MessagesBundle",currentLocale);


简单来说就是定位语言包失败,值得注意地地方如下:

1)在使用基名的时候,特别要注意给出完整的类名(或者路径名)。

2)MessagesBundle指的基名,现在有四个文件

  • MessagesBundle.properties
  • MessagesBundle_de_DE.properties
  • MessagesBundle_en_US.properties
  • MessagesBundle_fr_FR.properties

这里的MessagesBundle即指代MessagesBundle.properties这个文件基名,其余的资源文件都是根据基名_语言_国家来书写名称的。

可能的解决方法:

1)将几个propertires文件放置在src第一层目录下,如果编译错误,可能就是eclipse没有实现自动复制功能,我遇到的情况就是这种,可以到[preference]--->[java]--->[complier]-->[Building]里面选择[Restore Defaults]可能修复自动复制功能(这个查了好久,暂时我没找到更权威的方法)。

2)在src同级建立resource之类的文件夹,然后将几个propertires放进去,同时刷新工程,

[Properties]--->[java build path]--->[source]--[Add folder]将resource文件夹作为资源添加进来,之后eclipse就会自动复制到bin目录下了,可以正常工作。

3)使用包机制,可以查看其他文档,这个方法我暂时没有使用。


12.java 国际化 中文乱码

存储语言的属性文件都是ascii码文件,如果需要保存unicode字符文件到属性文件中,那么需要用\uxxxx编码方式进行编码。java提供native2ascii工具来实现,例如java tutorial中的那个Quick Example中添加中文资源文件,然后进行转化如下图所示:



转换后即可正常显式中文了。

当finall块中包含return语句时,Eclipse会给出警告“finally block does not complete normally”,原因分析如下:

1、不管try块、catch块中是否有return语句,finally块都会执行。

2、finally块中的return语句会覆盖前面的return语句(try块、catch块中的return语句),所以如果finally块中有return语句,Eclipse编译器会报警告“finally block does not complete normally”。


3、如果finally块中包含了return语句,即使前面的catch块重新抛出了异常,则调用该方法的语句也不会获得catch块重新抛出的异常,而是会得到finally块的返回值,并且不会捕获异常。

结论,应避免在finally块中包含return语句。如果你在前面的语句中包含了return语句或重新抛出了异常,又在finally块中包含了return语句,说明你概念混淆,没有理解finally块的意义。


2.三目条件运算符不能取代一般的if语句

条件表达式不能取代一般的if语句,仅当if语句中内嵌的语句为赋值语句(且两个分支都给同一变量赋值)时才能代替if语句.例如:

if(a%2==0)
    printf("even/n");
else
    printf("odd/n");
不能写成:

(a%2==0)?printf("even/n"):printf("odd/n");

但可以用下面语句代替:

printf("%s/n",(a%2==0?"even":"odd");


3.Jadclipse 插件安装不出现Jadclipse选项

Jadclipse 是一款反编译插件,可以按照:
http://www.mkyong.com/java/java-decompiler-plugin-for-eclipse/ 
   上的步骤安装,一般可以安装成功。

linux下安装不成功,除了clean参数重启外,可能还有一个原因:权限问题。

将拷贝的jar文件权限修改: sudo chown user:   sudo chmod u+x  后可以再试,应该成功了。

抱歉!评论已关闭.