Interviewer Stop Ask Series: в чем разница между Java Exception и Error?

Java
Interviewer Stop Ask Series: в чем разница между Java Exception и Error?

Вчера сэр Лао Юань ждал кандидатов в комнате для собеседований и услышал, как интервьюер в соседней комнате задает кандидату вопрос: "JavaизExceptionа такжеErrorкакие отличия есть? ". Сэр Лао Юань услышал это и улыбнулся в своем сердце. Это обычная серийная проблема. В результате я не ожидал, что кандидат застрянет на первом вопросе. Сэр Лао Юань не мог не потеть перед ответом. кандидат Этот вопрос на самом деле довольно простой... В то время я решил написать статью об этом.JavaИсключения объясняются понятно, чтобы каждый больше не боялся столкнуться с такими проблемами на собеседовании.

заявление о броске

немногоjavaБазовые студенты должны знатьthrowЭто предложение (если вы его не знаете, то можете нажать на крестик в правом верхнем углу 😂). мы все знаемthrowоператор делает свое дело, он выдаетthrowableОбъект подкласса, виртуальная машина может выполнять ряд операций над этим объектом или может обрабатывать это исключение (посредствомcatch) или не может его обработать, что в конечном итоге приводит к остановке потока, в котором находится инструкция.

Итак, как именно JVM это делает? Давайте попробуем:

Сначала напишите кусок кода,throwОдинRuntimeException:

package com.company;

public class TestException {
    public static void main(String[] args) {
        throw new RuntimeException();
    }
}

После компиляции кclassКаталог, в котором находится файл, используйтеjavap -verboseОткройте файл .class:

 javap -verbose TestException

Некоторые байткод можно увидеть. Мы находим Bytecode, соответствующий функции TESTEXCECTION.MAIN:

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: new           #2                  // class java/lang/RuntimeException
         3: dup
         4: invokespecial #3                  // Method java/lang/RuntimeException."<init>":()V
         7: athrow
      LineNumberTable:
        line 5: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       8     0  args   [Ljava/lang/String;

Смотретьcodeчасть, на самом деле первые три строки соответствуютnewRuntimeExcpetion() по причинам темы не будет здесь раскрываться. Изюминкой является последний бросок, что именно он делает?

1. 先检查栈顶元素,必须是一个java.lang.Throwable的子类对象的引用;

2. 上述引用出栈,搜索本方法的异常表,是否存在处理此异常的 handler;

    2.1 如果找到对应的handler,则用这个handler处理异常;

    2.2 如果找不到对应的handler,当前方法栈帧出栈(退出当前方法),到调用该方法的方法中搜索异常表(重复2);

3. 如果一直找不到 handler,当前线程终止退出,并输出异常信息和堆栈信息(其实也就是不断寻找 handler 的过程)。

Вы можете видеть, что действие броска имеет несколько возможных побочных эффектов:

  1. Завершить вызов текущего метода и передать информацию об исключении вызывающему методу;
  2. Если исключение не было найдено в таблице исключений методаhandler, что в конечном итоге приведет к завершению потока.

Ну, вот мы и выяснили, что делает throw. Но мы заметили, что инструкция athrow ищет ссылку на объект подкласса java.lang.Throwable, что означает, что за оператором throw может следовать только объект подкласса java.lang.Throwable, иначе компиляция завершится ошибкой. Так что же такое Throwable?

Кластер метательного класса

ThrowableКак следует из названия, этоМетательныйобъект! Это родительский класс всех исключений в java:

public class Throwable implements Serializable {
    ...
}

JDK поставляется с ненормальными кластерами классов, наследование, вероятно, выглядит так:

Прежде всего, вы можете видеть, что Throwable делится на две категории: Exception и Error.

Error

Ошибка — это ошибка, выдаваемая виртуальной машиной Java, серьезная проблема, возникающая при запуске программы.

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

Это похоже на то, что лодка сломана, и пассажиры на ней ничего не могут сделать, даже если они знают, что лодка сломана, потому что это не то, что они могут починить.

Exception

Исключения — это возможные предсказуемые, восстанавливаемые проблемы в приложении.

Что ты имеешь в виду? Другими словами, исключения — это все исключения, возникающие на уровне пользовательского кода. Другими словами, эти аномалии могут быть устранены самими пассажирами корабля. Например, обычное исключение нулевого указателяNullPointerException, выдает, когда нижний индекс массива выходит за пределыArrayIndexOutOfBoundException.

Это все проблемы, вызванные неправильной работой "пассажира", поэтому "пассажирку" можно решить.

На данный момент уже решен вопрос интервью, услышанный сэром Лао Юанем?

CheckedException и UncheckedException

Сэр Laoyuan ранее также говорил, что это обычная серийная проблема. Итак, решив первый вопрос, что интервьюер спросит дальше?

Из описания в предыдущем разделе мы видим, чтоThrowableСама система имеет большую связь с программистами.Exceptionи его подклассы. Поскольку пассажиры на корабле созданы программистами, программистам все равно придется более тщательно справляться с их неправильным поведением.

Exceptionможно разделить на два типа,CheckedExceptionа такжеUncheckedException.

  • UncheckedException

Как следует из названия, UncheckedException — это исключение, которое нельзя проверить. JVM предусматривает, что исключения, унаследованные от RuntimeException, являются UncheckedException.

  • CheckedException

Все исключения, кроме RuntimeException.

Итак, вопрос в том, что это такое?проверенное исключение? Кто проверяет?

бросает заявление

Рассмотрим следующий сценарий развития:

  • Одноклассник А написал класс инструментов, который был скомпилирован в пакет jar для использования одноклассником Б.
  • Когда одноклассник Б вызывал этот инструментальный класс, возникало множество разных типов исключений из-за разных сценариев применения.Каждый раз, когда появлялось новое исключение, однокласснику Б приходилось модифицировать код для адаптации, что было очень болезненно. . .

Чтобы решить проблему в этом сценарии, JVM предусматривает, что каждая функция должна знать исключения, которые должны быть выброшены самой, и объявить исключения, которые могут быть выброшены функцией, с помощью оператора throws при объявлении функции:

 public Remote lookup(String name)
        throws RemoteException, NotBoundException, AccessException;

Это утверждение - то, что я сказал ранеепроверенное исключение.

ТакНепроверенные исключенияВ чем дело?

фактическиCheckedExcpetionзачем бытьCheck, главным образом потому, что вызывающая сторона поручила вам обрабатывать эти исключения.

кjava.net.URLНапример, конструктор этого класса:

public final class URL implements java.io.Serializable {
    ...
    public URL(String protocol, String host, int port, String file,
               URLStreamHandler handler) throws MalformedURLException {
       ...
       if (port < -1) {
                throw new MalformedURLException("Invalid port number :" +
                                                    port);
            }
    }
}

MalformedURLExceptionэтоchecked exception, когда вошлиport < -1, программа выдаетMalformedURLExceptionисключение, поэтому вызывающий может исправить этоportВведите и получите правильный URL.

Но есть некоторые случаи, такие как следующая функция:

public void method(){
   int [] numbers = { 1, 2, 3 };
   int sum = numbers[0] + numbers[3];
}

из-заnumbersВ массиве всего 3 элемента, но функция принимает 4-й элемент, поэтому вызываемmethod()выдает исключениеArrayIndexOutOfBoundsException. Но вызывающая сторона этого исключения не может быть исправлена.

Для этого случая JVM специально предусматриваетRuntimeExceptionЭтот подкласс иUnchekcedException, может не бытьthrowsЗаявление объявляет, что при компиляции не будет сообщено об ошибке.

Обработка исключений

Мы представили определение и методы генерации исключений выше, так как же перехватывать и обрабатывать исключения? Теперь твоя очередьtry catch finallyпоявился. Например:

public void readFile(String filePath) throws FileNotFoundException {
    FileReader fr = null;
    BufferedReader br = null;
    try{
        fr = new FileReader(filePath);
        br = new BufferedReader(fr);
        String s = "";
        while((s = br.readLine()) != null){
            System.out.println(s);
        }
    } catch (IOException e) {
        System.out.println("读取文件时出错: " + e.getMessage());
    } finally {
        try {
            br.close();
            fr.close();
        } catch (IOException ex) {
            System.out.println("关闭文件时出错: " + ex.getMessage());
        }
    }
}

Это функция, которая печатает содержимое файла построчно. при вводеfilePathКогда нет, бросаетCheckedException FileNotFoundException.

В процессе чтения файла также могут возникать непредвиденные ситуации, которые могут вызвать некоторыеIOException, поэтому код связывает возможныеIOExceptionПроведенныйtry catch finallyобработка.tryБлок кода — это обычный бизнес-код,catchдля обработки исключений,finallyБудь тоtryЯвляется ли это ненормальным или нет, код должен быть выполнен. дляreadFileДля этой функции нужно закрыть дескриптор файла, чтобы предотвратить утечку памяти.

Что более неудобно здесь, так это то, чтоfr brнуждаться вfinallyблок, так и должно бытьtryобъявить раньше. Есть ли более элегантный способ написать это?

Вот некоторые новые функции, представленные в JDK 7:

try-with-resources

try-with-resourcesНе функция, а набор решений, позволяющих сделать операторы перехвата исключений более элегантными.

для любого реализованногоjava.io.Closeableинтерфейсный класс, покаtryИнициализируется в следующем (),JVMавтоматически добавит блоки кода finally для выполнения этихCloseableизclose()метод.

ClosableОпределяется следующим образом:

public interface Closeable extends AutoCloseable {

    /**
     * Closes this stream and releases any system resources associated
     * with it. If the stream is already closed then invoking this
     * method has no effect.
     *
     * <p> As noted in {@link AutoCloseable#close()}, cases where the
     * close may fail require careful attention. It is strongly advised
     * to relinquish the underlying resources and to internally
     * <em>mark</em> the {@code Closeable} as closed, prior to throwing
     * the {@code IOException}.
     *
     * @throws IOException if an I/O error occurs
     */
    public void close() throws IOException;
}

из-заFileReaderа такжеBufferedReaderвсе сбудетсяCloseableинтерфейс, поэтому наш предыдущийreadFileФункцию можно переписать так:

    public void readFile(String filePath) throws FileNotFoundException {
        try(
                FileReader fr = new FileReader(filePath);
                BufferedReader br = new BufferedReader(fr)
        ){
            String s = "";
            while((s = br.readLine()) != null){
                System.out.println(s);
            }
        } catch (IOException e) {
            System.out.println("读取文件时出错: " + e.getMessage());
        }
    }

Разве это не намного круче?

Несколько частных случаев окончательно

Наконец, давайте поговорим о наконец 😂.

Порядок выполнения полного блока try catch finally следующий: попробовать --> поймать --> наконец.

Но всегда есть какой-то странный код, на который стоит обратить внимание:

    public static void returnProcess() {
        try {
            return;
        } finally {
            System.out.println("Hello");
        }
    }

Угадайте, будет ли выполняться код в finally? Логически говоря, сначала выполните блок кода try и вернитесь напрямую,finallyОн больше не должен работать? Но реальность такова,finallyКод вreturnбудет казнен потом.

Затем посмотрите на код ниже и угадайтеfinallyКод не будет выполняться:

    public void exitProcess() {
        try {
            System.exit(1);
        } finally {
            System.out.println("Hello");
        }
    }

Некоторые одноклассники скажут это, разве я не говорил это раньше, несмотря ни на что?tryВыдает ли код исключение,finallyКод будет выполнен. Но это утверждение не точно. В этом примере код в try вызываетSystem.exit(1), этот оператор выйдет напрямуюJavaпроцесс, процесс завершился,finallyМеханизм выполнения блока кода инструкции не существует.finallyОператор in не будет выполнен.

Посмотрите еще раз на следующий код:

    public static int returnInt() {
        int res = 10;
        try {
            res = 30;
            return res;
        } finally {
            res = 50;
        }
    }

    public static void main(String[] args) {
        System.out.println(returnInt());
    }

Основываясь на опыте с кодом 1,finallyОператор in будет выполняться, затемres50 должно быть присвоено, поэтому программа будет выводиться50Бар?

Но это не так, программа все равно будет выводиться30.

Какой! ! !

Пожалуйста, не смотрите на это с точки зрения функцийreturnзаявление, но стоятьJVMПерспективаreturnутверждение. Из функции перспективы,returnВсегда выполняется последняя строка инструкции. но стояJVMС точки зрения, это просто обычное предложение.

Озорной одноклассник снова спросил: А что, еслиfinallyсерединаreturnЧто произойдет через мгновение?

    public static int returnInt() {
        int res = 10;
        try {
            res = 30;
            return res;
        } finally {
            res = 50;
            return res;
        }
    }

    public static void main(String[] args) {
        System.out.println(returnInt());
    }

Ха-ха, на этот раз будет вывод50!

Что за черт! Я был перепутан на ветру!

Это потому чтоreturnУтверждения фактически «перезаписываются». То есть, когдаfinallyпоявился вreturnутверждение, которое появляется в другом местеreturnЗаявления недействительны. а такжеfinallyв предложенииreturnкогда заявлениеres = 50после этого оператора присваивания, поэтому он возвращает50.

Вот и получается, что использовать return в блоке finally очень опасно:

Не используйте return в finally!

резюме

Эта статья в основном представляет следующее содержание:

  • JavaКак работает исключение;
  • Javaкластер класса исключений;
  • процесс обработки исключений;
  • finallyНесколько исключений из заявления.

Надеюсь, что после прочтения этой статьи вы не будетеJavaИсключительные вопросы интервью! Из-за ограниченного уровня, если у вас есть какие-либо недостатки, вы можете обсудить их в области сообщений!

Категории