例外処理

Java

IllegalArgumentException 引数の値が不正

IllegalStateException 引数の状態が不正

NullPointerException

IndexOutOfBoundsException

ConcurrentModificationException 並行した変更を検出

UnsupportedOperationException

★カスタムException

DEMO

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のテスト

DEMO

テスト対象

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)