среда, 1 августа 2012 г.

exception: multi-catch

multi-catch 

    В жизни так бывает, что catch-блоки по разным исключительным ситуациям выглядят идентично:
import java.io.IOException;

public class ExampleMultiCatch0 {
    public static void main(String[] args) {
        try {
            if (args == null) {
                throw new IOException();
            } else {
                throw new InterruptedException();
            }
        } catch (IOException e) {
            System.out.println("O mama ...");
        } catch (InterruptedException e) {
            System.out.println("O mama ...");
        }
    }
}

    Если содержимое блоков многострочно, то создаем специальный метод и не забываем его вызывать в каждом catch-блоке:
import java.io.IOException;

public class ExampleMultiCatch00 {
    public static void main(String[] args) {
        try {
            if (args == null) {
                throw new IOException();
            } else {
                throw new InterruptedException();
            }
        } catch (IOException e) {
            repair();
        } catch (InterruptedException e) {
            repair();
        }
    }

    private static void repair() {
        System.out.println("O mama ...");
        System.out.println("O daddy ...");
        System.out.println("O baby ...");
    }
}


    Можем, конечно, во избежании дубликации пользоваться полиморфностью перехвата и "ловить предка" (однако в такой catch-блок можем наловить и лишнего - любого наследника предка, в нашем примере, скажем NullPointerException):
import java.io.IOException;

public class ExampleMultiCatch000 {
    public static void main(String[] args) {
        try {
            if (args == null) {
                throw new IOException();
            } else {
                throw new InterruptedException();
            }
        } catch (Exception e) {
            System.out.println("O mama ...");
        }
    }
}
    
    Однако, хорошо бы синтаксически подчеркнуть тот факт, что реакция на два разных исключения идентична. Для этого в Java 7 ввели multi-catch блок:
import java.io.IOException;

public class ExampleMultiCatch1 {
    public static void main(String[] args) {
        try {
            if (args == null) {
                throw new IOException();
            } else {
                throw new InterruptedException();
            }
        } catch (IOException | InterruptedException e) {
            System.out.println("O mama ...");
        }
    }
}

    Используется синтаксис сходный с логическим ИЛИ:
public class ExampleMultiCatch11 {
    public static void main(String[] args) {
        if (3 < args.length | args.length < 33) {
            System.out.println("!");
        }
    }
}


more precise rethrow

    Однако, вот я хочу сохранить переменную e, какой тип выбрать? Так не выйдет:
import java.io.IOException;

public class ExampleMultiCatch2 {
    public static void main(String[] args) {
        try {
            if (args == null) {
                throw new IOException();
            } else {
                throw new InterruptedException();
            }
        } catch (IOException | InterruptedException e) {
            IOException | InterruptedException x = e; // don't compile
        }
    }
}

    Отступление: хотя такое вот пропускает:
x

    Ну хорошо, возьмем общего предка:
import java.io.IOException;

public class ExampleMultiCatch22 {
    public static void main(String[] args) {
        try {
            if (args == null) {
                throw new IOException();
            } else {
                throw new InterruptedException();
            }
        } catch (IOException | InterruptedException e) {
            Exception x = e;
        }
    }
}

    Однако вот такое компилятор не пропускает:    
import java.io.IOException;

public class ExampleMultiCatch222 {
    public static void main(String[] args) throws IOException, InterruptedException {
        try {
            if (args == null) {
                throw new IOException();
            } else {
                throw new InterruptedException();
            }
        } catch (IOException | InterruptedException e) {
            Exception x = e;
            System.out.println("O mama ...");
            throw x; // don't compile
        }
    }
}

    А так неохота (мы же точно знаем, что повторно кидаем одно-из-двух, а не более общего предка):
import java.io.IOException;

public class ExampleMultiCatch2222 {
    public static void main(String[] args) throws Exception {
        try {
            if (args == null) {
                throw new IOException();
            } else {
                throw new InterruptedException();
            }
        } catch (IOException | InterruptedException e) {
            Exception x = e;
            System.out.println("O mama ...");
            throw x;
        }
    }
}

    Однако, если не сохранять e в переменную (которой надо объявить тип, то все хорошо):
public class ExampleMultiCatch22222 {
    public static void main(String[] args) throws IOException, InterruptedException {
        try {
            if (args == null) {
                throw new IOException();
            } else {
                throw new InterruptedException();
            }
        } catch (IOException | InterruptedException e) {
            System.out.println("O mama ...");
            throw e;
        }
    }
}

    Начиная с Java 7 этот трюк работает также в такой форме:
import java.io.IOException;

public class ExampleMultiCatch3 {
    public static void main(String[] args) throws IOException, InterruptedException {
        try {
            if (args == null) {
                throw new IOException();
            } else {
                throw new InterruptedException();
            }
        } catch (Exception e) {
            System.out.println("O mama ...");
            throw e;
        }
    }
}