Вопросы и ответы на собеседование по исключениям в Java

Java предоставляет надежный и объектно-ориентированный подход к обработке сценариев исключений, известный как Обработка исключений в Java. Некоторое время назад я написал длинный пост о Обработке исключений в Java, и сегодня я перечисляю некоторые важные Вопросы по исключениям в Java с ответами, чтобы помочь вам на собеседованиях.

  1. Что такое исключение в Java?
  2. Какие ключевые слова для обработки исключений существуют в Java?
  3. Объясните иерархию исключений в Java?
  4. Какие важные методы класса исключений в Java?
  5. Объясните функцию ARM в Java 7 и множественный блок catch?
  6. В чем разница между проверяемыми и непроверяемыми исключениями в Java?
  7. В чем разница между ключевыми словами throw и throws в Java?
  8. Как написать пользовательские исключения в Java?
  9. Что такое OutOfMemoryError в Java?
  10. Какие сценарии могут вызывать “Исключение в потоке main”?
  11. В чем разница между final, finally и finalize в Java?
  12. Что происходит, когда исключение выбрасывается в методе main?
  13. Можем ли мы иметь пустой блок catch?
  14. Предоставьте некоторые лучшие практики обработки исключений в Java?
  15. В чем проблема с нижеприведенными программами и как мы ее исправим?

1. Что такое исключение в Java?

Исключение – это событие ошибки, которое может произойти во время выполнения программы и нарушить ее нормальный ход. Исключение может возникнуть из различных ситуаций, таких как неправильные данные, введенные пользователем, сбой оборудования, сбой соединения с сетью и т. д. Когда происходит ошибка при выполнении оператора Java, создается объект исключения, а затем JRE пытается найти обработчик исключений для обработки исключения. Если подходящий обработчик исключений найден, то объект исключения передается в код обработчика для обработки исключения, известной как перехват исключения. Если обработчик не найден, то приложение выбрасывает исключение в среду выполнения, и JRE завершает программу. Фреймворк обработки исключений в Java используется только для обработки ошибок времени выполнения, ошибки времени компиляции не обрабатываются фреймворком обработки исключений.

2. Какие ключевые слова обработки исключений используются в Java?

В Java используются четыре ключевых слова для обработки исключений.

  1. throw: Иногда мы явно хотим создать объект исключения, а затем сгенерировать его, чтобы прервать нормальное выполнение программы. Ключевое слово throw используется для генерации исключений для обработки ими времени выполнения.
  2. throws: Когда мы генерируем проверяемое исключение в методе и не обрабатываем его, тогда мы должны использовать ключевое слово throws в сигнатуре метода, чтобы уведомить вызывающую программу о возможных исключениях, которые могут быть сгенерированы методом. Вызывающий метод может обработать эти исключения или передать их своему вызывающему методу, используя ключевое слово throws. Мы можем указать несколько исключений в разделе throws, и его можно использовать также с методом main().
  3. try-catch: Мы используем блок try-catch для обработки исключений в нашем коде. try – это начало блока, а catch – в конце блока try для обработки исключений. Мы можем иметь несколько блоков catch с одним блоком try, и блоки try-catch могут быть также вложенными. Блок catch требует параметра, который должен быть типа Exception.
  4. в конце концов: Блок finally является необязательным и может использоваться только с блоком try-catch. Поскольку исключение прерывает процесс выполнения, у нас может остаться открытым некоторое количество ресурсов, которые не будут закрыты, поэтому мы можем использовать блок finally. Блок finally выполняется всегда, независимо от того, возникает ли исключение или нет.

3. Объясните иерархию исключений в Java?

Исключения Java иерархичны, и наследование используется для категоризации различных типов исключений. Throwable является родительским классом иерархии исключений Java, и у него есть два дочерних объекта – Error и Exception. Исключения дополнительно делятся на проверяемые исключения и исключения времени выполнения. Ошибки – это исключительные ситуации, которые выходят за рамки приложения, и их невозможно предвидеть и восстановиться от них, например, сбой оборудования, сбой JVM или ошибка “недостаточно памяти”. Проверяемые исключения – это исключительные ситуации, которые мы можем предвидеть в программе и попытаться восстановиться от них, например, FileNotFoundException. Мы должны перехватывать это исключение и предоставлять пользователю полезное сообщение, а также правильно регистрировать его для целей отладки. Exception – это родительский класс всех проверяемых исключений. Исключения времени выполнения вызываются некорректным программированием, например, попытка извлечь элемент из массива. Мы должны проверить длину массива перед попыткой извлечения элемента, иначе это может вызвать ArrayIndexOutOfBoundException во время выполнения. RuntimeException – это родительский класс всех исключений времени выполнения.

4. Какие важные методы класса Java Exception?

Исключение и все его подклассы не предоставляют никаких специфических методов, и все методы определены в базовом классе Throwable.

  1. String getMessage() – Этот метод возвращает строку сообщения Throwable, и сообщение может быть предоставлено при создании исключения через его конструктор.
  2. String getLocalizedMessage() – Этот метод предоставлен для того, чтобы подклассы могли переопределить его для предоставления локализованных сообщений вызывающей программе. Реализация класса Throwable этого метода просто использует метод getMessage() для возврата сообщения об исключении.
  3. synchronized Throwable getCause() – Этот метод возвращает причину исключения или null, если причина неизвестна.
  4. String toString() – Этот метод возвращает информацию о Throwable в виде строки; возвращенная строка содержит имя класса Throwable и локализованное сообщение.
  5. void printStackTrace() – Этот метод печатает информацию трассировки стека в стандартный поток ошибок; этот метод перегружен, и мы можем передать PrintStream или PrintWriter в качестве аргумента для записи информации трассировки стека в файл или поток.

5. Объясните функцию ARM и множественный блок catch в Java 7?

Если вы ловите много исключений в одном блоке try, вы заметите, что код блока catch выглядит очень уродливо и в основном состоит из избыточного кода для регистрации ошибки. Имея это в виду, одной из особенностей Java 7 был множественный блок catch, где мы можем ловить несколько исключений в одном блоке catch. Блок catch с этой функцией выглядит следующим образом:

catch(IOException | SQLException | Exception ex){
     logger.error(ex);
     throw new MyException(ex.getMessage());
}

Большую часть времени мы используем блок finally только для закрытия ресурсов, и иногда мы забываем их закрыть, и получаем исключения времени выполнения, когда ресурсы исчерпаны. Эти исключения трудно отлаживать, и нам может потребоваться просматривать каждое место, где мы используем этот тип ресурса, чтобы убедиться, что мы его закрываем. Таким образом, в Java 7 одним из улучшений была функция try-with-resources, где мы можем создавать ресурс в самом операторе try и использовать его внутри блока try-catch. Когда выполнение выходит из блока try-catch, среда выполнения автоматически закрывает эти ресурсы. Пример блока try-catch с этим улучшением:

try (MyResource mr = new MyResource()) {
            System.out.println("MyResource created in try-with-resources");
        } catch (Exception e) {
            e.printStackTrace();
        }

Подробнее об этом можно прочитать в Java 7 ARM.

6. В чем разница между проверяемыми и непроверяемыми исключениями в Java?

  1. Проверяемые исключения должны быть обработаны в коде с использованием блока try-catch, в противном случае метод должен использовать ключевое слово throws, чтобы сообщить вызывающему о проверяемых исключениях, которые могут быть сгенерированы из метода. Непроверяемые исключения не требуется обрабатывать в программе или упоминать их в блоке throws метода.
  2. Exception – это суперкласс всех проверяемых исключений, тогда как RuntimeException – суперкласс всех непроверяемых исключений. Обратите внимание, что RuntimeException является подклассом Exception.
  3. Проверяемые исключения – это сценарии ошибок, которые требуется обрабатывать в коде, в противном случае возникнет ошибка времени компиляции. Например, если использовать FileReader для чтения файла, он генерирует исключение FileNotFoundException, и мы должны перехватить его в блоке try-catch или снова сгенерировать его для вызывающего метода. Непроверяемые исключения в основном вызваны низким качеством программирования, например, NullPointerException при вызове метода по ссылке на объект без проверки, что он не является null. Например, я могу написать метод для удаления всех гласных из строки. Ответственность за убеждение в том, что строка не является null, лежит на вызывающем. Я могу изменить метод для обработки этих сценариев, но в идеале за это должен отвечать вызывающий.

7. В чем разница между ключевыми словами throw и throws в Java?

Ключевое слово throws используется с сигнатурой метода для объявления исключений, которые может вызвать метод, в то время как ключевое слово throw используется для прерывания потока программы и передачи объекта исключения на выполнение для его обработки.

8. Как написать пользовательские исключения на Java?

Мы можем расширить класс Exception или любой из его подклассов, чтобы создать наш собственный класс исключения. У пользовательского класса исключения могут быть собственные переменные и методы, которые мы можем использовать для передачи кодов ошибок или другой информации, связанной с исключением, обработчику исключений. Простой пример пользовательского исключения приведен ниже.

package com.journaldev.exceptions;

import java.io.IOException;

public class MyException extends IOException {

	private static final long serialVersionUID = 4664456874499611218L;
	
	private String errorCode="Unknown_Exception";
	
	public MyException(String message, String errorCode){
		super(message);
		this.errorCode=errorCode;
	}
	
	public String getErrorCode(){
		return this.errorCode;
	}
	

}

9. Что такое OutOfMemoryError в Java?

OutOfMemoryError в Java является подклассом java.lang.VirtualMachineError, и он выбрасывается JVM, когда заканчивается память кучи. Мы можем исправить эту ошибку, предоставив больше памяти для выполнения приложения Java с помощью параметров java. $>java MyProgram -Xms1024m -Xmx1024m -XX:PermSize=64M -XX:MaxPermSize=256m

10. Какие различные сценарии вызывают “Exception in thread main”?

Некоторые распространенные сценарии исключений главного потока:

  • Exception in thread main java.lang.UnsupportedClassVersionError: Это исключение возникает, когда ваш класс Java скомпилирован из другой версии JDK, и вы пытаетесь запустить его из другой версии Java.
  • Exception in thread main java.lang.NoClassDefFoundError: Есть два варианта этого исключения. Первый – это когда вы указываете полное имя класса с расширением .class. Второй сценарий – когда класс не найден.
  • Exception in thread main java.lang.NoSuchMethodError: main: Это исключение возникает, когда вы пытаетесь запустить класс, у которого отсутствует метод main.
  • Исключение в потоке “main” java.lang.ArithmeticException: Когда исключение выбрасывается из основного метода, оно выводится в консоль. Первая часть объясняет, что исключение выбрасывается из основного метода, вторая часть выводит имя класса исключения, а затем после двоеточия выводится сообщение об исключении.

Узнайте больше об этом на Java Exception in thread main.

11. В чем разница между final, finally и finalize в Java?

final и finally – ключевые слова в Java, тогда как finalize – метод. Ключевое слово final может использоваться с переменными класса, чтобы они не могли быть переопределены, с классом, чтобы предотвратить расширение классами, и с методами, чтобы предотвратить переопределение подклассами. Ключевое слово finally используется с блоком try-catch для выполнения операторов, которые всегда будут выполняться даже в случае возникновения исключения; обычно finally используется для закрытия ресурсов. Метод finalize() выполняется сборщиком мусора перед уничтожением объекта; это отличный способ убедиться, что все глобальные ресурсы закрыты. Из этих трех только finally связан с обработкой исключений в Java.

12. Что происходит, когда метод main генерирует исключение?

Когда метод main() генерирует исключение, Java Runtime завершает программу и выводит сообщение об исключении и стек вызовов в системной консоли.

13. Можем ли мы иметь пустой блок catch?

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

14. Предоставьте некоторые лучшие практики обработки исключений в Java?

Некоторые из лучших практик, связанных с обработкой исключений в Java, включают:

  • Использование конкретных исключений для упрощения отладки.
  • Выбрасывайте исключения рано (Fail-Fast) в программе.
  • Ловите исключения поздно в программе, позвольте вызывающему обрабатывать исключение.
  • Используйте функцию ARM в Java 7, чтобы убедиться, что ресурсы закрываются, или используйте блок finally для их правильного закрытия.
  • Всегда регистрируйте сообщения об исключениях для отладки.
  • Используйте блок multi-catch для более чистого закрытия.
  • Используйте пользовательские исключения для генерации одного типа исключения из API вашего приложения.
  • Следуйте соглашению о наименовании, всегда заканчивайте с Exception.
  • Документируйте исключения, выбрасываемые методом, используя @throws в javadoc.
  • Исключения затратны, поэтому выбрасывайте их только в том случае, если это имеет смысл. В противном случае вы можете их перехватить и предоставить пустой или нулевой ответ.

Узнайте больше о них подробно на Лучшие практики обработки исключений в Java.

15. В чем проблема с программами ниже и как мы можем ее исправить?

В этом разделе мы рассмотрим некоторые вопросы программирования, связанные с исключениями Java.

  1. В чем проблема с нижеприведенной программой?

    package com.journaldev.exceptions;
    
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class TestException {
    
    	public static void main(String[] args) {
    		try {
    			testExceptions();
    		} catch (FileNotFoundException | IOException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	
    	
    	public static void testExceptions() throws IOException, FileNotFoundException{
    		
    	}
    }
    

    Вышеуказанная программа не скомпилируется, и вы получите сообщение об ошибке “Исключение FileNotFoundException уже перехвачено альтернативным IOException”. Это потому, что FileNotFoundException является подклассом IOException, есть два способа решить эту проблему. Первый способ – использовать один блок catch для обоих исключений.

    		try {
    			testExceptions();
    		}catch(FileNotFoundException e){
    			e.printStackTrace();
    		}catch (IOException  e) {
    			e.printStackTrace();
    		}
    

    Другой способ – удалить FileNotFoundException из мульти-блока catch.

    		try {
    			testExceptions();
    		}catch (IOException  e) {
    			e.printStackTrace();
    		}
    

    Вы можете выбрать любой из этих подходов в зависимости от вашего кода блока catch.

  2. В чем проблема с программой ниже?

    package com.journaldev.exceptions;
    
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    import javax.xml.bind.JAXBException;
    
    public class TestException1 {
    
    	public static void main(String[] args) {
    			try {
    				go();
    			} catch (IOException e) {
    				e.printStackTrace();
    			} catch (FileNotFoundException e) {
    				e.printStackTrace();
    			} catch (JAXBException e) {
    				e.printStackTrace();
    			}
    	}
    
    	public static void go() throws IOException, JAXBException, FileNotFoundException{
    		
    	}
    }
    

    Программа не скомпилируется, потому что FileNotFoundException является подклассом IOException, поэтому блок перехвата FileNotFoundException недостижим, и вы получите сообщение об ошибке “Недостижимый блок перехвата для FileNotFoundException. Он уже обработан блоком перехвата для IOException”. Вам нужно изменить порядок блоков перехвата, чтобы исправить эту проблему.

    			try {
    				go();
    			} catch (FileNotFoundException e) {
    				e.printStackTrace();
    			} catch (IOException e) {
    				e.printStackTrace();
    			} catch (JAXBException e) {
    				e.printStackTrace();
    			}
    

    Обратите внимание, что JAXBException не связан с IOException или FileNotFoundException и может быть помещен в любое место в иерархии блока перехвата исключений выше.

  3. В чем проблема с нижеприведенной программой?

    package com.journaldev.exceptions;
    
    import java.io.IOException;
    
    import javax.xml.bind.JAXBException;
    
    public class TestException2 {
    
    	public static void main(String[] args) {
    		try {
    			foo();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}catch(JAXBException e){
    			e.printStackTrace();
    		}catch(NullPointerException e){
    			e.printStackTrace();
    		}catch(Exception e){
    			e.printStackTrace();
    		}
    	}
    
    	public static void foo() throws IOException{
    		
    	}
    }
    

    Программа не скомпилируется, потому что JAXBException является проверяемым исключением, и метод foo() должен выбрасывать это исключение для перехвата в вызывающем методе. Вы получите сообщение об ошибке “Недостижимый блок catch для JAXBException. Это исключение никогда не выбрасывается из тела оператора try”. Чтобы решить эту проблему, вам нужно удалить блок catch для JAXBException. Обратите внимание, что перехват NullPointerException допустим, потому что это непроверяемое исключение.

  4. В чем проблема с программой ниже?

    package com.journaldev.exceptions;
    
    public class TestException3 {
    
    	public static void main(String[] args) {
    		try{
    		bar();
    		}catch(NullPointerException e){
    			e.printStackTrace();
    		}catch(Exception e){
    			e.printStackTrace();
    		}
    		
    		foo();
    	}
    
    	public static void bar(){
    		
    	}
    	
    	public static void foo() throws NullPointerException{
    		
    	}
    }
    

    Это ловкий вопрос, в коде нет проблем, и он будет успешно компилироваться. Мы всегда можем перехватывать исключение Exception или любое непроверяемое исключение, даже если оно не указано в списке исключений throws метода. Аналогично, если метод (foo) объявляет непроверяемое исключение в списке исключений throws, необязательно обрабатывать его в программе.

  5. Какова проблема с программой ниже?

    package com.journaldev.exceptions;
    
    import java.io.IOException;
    
    public class TestException4 {
    
    	public void start() throws IOException{		
    	}
    	
    	public void foo() throws NullPointerException{
    		
    	}
    }
    
    class TestException5 extends TestException4{
    	
    	public void start() throws Exception{
    	}
    	
    	public void foo() throws RuntimeException{
    		
    	}
    }
    

    Приведенная выше программа не будет компилироваться, потому что сигнатура метода start() в подклассе отличается от суперкласса. Чтобы исправить эту проблему, мы можем либо изменить сигнатуру метода в подклассе точно такой же, как в суперклассе, либо мы можем удалить клавишу throws из метода подкласса, как показано ниже.

    @Override
    	public void start(){
    	}
    
  6. В чем проблема с нижеприведенной программой?

    package com.journaldev.exceptions;
    
    import java.io.IOException;
    
    import javax.xml.bind.JAXBException;
    
    public class TestException6 {
    
    	public static void main(String[] args) {
    		try {
    			foo();
    		} catch (IOException | JAXBException e) {
    			e = new Exception("");
    			e.printStackTrace();
    		}catch(Exception e){
    			e = new Exception("");
    			e.printStackTrace();
    		}
    	}
    
    	public static void foo() throws IOException, JAXBException{
    		
    	}
    }
    

    Приведенная выше программа не будет компилироваться, потому что объект исключения в блоке множественного перехвата является финальным, и мы не можем изменить его значение. Вы получите ошибку времени компиляции “Параметр e блока множественного перехвата не может быть присвоен”. Чтобы решить эту ошибку, мы должны удалить присвоение “e” новому объекту исключения. Узнайте больше на Блок множественного перехвата Java 7.

Вот все вопросы для собеседования по исключениям в Java, надеюсь, они вам понравились. Я буду добавлять еще в список в будущем, убедитесь, что закладываете его для будущего использования.

Source:
https://www.digitalocean.com/community/tutorials/java-exception-interview-questions-and-answers