Java中如何释放资源?
刚进公司时小白在学习 Java,碰到一个编程问题:文件操作关闭资源的时候,会莫名其妙的报错。代码如下:
publicvoidopenFile() throwsIOException { FileReaderreader=newFileReader("someFile"); inti=0; while(i!=-1){ i=reader.read(); System.out.println((char) i ); } reader.close(); System.out.println("--- File End ---"); }
扫地僧针对小白刚刚编程的经历,采用循循诱导的方式。
扫地僧:上面的代码是不是没有捕获异常?是不是可以把异常捕获到,再分析异常原因?
小白:对哦,那我使用 try … catch 试试:
publicvoidopenFile(){ try { // constructor may throw FileNotFoundExceptionFileReaderreader=newFileReader("someFile"); inti=0; while(i!=-1){ //reader.read() may throw IOExceptioni=reader.read(); System.out.println((char) i ); } reader.close(); System.out.println("--- File End ---"); } catch (FileNotFoundExceptione) { //do something clever with the exception } catch (IOExceptione) { //do something clever with the exception } }
扫地僧:做的很不错,知道捕捉多重异常了,资源的关闭是不是放到 finally 比较好?
小白:对哦,我看语法有这样的,那我重新写一下:
publicvoidopenFile() throwsIOException { FileReaderreader=null; try { reader=newFileReader("someFile"); inti=0; while(i!=-1){ i=reader.read(); System.out.println((char) i ); } } catch (FileNotFoundExceptione) { //do something clever with the exception } catch (IOExceptione) { //do something clever with the exception }finally { reader.close(); System.out.println("--- File End ---"); } }
小白:哦,还忘掉 reader 的判断,再改一下:
publicvoidopenFile() throwsIOException { FileReaderreader=null; try { reader=newFileReader("someFile"); inti=0; while(i!=-1){ i=reader.read(); System.out.println((char) i ); } } catch (FileNotFoundExceptione) { //do something clever with the exception } catch (IOExceptione) { //do something clever with the exception }finally { if(reader!=null){ reader.close(); } reader.close(); System.out.println("--- File End ---"); } }
扫地僧:reader 的关闭,是不是还有可能抛出异常,是不是还要捕获?
小白:是哦,我忘记了,修改后的是这样的吗?
publicvoidopenFile() throwsIOException { FileReaderreader=null; try { reader=newFileReader("someFile"); inti=0; while(i!=-1){ i=reader.read(); System.out.println((char) i ); } } catch (FileNotFoundExceptione) { //do something clever with the exception } catch (IOExceptione) { //do something clever with the exception }finally { if(reader!=null){ try { reader.close(); } catch (IOExceptione) { //do something clever with the exception } } reader.close(); System.out.println("--- File End ---"); } }
扫地僧:代码是不是太繁琐了?有没有更简洁的办法?让 Jvm 帮你处理一些繁琐的工作?
小白:听说过 try-with-resources,但没有用过。
扫地僧:那你看看这个是否简洁了一些呢?
publicvoidopenFile() throwsIOException { Stringline; try (BufferedReaderbr=newBufferedReader( newFileReader("C:\\testing.txt"))) { while ((line=br.readLine()) !=null) { System.out.println(line); } } catch (IOExceptione) { e.printStackTrace(); } }
从 JDK7 开始,使用 try-with-resources 可以自动释放资源,即把资源放到 try() 内部, JVM 会调用 java.lang.AutoCloseable.close() 方法,自动关闭 try() 内部的资源。
小白:厉害,我学会了。
扫地僧:那我考考你。
publicstaticvoidmain(String[] args) { try { System.out.println("Hello world"); return; } finally { System.out.println("Goodbye world"); } }
这个会打印出什么结果?
小白:“hello world” ,因为 return 退出了,finally 不能执行。
扫地僧:不对,finally 总是会执行的,打印:
HelloworldGoodbyeworld
小白:我明白了,finally 总是会执行的。
扫地僧:那可不一定哦,看看这个:
publicstaticvoidmain(String[] args) { try { System.out.println("Hello world"); System.exit(0); } finally { System.out.println("Goodbye world"); } }
小白:不是打印?
HelloworldGoodbyeworld
扫地僧:不论 try 语句块的执行是正常地还是意外地结束,finally 语句块确实都会执行。然而在这个程序中,try 语句块根本就没有结束其执行过程。System.exit 方法将停止当前线程和所有其他当场死亡的线程。finally 子句的出现并不能给予线程,继续去执行的特殊权限。如果想要执行,需要使用 ShutdownHook。JAVA中的ShutdownHook遇到进程挂掉的情况,且一些状态没有正确的保存下来,ShutdownHook可以在JVM关掉的时候执行一些清理现场的代码。
publicstaticvoidmain(String[] args) { System.out.println("Hello world"); Runtime.getRuntime().addShutdownHook( newThread() { publicvoidrun() { System.out.println("Goodbye world"); } }); System.exit(0); }
小白:好神奇!
扫地僧:学无止境,一起加油!今天到这里了!
