throw и throws
Ключевые слова throw и throws в Java похожи, но выполняют разные функции:
``throw`` — оператор, который явно выбрасывает объект-исключение из кода.
``throws`` — модификатор сигнатуры метода, который объявляет, какие checked-исключения метод может пробросить наружу.
Различие checked / unchecked важно: компилятор требует обрабатывать или объявлять через throws
только checked-исключения (наследники Exception, кроме RuntimeException). Unchecked
(RuntimeException и его потомки) можно бросать без всяких объявлений.
Синтаксис
// throw — выбросить исключение
throw new IllegalArgumentException("pin должен быть >= 0");
// throws — объявить в сигнатуре
public void readConfig(String path) throws IOException {
// ...
}
Пример 1. throw для проверки аргументов
public class ValidatePin {
static void setPin(int pin) {
if (pin < 0 || pin > 53) {
throw new IllegalArgumentException("Недопустимый пин: " + pin);
}
System.out.println("Пин " + pin + " настроен");
}
public static void main(String[] args) {
setPin(13);
try {
setPin(99);
} catch (IllegalArgumentException e) {
System.out.println("Поймано: " + e.getMessage());
}
}
}
Output:
Пин 13 настроен
Поймано: Недопустимый пин: 99
Пример 2. throws в сигнатуре метода
import java.io.IOException;
public class ThrowsExample {
static String readSensorName() throws IOException {
throw new IOException("Датчик не отвечает");
}
public static void main(String[] args) {
try {
String name = readSensorName();
System.out.println(name);
} catch (IOException e) {
System.out.println("Ошибка I/O: " + e.getMessage());
}
}
}
Output:
Ошибка I/O: Датчик не отвечает
Пример 3. Несколько типов в throws
import java.io.IOException;
public class MultipleThrows {
static void process(String input) throws IOException, NumberFormatException {
if (input == null) {
throw new IOException("Нет данных от Arduino");
}
int v = Integer.parseInt(input);
System.out.println("Значение: " + v);
}
public static void main(String[] args) {
try {
process("42");
process("abc");
} catch (IOException e) {
System.out.println("I/O: " + e.getMessage());
} catch (NumberFormatException e) {
System.out.println("Парсинг: " + e.getMessage());
}
}
}
Output:
Значение: 42
Парсинг: For input string: "abc"
Пример 4. Проброс исключения вызывающему
public class Rethrow {
static int parsePositive(String s) {
int v = Integer.parseInt(s);
if (v <= 0) {
throw new IllegalArgumentException("Ожидалось > 0, получили " + v);
}
return v;
}
public static void main(String[] args) {
try {
System.out.println(parsePositive("0"));
} catch (IllegalArgumentException e) {
System.out.println("Главный поймал: " + e.getMessage());
}
}
}
Output:
Главный поймал: Ожидалось > 0, получили 0
Пример 5. Цепочка исключений (causes)
public class ChainedException {
static void loadConfig() {
try {
int v = Integer.parseInt("not-a-number");
} catch (NumberFormatException e) {
throw new IllegalStateException("Конфиг повреждён", e);
}
}
public static void main(String[] args) {
try {
loadConfig();
} catch (IllegalStateException e) {
System.out.println("Главное: " + e.getMessage());
System.out.println("Причина: " + e.getCause());
}
}
}
Output:
Главное: Конфиг повреждён
Причина: java.lang.NumberFormatException: For input string: "not-a-number"
Подводные камни
Предупреждение
Checked-исключения нужно либо ловить, либо объявлять — иначе ошибка компиляции.
Unchecked можно не объявлять в
throws, но добавить можно для документации.``throw null`` выбросит
NullPointerException, а не «ничего».Переопределяемый метод не может объявлять более широкий ``throws``, чем у родителя.
Не оборачивайте исключения без сохранения cause — теряете оригинальный stack trace.
См. также
Примечание
Материал подготовлен на основе официальной документации Oracle Java Tutorials — Throwing Exceptions (Oracle Free Documentation License). Текст переведён и переработан, примеры кода написаны заново.