例外処理
Java
IllegalArgumentException 引数の値が不正
IllegalStateException 引数の状態が不正
NullPointerException
IndexOutOfBoundsException
ConcurrentModificationException 並行した変更を検出
UnsupportedOperationException
★カスタムException
public class MyException extends Exception {
private List<Throwable> causes = new ArrayList<Throwable>();
public MyException() {
super();
}
// 原因
public MyException(String message) {
super(message);
}
// 元例外
public MyException(Throwable e) {
super(e);
}
// 原因+元例外
public MyException(String message, Throwable e) {
super(message, e);
}
// 例外リスト
public MyException(List<? extends Throwable> causes) {
this.causes.addAll(causes);
}
public List<Throwable> getExceptions(){
return this.causes;
}
}
利用例
public class Test {
Logger log;
public void doStuff() throws MyException{
try {
InputStream is = new FileInputStream("NotExisted.txt");
// do something
} catch (FileNotFoundException e) {
log.info("File Not Found");
e.printStackTrace(); ←開発者のため
throw new MyException(e); ←利用者のため
} catch (SecurityException e) {
log.info("Security");
e.printStackTrace();
throw new MyException(e);
} catch (Exception e) {
log.info("Other");
e.printStackTrace();
throw new MyException(e);
} finally {
// do something
}
// FileNotFoundExceptionについての改善例
File file = new File("NotExisted.txt");
if(file.exists() && !file.isDirectory()){
try {
InputStream is = new FileInputStream(file);
// do something
// FileNotFoundExceptionがなくなる
} catch (SecurityException e) {
//省略
} finally {
// do something
}
}
}
// まとめる式
public void doStuff2() throws MyException{
List<Throwable> list = new ArrayList<Throwable>();
try {
// do something
} catch (Exception e) {
list.add(e);
}
try {
// do something
} catch (Exception e) {
list.add(e);
}
if(list.size() > 0){
throw new MyException(list);
}
}
}
★Exceptionのテスト
テスト対象
public void setAge(int age) {
if (age < 0 ) {
throw new IllegalArgumentException("age is invalid");
}
...
}
方法1 Try-catch
@Test
public void shouldGetExceptionWhenAgeLessThan0() {
Person person = new Person();
try {
person.setAge(-1);
fail("should get IllegalArgumentException");
} catch (IllegalArgumentException ex) {
assertThat(ex.getMessage(), containsString("age is invalid"));
}
}
方法2 JUnit/TestNG annotation
@Test(
expectedExceptions=IllegalArgumentException.class,
expectedExceptionsMessageRegExp="age is invalid")
public void shouldGetExceptionWhenAgeLessThan0() {
Person person = new Person();
person.setAge(-1);
}
方法3 Junit ExpectedException rule
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void shouldGetExceptionWhenAgeLessThan0() {
Person person = new Person();
exception.expect(IllegalArgumentException.class);
exception.expectMessage(containsString("age is invalid"));
person.setAge(-1);
}
方法4 catch-exceptionライブラリ
@Test
public void shouldGetExceptionWhenAgeLessThan0() {
Person person = new Person();
catchException(person).setAge(-1);
assertThat(caughtException(),instanceOf(IllegalArgumentException.class));
assertThat(caughtException().getMessage(), containsString("age is invalid"));
}
あるいは
@Test
public void shouldGetExceptionWhenAgeLessThan0() {
// given
Person person = new Person();
// when
when(person).setAge(-1);
// then (BDD風)
then(caughtException())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("age is invalid")
.hasNoCause();
// then (Hamcrest風)
assertThat(caughtException(), allOf(
instanceOf(IllegalArgumentException.class)
,hasMessage("age is invalid")
,hasNoCause()));
}
C#
すべてのExceptionはUnchecked
自作Exception
[Serializable]
public class MyException : ApplicationException
{
public MyException()
: base() { }
public MyException(string message)
: base(message) { }
public MyException(string message, Exception exception)
: base(message, exception) { }
public MyException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}
★throwについて
try
{
...
}
catch (Exception ex)
{
throw; // 警告 exが未使用
throw ex; // 以前の例外をクリアしてしまう
throw new Exception("XXX", ex); // 推薦 以前の例外をクリアせずにラップする
}
下記はJava
★finalizeについて
public class Sample {
private boolean released = false;
private FileInputStream stream = null;
public synchronized void release() throws Throwable{
if (!released) {
if(stream != null){
stream.close();
}
released = true;
}
}
@Override
public void finalize() throws Throwable {
this.release();
super.finalize();
}
}
public class Test {
private Sample sample = new Sample();
private void method() throws Throwable {
//sample.finalize(); 明示的にfinalize()を呼ばないよう
sample.release();
sample = null;
}
}
★Tip
public static boolean target(){
StackTraceElement[] sts = new Throwable().getStackTrace();
for (StackTraceElement st : sts) {
if (st.getMethodName().equals("method1")) {
return true;
}
}
throw new RuntimeException("Only used in method1");
}
------------------------------------------------------------------
public void method1(){
System.out.println(Test.target()); //true
}
public void method2(){
System.out.println(Test.target()); //例外
}
★補足
class Base{
public Base() throws IOException{
throw new IOException();
}
public void method() throws Exception{
// do something
}
}
class Sub extends Base{
public Sub() throws Exception{ ←IOException或いは親クラス
}
@Override
public void method() throws IOException{ ←Exception或いは子クラス
// do something
}
}
★Stack Traceについて
public class Test4 {
public static void method1() throws Exception{
throw new Exception("Error!");
}
public static void method2() throws Exception{
try {
method1();
}catch(Exception e) {
System.out.println("In method2");
e.printStackTrace();
throw e;
//throw (Exception)e.fillInStackTrace();
}
}
public static void main(String[] args) {
try {
method2();
}catch(Exception e) {
System.out.println("In Main");
e.printStackTrace();
for(StackTraceElement element : e.getStackTrace()) {
System.out.println(element);
}
}
}
}
出力:
In method2
java.lang.Exception: Error!
at com.Test4.method1(Test4.java:6)
at com.Test4.method2(Test4.java:10)
at com.Test4.main(Test4.java:21)
In Main
java.lang.Exception: Error!
at com.Test4.method1(Test4.java:6) ←fillInStackTraceを使う場合、この行は出力されない
at com.Test4.method2(Test4.java:10)
at com.Test4.main(Test4.java:21)
com.Test4.method1(Test4.java:6)
com.Test4.method2(Test4.java:10)
com.Test4.main(Test4.java:21)