Поймать исключение из метода toString в Java - PullRequest
1 голос
/ 19 марта 2019

Недавно я увидел следующий фрагмент кода на GitHub:

private static String safeToString(Object obj) {
    if (obj == null) return null;
    try {
        return obj.toString();
    } catch (Throwable t) {
        return "Error occured";
    }
}

Я никогда не помещал toString() вызовы методов внутри блоков try-catch. Но теперь, когда я думаю об этом, это может иметь смысл. Например, кто-то может перезаписать метод toString() в своем классе, который может вызвать исключение времени выполнения, например NullPointerException. Таким образом, мы можем попытаться поймать Exception. Но почему Throwable? Как вы думаете, это имеет какой-то смысл?

Ответы [ 4 ]

2 голосов
/ 19 марта 2019

Почти никогда нет веских причин для этого. контракт toString () не говорит, что допустимо генерировать исключение из этого метода. Любой код, который генерирует исключение, является неработающим кодом, и такое исключение необходимо раскрывать и исправлять, а не подавлять.

В случае, когда вы конвертируете некоторый «плохой» объект из библиотеки, которая находится вне вашего контроля, в строку, может быть целесообразно написать catch (RuntimeExcepton e), но такой улов должен сопровождаться комментариями, которые описывают в подробно, почему это необходимо, потому что в нормальных условиях это не нужно.

Не обращайте внимания на методы toString, генерирующие исключения, обратите внимание, что в Java уже есть по крайней мере два «безопасных» способа преобразования возможно нулевого значения в строку:

  • Objects.toString(obj, null)
  • String.valueOf(obj)

… поэтому я хотел бы задать вопрос, должен ли вообще существовать метод safeToString.

1 голос
/ 19 марта 2019

В редких случаях вы можете захотеть поймать ошибку, подобную этой.В целом, однако, это плохая идея, в этом случае это может иметь смысл, поскольку это обычно для целей ведения журнала / отладки и не используется непосредственно приложением.

Я бы предпочел что-то более информативное, такое как

private static String safeToString(Object obj) {
    if (obj == null) return null;
    try {
        return obj.toString();
    } catch (Throwable t) {
        return obj.getClass() + ".toString() threw " + t;
    }
}

например

class Element {
    Object data;
    Element e;

    public String toString() {
        return data + (e == null ? "" : e.toString());
    }
}

Element e = new Element();
e.data = "hi";
e.e = e; // oops

System.out.println("e: " + safeToString(e)); // doesn't kill the thread or JVM.
1 голос
/ 19 марта 2019

Throwable является родительским классом Exception и Error. Обычно это плохая идея, чтобы попытаться поймать Error, так как она разработана, чтобы ее не поймали.

Ловля Throwable - это просто переоцененная и контрпродуктивная версия ловли Exception. Тем не менее, если по какой-то причине вы создали другой вид Throwable, который вы хотите поймать вместе с Exception, это может быть способом сделать это в одном блоке try / catch. Не то чтобы это был чистый способ сделать это, но это сработало бы.

РЕДАКТИРОВАТЬ для TL; DR: в большинстве случаев, поймать Exception вместо Throwable.

0 голосов
/ 19 марта 2019

Неправильно отлавливать любые Throwable и затем продолжать выполнение, поскольку оно включает Error, что должно быть фатальным:

Из Javadocs :

Error - это подкласс Throwable, который указывает на серьезные проблемы, которые не должно пытаться решить разумное приложение. Большинство таких ошибок являются ненормальными условиями. Ошибка ThreadDeath, хотя и является "нормальным" условием, также является подклассом Error, поскольку большинство приложений не должны пытаться ее перехватить.

То есть некоторые Error s могут быть восстановлены (например, LinkageError), но другие не так много.

Но перехват Exception может быть допустимым вариантом использования, например, при регистрации кода, когда вы не хотите, чтобы выполнение прерывалось просто из-за сбоя при вызове toString():

private static String safeToString(Object obj) {
    try {
        return obj == null ? "null" : obj.toString();
    } catch (Exception e) {
        return "<exception: " + e + ">";
    }
}
...