1.switch语句中使用字符串
package com.chap1.switch_string;
/** *//**
*
* 使用Switch_String
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月22日
*
*/
public class Title
{
public String generate(String name, String gender)
{
String title = "";
// case子句为字符串常量
switch (gender)
{
case "男":
title = name + " 先生";
break;
case "女":
title = name + " 女士";
break;
// case语句不能为null,语法错误
// case null;
// break;
default:
title = name;
}
return title;
}
public static void main(String[] args)
{
Title title = new Title();
System.out.println(title.generate("kobe", "男"));
// 表达式不能为null,否则运行空指针
// System.out.println(title.generate("kobe", null));
}
}
package com.chap1.switch_string;
/** *//**
*
* case子句值不能重复,Java字符串可以包含Unicode转义字符.->重复值检查是在Java编译器对Java源代码做完词法转换后进行->
* 词法转换过程包括了对Unicode转义字符的处理->即case子句的值在源代码中虽然不同,但是经过词义转换后是一样的,也会编译错误
*
* <pre>
* 实现原理
* 1.编译器层次上实现的。Java虚拟机和字节码代码这个层次上还是只支持与整数兼容的类型,减少这个特性影响的范围,降低实现的代价
* 2.即虽然源代码中使用字符串case子句,编译过程中,编译器会根据源代码的含义进行转换,转换成与整数兼容的格式
* 3.优化策略
* 1.switch中一个case->直接转为if
* 2.switch中一个case,一个default->直接转为if/else
* 3.多个case->转为Java7以前的case->使用字符串的hash值作为表达式的值
* 4.参见:Title.jad
* jad Title.class
* 5.Title.jd是用jd-gui反编译而成.
* 6.从两个反编译的文件来看,可确认的一点是转换:switch(s.hashCode())
* 7.从jad反编译的文件来看,+是用StringBuilder.append进行替换的->
* 8.如果程序中有多处swich_string->建议枚举,否则虽然直观,不过维护麻烦->因为case只是一个字符串常量而已.而枚举是一个类,更加方便和安全.
* </pre>
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月22日
*
*/
public class TitleDuplicate
{
public String generate(String name, String gender)
{
String title = "";
// 语法提示:Duplicate case,即重复的case子句,注释掉其中一个即可
// \u7537是"男"的Unicode转义字符
switch (gender)
{
// case "男":
// title = name + " 先生";
// break;
case "\u7537":
break;
default:
}
return title;
}
}
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: Title.java
package com.chap1.switch_string;
import java.io.PrintStream;
public class Title
{
public Title()
{
}
public String generate(String name, String gender)
{
String title;
label0:
{
title = "";
String s;
switch((s = gender).hashCode())
{
default:
break;
case 22899:
if(!s.equals("\u5973"))
break;
title = (new StringBuilder(String.valueOf(name))).append(" \u5973\u58EB").toString();
break label0;
case 30007:
if(s.equals("\u7537"))
{
title = (new StringBuilder(String.valueOf(name))).append(" \u5148\u751F").toString();
break label0;
}
break;
}
title = name;
}
return title;
}
public static void main(String args[])
{
Title title = new Title();
System.out.println(title.generate("kobe", "\u7537"));
}
}
package com.chap1.switch_string;
import java.io.PrintStream;
public class Title
{
public String generate(String name, String gender)
{
String title = "";
String str1;
switch ((str1 = gender).hashCode())
{
case 22899:
if (str1.equals("女")) {
break;
}
case 30007:
if ((goto 108) && (str1.equals("男")))
{
title = name + " 先生";
return title;
title = name + " 女士";
}
break;
}
title = name;
return title;
}
public static void main(String[] args)
{
Title title = new Title();
System.out.println(title.generate("kobe", "男"));
}
}
2.数值字面量的改进
package com.chap1.binary_literal;
/** *//**
*
* 二进制整数字面量
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月22日
*
*/
public class BinaryIntegralLiteral
{
// 打印二进制整数字面量
public void displayBinaryLiteral()
{
// 0b/0B表示二进制
System.out.println(0b1001);
System.out.println(0B1111);
System.out.println(0b01111111);
}
// 打印八进制整数字面量
public void displayOctalLiteral()
{
// 0表示8进制
// 1 * 8 + 7 = 15
System.out.println(017);
// 1 * 8的平方 + 2 * 8 + 7 = 87
System.out.println(0127);
}
// 打印十六进制整数字面量
public void displayHexLiteral()
{
// 0x/0X表示16进制
// a,b,c,d,e,f分别为10,11,12,13,14,15
// 15
System.out.println(0xf);
// 1 * 16 + 15 = 31
System.out.println(0X1f);
// 2 * 16 + 10 = 42
System.out.println(0x2a);
}
public static void main(String[] args)
{
BinaryIntegralLiteral bil = new BinaryIntegralLiteral();
bil.displayBinaryLiteral();
bil.displayOctalLiteral();
bil.displayHexLiteral();
}
}
package com.chap1.binary_literal;
/** *//**
*
* 数字字面量中使用下划线->方便分辨数字的位数->方便阅读->多位数值对齐等 ->允许数字之间插入任意多个下划线
* ->下划线只能用在数字之间->降低实现复杂度
* ->只需要扫描源代码的时候将数字之间的下划线直接删除即可->否则需要做语法分析,如_100可能是个整数字面量,也可能是个变量名称
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月22日
*
*/
public class Underscore
{
public void display()
{
System.out.println(1_500_000);
double value1 = 5_6.3_4;
// 可插入多个下划线
int value2 = 89_3__1;
System.out.println(value1);
System.out.println(value2);
}
public static void main(String[] args)
{
Underscore underscore = new Underscore();
underscore.display();
}
}
3.优化的异常处理
package com.chap1.exception_optimize;
/** *//**
*
* Java7改进了catch子句的语法,允许在其中指定多种异常,每个异常类型之间用“|” 分割,这样会减少一部分catch子句处理的重复代码
* ->#throwManyExceptions
* 注:1.catch子句中声明捕获的这些异常类中,不能出现重复的类型也不允许其中的某个异常是另外一个异常的子类,否则出现编译错误。
* ->#throwSubExceptions
* 2.如果catch子句中中声明了多个异常类,那么异常参数的具体类型是所有这些异常类型的最小上界(所以子句中“e”可调用的方法是最小祖先类的方法)。
* ->#throwIncludeRuntimeException
* 3.关于不允许其中的某个异常是另外一个异常的子类的情况,实际上是涉及捕获多个异常的实现方式。异常的声明位置很重要
* ->landon:注意经过测试和书里描述的并不一样
* ,允许其中的某个异常是另外一个异常的子类,这个没有特殊情况,如#throwIncludeRuntimeException的catch子句
* 是NullPointerException在前面还是在后面,都会提示编译错误的(可能是jdk7的版本不同)
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月24日
*
*/
public class CatchManyExceptions
{
// 抛出多个异常的方法
public void throwManyExceptions() throws ExceptionA, ExceptionB, ExceptionC
{
}
// 抛出的异常:D为C的子类
public void throwSubExceptions() throws ExceptionC, ExceptionD
{
}
// 可能会抛出RunTimeException
public void throwIncludeRuntimeException() throws NullPointerException,
RuntimeException
{
}
// 抛出两个子异常,D,E均为C的子类
public void throw2SubExceptions() throws ExceptionD, ExceptionE
{
}
public static void main(String[] args)
{
CatchManyExceptions catchManyExceptions = new CatchManyExceptions();
try
{
// Ctrl + 1,Surround with try/multi-catch
catchManyExceptions.throwManyExceptions();
} catch (ExceptionA | ExceptionB e)
{
System.err.println("catch Exception A | B");
} catch (ExceptionC e)
{
System.err.println("catch Exception C");
}
// 这里提示编译错误:The exception ExceptionD is already caught by the
// alternative ExceptionC
// try
// {
// catchManyExceptions.throwSubExceptions();
// } catch (ExceptionD | ExceptionC e)
// {
// }
// 这里提示编译错误: The exception ExceptionD is already caught by the
// alternative ExceptionC
// try
// {
// catchManyExceptions.throwSubExceptions();
// } catch ExceptionC | ExceptionD e)
// {
// }
// 这个是jdk1.7以前的实现方式
try
{
catchManyExceptions.throwSubExceptions();
} catch (ExceptionD e)
{
e.printStackTrace();
} catch (ExceptionC e)
{
e.printStackTrace();
}
// 这里提示编译错误:The exception NullPointerException is already caught by the
// alternative RuntimeException
// try
// {
// catchManyExceptions.throwIncludeRuntimeException();
// } catch (RuntimeException | NullPointerException e)
// {
// }
// The exception NullPointerException is already caught by the
// alternative RuntimeException
// try
// {
// catchManyExceptions.throwIncludeRuntimeException();
// } catch (NullPointerException | RuntimeException e)
// {
// }
try
{
catchManyExceptions.throwIncludeRuntimeException();
} catch (NullPointerException e)
{
} catch (RuntimeException e)
{
}
// 抛出的异常D和E均为C的子类,即“e”所代表的类型
try
{
catchManyExceptions.throw2SubExceptions();
} catch (ExceptionD | ExceptionE e)
{
// 可以调用最小祖先类的方法
e.exception_c();
}
}
}
class ExceptionA extends Exception
{
}
class ExceptionB extends Exception
{
}
class ExceptionC extends Exception
{
public void exception_c()
{
System.err.println("i'm exception c");
}
}
// 声明一个D异常继承自C
class ExceptionD extends ExceptionC
{
}
// 再次声明一个E异常继承自C;
class ExceptionE extends ExceptionC
{
}
package com.chap1.exception_optimize;
import java.io.FileInputStream;
import java.io.IOException;
/** *//**
* 使用异常包装技术
*
* <pre>
* 1.在不同的抽象层次上定义不同的 异常
* 2.一般说来,对于程序中可能出现的各种错误,都需要一个异常类与之对应
* 3.在一个异常要跨越多个抽象层次边界的时候,要进行包装。包装后的异常才是上层代码需要关注的。
* 4.Throwable构造方法中可传入另一个异常作为参数,而这个参数表示的异常会被包装在新的异常中,即cause
* public Throwable(Throwable cause)
* 5.使用异常包装的一个典型用法是为每一个层次定义一个基本的异常类,这个层次的所有公开方法在声明异常的时候都使用这个异常类。所有在这个层次上出现的底层异常都
* 被包装成这个异常
* </pre>
*
* <output>
* Exception in thread "main" com.chap1.exception_optimize.DataAccessException: java.io.FileNotFoundException: data.txt (系统找不到指定的文件。)
at com.chap1.exception_optimize.DataAccessGateway.load(DataAccessGateway.java:34)
at com.chap1.exception_optimize.DataAccessGateway.main(DataAccessGateway.java:41)
Caused by: java.io.FileNotFoundException: data.txt (系统找不到指定的文件。)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(Unknown Source)
at java.io.FileInputStream.<init>(Unknown Source)
at com.chap1.exception_optimize.DataAccessGateway.load(DataAccessGateway.java:30)
1 more
* </output>
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月23日
*
*/
public class DataAccessGateway
{
public void load() throws DataAccessException
{
try
{
FileInputStream input = new FileInputStream("data.txt");
} catch (IOException e)
{
// 上层代码只需要知道DataAccessException,而比不知晓IOException的存在,即包装异常异常
throw new DataAccessException(e);
}
}
public static void main(String[] args)
{
DataAccessGateway gateway = new DataAccessGateway();
gateway.load();
}
}
// 数据访问异常
class DataAccessException extends RuntimeException
{
public DataAccessException(Throwable cause)
{
super(cause);
}
}
package com.chap1.exception_optimize;
/** *//**
*
* 异常的“消失”,该例是在catch中抛出了NumberFormatException(包装);但是finally中又抛出一个ArithmeticException(包装)
* 原因:如果try中抛出了异常,在控制权转移到调用栈上一层代码之前,finally中的语句也会执行
*
* <output>
* Exception in thread "main" com.chap1.exception_optimize.BaseException: java.lang.ArithmeticException: / by zero
at com.chap1.exception_optimize.DisappearException.show(DisappearException.java:30)
at com.chap1.exception_optimize.DisappearException.main(DisappearException.java:38)
Caused by: java.lang.ArithmeticException: / by zero
at com.chap1.exception_optimize.DisappearException.show(DisappearException.java:27)
1 more
* </output>
*
* 从输出可以看出,输出的是finally中抛出的ArithmeticException的异常堆栈,而try中抛出的异常则“丢失”了.这种情况在日常开发还是比较常见的,如数据库操作的时候,
* finally语句关闭数据库连接(可能抛出异常),由于之前的异常丢失,可能无法准确确定异常的发生位置从而造成错误的判断
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月23日
*
*/
public class DisappearException
{
public void show() throws BaseException
{
try
{
Integer.parseInt("hello");
} catch (NumberFormatException e)
{
throw new BaseException(e);
} finally
{
try
{
int result = 2 / 0;
} catch (ArithmeticException e)
{
throw new BaseException(e);
}
}
}
public static void main(String[] args)
{
DisappearException disappearException = new DisappearException();
disappearException.show();
}
}
class BaseException extends RuntimeException
{
public BaseException(Throwable cause)
{
super(cause);
}
}
package com.chap1.exception_optimize;
/** *//**
*
* 通过Throwable#void addSuppressed(Throwable exception)解决'异常'消失问题
* 从下面的异常堆栈输出可以看出,多了一项"Suppressed"
*
* <output>
* Exception in thread "main" com.chap1.exception_optimize.BaseException: java.lang.NumberFormatException: For input string: "hello"
at com.chap1.exception_optimize.DisappearExceptionResolve.show(DisappearExceptionResolve.java:43)
at com.chap1.exception_optimize.DisappearExceptionResolve.main(DisappearExceptionResolve.java:51)
Caused by: java.lang.NumberFormatException: For input string: "hello"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at com.chap1.exception_optimize.DisappearExceptionResolve.show(DisappearExceptionResolve.java:21)
1 more
Suppressed: java.lang.ArithmeticException: / by zero
at com.chap1.exception_optimize.DisappearExceptionResolve.show(DisappearExceptionResolve.java:29)
1 more
* </output>
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月23日
*
*/
public class DisappearExceptionResolve
{
public void show() throws BaseException
{
Throwable throwable = null;
try
{
Integer.parseInt("hello");
} catch (NumberFormatException e)
{
throwable = e;
} finally
{
try
{
int result = 2 / 0;
} catch (ArithmeticException e)
{
if (throwable != null)
{
throwable.addSuppressed(e);
} else
{
throwable = e;
}
}
if (throwable != null)
{
throw new BaseException(throwable);
}
}
}
public static void main(String[] args)
{
DisappearExceptionResolve resolve = new DisappearExceptionResolve();
resolve.show();
}
}
package com.chap1.exception_optimize;
import java.math.BigDecimal;
/** *//**
*
* 余额不足异常
*
* <pre>
* 1.native2ascii,回车,控制台输入 余额不足得到->\u4f59\u989d\u4e0d\u8db3
* 2.写入message_zh_cn.properties
* </pre>
*
* <output>
* Exception in thread "main" com.chap1.exception_optimize.InsufficientBalanceException: 余额不足:8.09:10.32:2.23
at com.chap1.exception_optimize.InsufficientBalanceException.main(InsufficientBalanceException.java:47)
* </output>
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月23日
*
*/
public class InsufficientBalanceException extends LocalizedException
{
// 所需金额
private BigDecimal requested;
// 余额
private BigDecimal balance;
// 差额
private BigDecimal shortage;
public InsufficientBalanceException(BigDecimal requested,BigDecimal balance)
{
super("INSUFFICIENT_BALANCE_EXCEPTION");
this.requested = requested;
this.balance = balance;
this.shortage = requested.subtract(balance);
}
@Override
public String getLocalizedMessage()
{
return format(balance,requested,shortage);
}
public static void main(String[] args) throws Exception
{
throw new InsufficientBalanceException(new BigDecimal("10.32") , new BigDecimal("8.09"));
}
}
package com.chap1.exception_optimize;
import java.text.MessageFormat;
import java.util.ResourceBundle;
/** *//**
*
* 支持国际化异常消息的异常类,参考ResourceBundle的用法
*
* <pre>
* 1.读取资源属性文件(properties),然后根据.properties文件的名称信息(本地化信息),匹配当前系统的国别语言信息(也可以程序指定),然后获取相应的properties文件的内容。
* 使用这个类,要注意的一点是,这个properties文件的名字是有规范的:一般的命名规范是: 自定义名_语言代码_国别代码.properties,
* 2.如果是默认的,直接写为:自定义名.properties
* 3.比如:msg_en_US.properties,msg_zh_CN.properties,msg.properties
* 4.资源文件都必须是ISO-8859-1编码->native2ascii工具
* 5.MessageFormat:消息格式化
* </pre>
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月23日
*
*/
public abstract class LocalizedException extends Exception
{
private String messageKey;
protected ResourceBundle resourceBundle;
public LocalizedException(String msgKey)
{
messageKey = msgKey;
initResouceBundle();
}
public abstract String getLocalizedMessage();
// 覆写该方法
@Override
public String getMessage()
{
return getLocalizedMessage();
}
private void initResouceBundle()
{
resourceBundle = ResourceBundle.getBundle("message_zh_CN");
}
protected String format(Object args)
{
String message = resourceBundle.getString(messageKey);
return MessageFormat.format(message, args);
}
}
package com.chap1.exception_optimize;
/** *//**
*
* 精确的异常抛出 Java7中,如果一个catch子句中的异常参数类型在catch代码块中没有被修改,
* 而这个异常又被重新抛出则编译器会知道这个被重新抛出的异常肯定是try块中可以 抛出的异常,同时也是没有被之前的catch子句捕获的异常
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月28日
*
*/
public class PreciseThrowUse
{
public void testThrow() throws ExceptionA
{
try
{
throw new ExceptionASub2();
} catch (ExceptionA e)
{
// 这里编译报错:因为编译器知道抛出的精确异常是ExceptionASub2,所以你catchExceptionASub1则编译报错
// Java6编译器应该是可以编译通过的:1.因为该try子句抛出的异常是前一个catch子句声明的ExceptionA,所以第二个catch子句中(尝试)
// 捕获ExceptionA的子类型ExceptionASub1是合法的.
// try
// {
// throw e;
// }
// catch(ExceptionASub1 e2)
// {
//
// }
// 这个编译就正常通过了,因为e的精确类型就是ExceptionASub2
// try
// {
// throw e;
// } catch (ExceptionASub2 e2)
// {
//
// }
// 这个也正常编译通过,因为e肯定是ExceptionA类型
try
{
throw e;
} catch (ExceptionA e3)
{
}
}
}
}
// ExceptionA的一个子异常1
class ExceptionASub1 extends ExceptionA
{
}
// ExceptionA的一个子异常2
class ExceptionASub2 extends ExceptionA
{
}
package com.chap1.exception_optimize;
import java.io.FileInputStream;
import java.io.IOException;
/** *//**
*
* 对于"异常消失",通常有两种解决办法:这里说的是第二种,即Java7中为Throwable类增加的addSuppressed方法.即当一个
* 异常被抛出的时候,可能有其他异常
* 因为该异常而被抑制住,从而无法正常被抛出则可以通过addSuppressed方法把这些被抑制的方法记录下来。被异常的异常会出现在抛出的异常堆栈信息中
* ,也可以通过getSuppressed 方法来获取这些异常。这样做的好处是不会丢失任何异常,方便开发人员进行调试。
* 下面的是Throwable中源代码中1.7新增该相关的
*
* <pre>
* * @serial
* @since 1.7
*
* private List<Throwable> suppressedExceptions = SUPPRESSED_SENTINEL;
* </pre>
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月23日
*
*/
public class ReadFileAddSuppressedException
{
// 把finally语句产生的异常通过addSuppressed方法添加到try语句产生的异常中
public void read(String fileName) throws BaseException
{
FileInputStream input = null;
IOException ioException = null;
try
{
input = new FileInputStream(fileName);
} catch (IOException e)
{
ioException = e;
} finally
{
if (input != null)
{
try
{
input.close();
} catch (IOException e)
{
if (ioException != null)
{
// 加入“suppressedExceptions”
ioException.addSuppressed(e);
} else
{
ioException = e;
}
}
}
if (ioException != null)
{
throw new BaseException(ioException);
}
}
}
}
package com.chap1.exception_optimize;
import java.io.FileInputStream;
import java.io.IOException;
/** *//**
*
* 对于"异常消失",通常有两种解决办法:
* 1.抛出try语句产生的原始异常,忽略在finally块产生的异常,该出发点是try语句块的异常才是问题的根源
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月23日
*
*/
public class ReadFileIgnoreFinallyException
{
public void read(String fileName) throws BaseException
{
FileInputStream input = null;
IOException ioException = null;
try
{
input = new FileInputStream(fileName);
}
catch(IOException e)
{
ioException = e;
}
finally
{
if(input != null)
{
try
{
input.close();
}
catch(IOException e)
{
if(ioException == null)
{
ioException = e;
}
}
}
if(ioException != null)
{
throw new BaseException(ioException);
}
}
}
}
INSUFFICIENT_BALANCE_EXCEPTION = insufficient balance:{0}:{1}:{2}
INSUFFICIENT_BALANCE_EXCEPTION = \u4f59\u989d\u4e0d\u8db3\uFF1A{0}\uFF1A{1}\uFF1A{2} 4.try-with-resources语句
package com.chap1.try_resources;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
/** *//**
*
* 1.1.7引入了try语句进行资源管理的新用法,即try-with-resources语句
* 2.资源管理:谁申请,谁释放(如主存,磁盘文件,网络连接,数据库连接等)->数量有限,需要申请和释放的实体,都应该纳入到资源管理
* 3.1.7以前使用try-catch-finall语句块中的finally语句进行资源释放操作,虽然简单易懂,但是冗余代码较多
* 4.1.7对try语句进行了增强,使它可以对资源进行管理,保证资源总是被正确释放
* 5.使用以上该语句时,异常可能发生在try语句也可能发生在释放资源的时候,如果是前者,则try的异常会被正常抛出;如果同时出现异常,则抛出的是try的异常,
* 而释放资源的异常会被作为被抑制的异常添加进去即Throwable#addSuppressed方法实现
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月28日
*
*/
public class ResourceBasicUse
{
public String readFile(String path) throws IOException
{
// try()
// 该语句并不需要使用finally语句来保证打开的流被正确关闭,这是自动完成的。相对传统的finally的做法,简单很多
try (BufferedReader reader = new BufferedReader(new FileReader(path)))
{
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null)
{
builder.append(line);
// 换行符
builder.append(String.format("%n"));
}
return builder.toString();
}
}
public static void main(String[] args) throws Exception
{
ResourceBasicUse basicUse = new ResourceBasicUse();
basicUse.readFile("tmp.txt");
}
}
package com.chap1.try_resources;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/** *//**
*
* try-with-resources语句对多个资源进行管理
* 1.在对多个资源进行管理的时候,释放每个资源时都会产生异常;所有这些异常都会被加到资源初始化异常或者try语句块中抛出的异常的被抑制异常列表
* 2.try-with-resources语句也可以使用catch和finally子句。在catch子句中可以捕获try语句块和释放资源时可能发生的各种异常
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月28日
*
*/
public class MultiResourceUse
{
// 文件内容复制操作
public void copyFile(String fromPath, String toPath) throws IOException
{
// 可以对多个资源进行管理,如同时管理input和output
try (InputStream input = new FileInputStream(fromPath);
OutputStream output = new FileOutputStream(toPath))
{
byte[] bytes = new byte[8192];
int len = -1;
while ((len = input.read(bytes)) != -1)
{
output.write(bytes, 0, len);
}
}
// 可以catch
catch (Exception e)
{
e.printStackTrace();
}
// 可以finally
finally
{
System.out.println("copy file.finally");
}
}
public static void main(String[] args) throws Exception
{
MultiResourceUse mru = new MultiResourceUse();
mru.copyFile("source.txt", "dest.txt");
}
}
package com.chap1.try_resources;
/** *//**
* 自定义资源使用 1.被try语句管理的资源需要满足一个条件:即Java类要实现AutoCloseable接口.否则会出现编译错误.需要释放资源的时候,
* 该接口的close方法会被自动调用. 2.Java类库已经有不少接口或者类继承或者实现了该接口。->通常是IO操作和数据库相关的接口.
* 如:java.io.Closeable extends AutoCloseable ;java.sql.Connection extends
* Wrapper, AutoCloseable
* 3.如果希望自定义类也能利用try语句的自动化资源管理,只需要实现AutoCloseable并覆写close方法即可.
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月28日
*
*/
public class CustomResource implements AutoCloseable
{
@Override
public void close() throws Exception
{
System.out.println("进行资源释放");
}
public void useCustomResource() throws Exception
{
try (CustomResource resource = new CustomResource())
{
System.out.println("使用资源");
}
}
public static void main(String[] args) throws Exception
{
// Resource leak: 'cr' is never closed
CustomResource cr = new CustomResource();
// 输出使用资源
// 进行资源释放
// 从输出可以看出:close方法确实是自动调用的
cr.useCustomResource();
}
}
5.优化变长参数的方法调用
package com.chap1.varargs_optimize;
import java.util.ArrayList;
/** *//**
*
* 可变参数的优化 1.Java7之前,可变长度的参数与泛型一起使用则是个麻烦:编译器产生的警告过多,如useVarargs方法
* 为解决该问题,Java7引入了一个新的注解
* :@SafeVarargs,如果开发人员确定某个使用了可变长度参数的方法与泛型类使用不会出现类型安全问题,就可以使用这个注解 进行声明。
* 注:该注解只能用在参数长度可变的方法或者构造方法上且方法必须声明为static或者final上
* (landon:why:保证含有该注解的方法不会被覆写?否则覆写后会有潜在的类型安全的问题),否则会出现编译错误.如useVarargs3
* 使用该注解的前提是开发人员必须确保这个方法的实现中对泛型类型参数的处理不会引发类型安全问题
*
* <pre>
* @Documented
* @Retention(RetentionPolicy.RUNTIME)
* @Target({ ElementType.CONSTRUCTOR, ElementType.METHOD })
* public @interface SafeVarargs
* {
* }
* </pre>
*
* @author landon
* @since 1.7.0_51
* @version 1.0.0 2014年4月28日
*
*/
public class VarargsOptimize
{
// 如果参数传递的是不可具体话的类型,如List<String>这样的泛型,则会有警告信息.原因是可变长度的方法参数的实际值是通过数组传递的
// 而数组中存储的是不可泛化的泛型类对象,自身存在类型安全问题.
// 同理Arrays.asList/Collections.addAll方法
public static <T> T useVarargs(T args)
{
return args.length > 0 ? args[0] : null;
}
// 加上了该注解
@SafeVarargs
public static <T> T useVarargs2(T args)
{
return args.length > 0 ? args[0] : null;
}
// 编译错误:@SafeVarargs annotation cannot be applied to non-final instance
// method useVarargs3,因为不是final方法
// @SafeVarargs
// public <T> T useVarargs3(T args)
// {
// return args.length > 0 ? args[0] : null;
// }
// 编译通过,则证明final方法可以使用该注解:猜测原因:即含有该注解的方法不能被覆写,否则覆写后会有潜在的类型安全的问题.
@SafeVarargs
public final <T> T useVarargs4(T args)
{
return args.length > 0 ? args[0] : null;
}
public static void main(String[] args)
{
// 警告:Type safety: A generic array of ArrayList<String> is created for a
// varargs parameter
useVarargs(new ArrayList<String>());
// 没有任何警告,因为使用了@SafeVarargs注解
useVarargs2(new ArrayList<String>());
}
}
posted on 2014-04-28 20:16
landon 阅读(2132)
评论(1) 编辑 收藏