I am kind of new to java so pardon this rather simple question, I guess. This method will count how many digits are there on a POSITIVE integer only. So it needs to throw an error to the caller. How do I do so when the input is negative, I throw an error and exit the method without returning anything?
public static int countDigits(int n)
{
if (n<0)
{
System.out.println("Error! Input should be positive");
return -1;
}
int result = 0;
while ((n/10) != 0)
{
result++;
n/=10;
}
return result + 1;
}
Tobias
7,6731 gold badge27 silver badges44 bronze badges
asked Sep 10, 2015 at 16:05
1
You’re not throwing an error here; you’re displaying an error message and returning a sentinel value of -1
.
If you want to throw an error, you have to use the throw
keyword, followed by an appropriate Exception
.
public static int countDigits(int n) {
if (n < 0) {
throw new IllegalArgumentException("Input should be positive");
}
int result = 0;
while ((n / 10) != 0) {
result++;
n /= 10;
}
return result + 1;
}
The Java Trails on throwing exceptions will provide you with invaluable insights into what different kinds of exceptions there are. Above, IllegalArgumentException
is considered a runtime exception, so something that is calling this method won’t be forced to catch its exception.
answered Sep 10, 2015 at 16:08
MakotoMakoto
103k27 gold badges188 silver badges224 bronze badges
You need to throw an exception.
if (n < 0) {
throw new Exception("n must be a positive integer");
}
You can make life easier for callers of your method by using a more specific exception type. In this case, IllegalArgumentException
would be appropriate.
if (n < 0) {
throw new IllegalArgumentException("n must be a positive integer");
}
Different types of error can be handled separately in a try-catch.
I would take a look at Guava’s preconditions to do this in a cleaner fashion.
answered Sep 10, 2015 at 16:08
sdgfsdhsdgfsdh
31.7k23 gold badges121 silver badges226 bronze badges
1
It depends. If the caller doesn’t handle an eventual failure, then I’d throw an exception. But it is much simpler to return a value like -1 and then check the result after the call. Exceptions are slow.
answered Sep 10, 2015 at 16:11
5
Наконец, я нашел причину.
Сначала я замечаю, что НЕ всегда это исключение приходит
в той же точке.
Иногда был java.io.IOException: неверный аргумент в java.io.FileOutputStream.close0 (собственный метод) в java.io.FileOutputStream.close(FileOutputStream.java:279) ^^^^^
и иногда был
java.io.IOException: Invalid argument
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:260)
Поэтому проблема НЕ является проблемой Java. Даже проблема NFS.
Проблема — базовый тип файловой системы, который является DRBD
файловой системы.
Тестирование в оболочке для записи по узлам работает, если вы пишете небольшую
файл. То есть:
на установленном nfs node
cd /tmp
date > /shared/path-to-some-not-mounted-dir/today
will work
но
cat myBigFile > /shared/path-to-some-not-mounted-dir/today
выдаст следующую ошибку
cat: write error: Invalid argument
Поэтому решение заключается в использовании другого типа файловой системы, например gfs.
Ошибка при получении соединения: java.net.SocketException: Неверный аргумент Исключение в потоке «Thread-698» java.lang.RuntimeException: Не удалось установить ввод/вывод в Handin2.ConnectionHandlerImpl.run(ConnectionHandlerImpl.java:124) в java.lang. Thread.run(Thread.java:722)
Я много искал это исключение. Везде вроде бы вывод, что если компилировать с опцией JVM -Djava.net.preferIPv4Stack=true
это решит проблему. Хотя это не для меня. Я запускаю IntelliJ и пытаюсь реализовать систему Chord с сокетами и потоками. Именно здесь перехватывается и выбрасывается упомянутое выше исключение:
if(this.remote == null || this.node == null) {
throw new RuntimeException("Connection handler has not been properly "
+ "initalialized");
}
try{
if(this.out == null) {
this.out = new ObjectOutputStream(remote.getOutputStream());
}
if(this.in == null) {
this.in = new ObjectInputStream(remote.getInputStream());
}
} catch(IOException e) {
System.out.println("Trying to make input/output for remote " + remote);
System.err.println(node.getKey()/Constants.NORMALIZE_KEY+": Error receiving connection: " + e.toString());
return false;
}
Я не знаю, нужны ли дополнительные фрагменты кода, чтобы помочь, но я просто теряюсь в этом исключении, поскольку решения при поиске совсем не помогают.
Любые намеки на то, что вызывает эту ошибку? Исключение сокета перехватывается данным блоком try-catch как особый случай исключения ввода-вывода.
Перечень наиболее часто встречающихся исключений (исключительных ситуаций, ошибок) в языке программирования java с расшифровкой их значения.
Содержание
- ArithmeticException
- ArrayIndexOutOfBoundsException
- ArrayStoreException
- ClassCastException
- ConcurrentModificationException
- EmptyStackException
- IllegalArgumentException
- IllegalMonitorStateException
- IllegalStateException
- IllegalThreadStateException
- IndexOutOfBoundsException
- MissingResourceException
- NegativeArraySizeException
- NoSuchElementException
- NullPointerException
- NumberFormatException
- SecurityException
- StringIndexOutOfBoundsException
- UndeclaredThrowableException
- UnsupportedOperationException
ArithmeticException
Возникла исключительная ситуация, связанная с ошибкой при выполнении арифметического вычисления (например, с попыткой целочисленного деления на нуль). Класс ArithmeticalException унаследован от RuntimeException.
ArrayIndexOutOfBoundsException
Задано значение индекса массива, не принадлежащее допустимому диапазону. Имеется дополнительный конструктор, принимающий в качестве параметра ошибочное значение индекса и включающий его в текст описательного сообщения. Класс ArrayIndexOutOfBoundsException унаследован от IndexOutOfBoundException
ArrayStoreException
Предпринята попытка сохранения в массиве объекта недопустимого типа. Возникает, если попытаться записать в ячейку массива ссылку на объект неправильного типа.
Класс ArrayStoreException унаследован от RuntimeException.
ClassCastException
Выполнена неверная операция преобразования типов (ошибка приведения типов).
Класс ClassCastException унаследован от RuntimeException.
ConcurrentModificationException
Осуществлена попытка изменения объекта конкурирующим потоком вычислений (thread) с нарушением контракта класса (тип определен в пакете jav.util).
Также исключение может происходить при работе с коллекциями при обычной однопоточной работе. ConcurrentModificationException возникает когда коллекция модифицируется «одновременно» с проходом по коллекции итератором любыми средствами кроме самого итератора.
Класс ConcurrentModificationException унаследован от RuntimeException.
EmptyStackException
Возникает при попытке извлечения объекта из пустого стека. Тип обладает только конструктором без параметров, поскольку причина ситуации очевидна без дополнительных разъяснений (тип определен в пакете java.util).
Класс EmptyStackExceptionунаследован от RuntimeException.
IllegalArgumentException
Методу передано неверное значение аргумента (например, отрицательное, когда метод предполагает задание положительных значений).
Класс IllegalArgumentExceptionунаследован от RuntimeException.
IllegalMonitorStateException
Выполнено обращение к методу wait, notifyAll или notify объекта, когда текущий поток вычислений не обладает блокировкой (lock) этого объекта.
Класс IllegalMonitorStateException унаследован от RuntimeException.
IllegalStateException
Предпринята попытка выполнения операции в то время, когда объект не находится в соответствующем состоянии (например при регистрации или удалении ловушки события закрытия исполняющей системы (shutdown hook) после начала процедуры закрытия).
Класс IllegalStateExceptionунаследован от RuntimeException.
IllegalThreadStateException
Предпринята попытка выполнения операции в то время, когда объект потока вычислений не находится в соответствующем состоянии (например, вызван метод start для потока, который уже приступил к работе).
Класс IllegalThreadStateException унаследован от IllegalArgumentException
IndexOutOfBoundsException
Задано значение индекса массива или содержимого строки типа String, не принадлежащее допустимому диапазону.
Класс IndexOutOfBoundsException унаследован от RuntimeException
MissingResourceException
Не найден требуемый ресурс или пакет ресурсов (resource bundle). Единственный конструктор типа предусматривает задание трех аргументов: строки описательного сообщения, наименования класса ресурсов и объекта ключа, отвечающего отсутствующему ресурсу. Для получения строк наименования класса и ключа применяются методы detClassName и getKey соответственно (тип определен в пакете java.util).
Класс MissingResourceExceptionунаследован от RuntimeException.
NegativeArraySizeException
Предпринята попытка создания массива с размером, значение которого задано отрицательным числом.
Класс NegativeArraySizeException унаследован от RuntimeException.
NoSuchElementException
Операция поиска элемента в объекте одного из контейнерных классов завершилась неудачей (тип определен в пакете java.util).
Класс NoSuchElementException унаследован от RuntimeException.
NullPointerException
Возникает при попытке обращения к полю, методу или объекту по ссылке, равной null. Также исключение выбрасывается, когда метод, не допускающий передачи аргумента null, был вызван с заданием значения null. В последнем случае может быть сгенерировано и исключение типа IllegalArgumentException.
Класс NullPointerException унаследован от RuntimeException.
NumberFormatException
Строка, которая, как предполагалось должна содержать представление числа, не отвечает этому требованию. Исключение выбрасывается такими методами, как, например, Integer.parseInt.
Класс NumberFormatException унаследован от IllegalArgumentException.
SecurityException
Предпринята попытка выполнения операции, запрещенной системой обеспечения безопасности в соответствии с действующей политикой безопасности.
Класс SecurityException унаследован от RuntimeException.
StringIndexOutOfBoundsException
Задано значение индекса содержимого строки типа String, не принадлежащее допустимому диапазону. Имеется дополнительный конструктор, принимающий в качестве параметра ошибочное значение индекса и включающий его в текст описательного сообщения.
Класс StringIndexOutOfBoundsException унаследован от IndexOutOfBoundsException.
UndeclaredThrowableException
Выбрасывается при обращении к методу целевого объекта посредством объекта рефлективного класса Proxy, если метод invoke объекта InvocationHandler генерирует объявляемое исключение, которое не допускает присваивания ни одному из типов исключений, упомянутых в предложении throws метода целевого объекта. Рассматриваемое исключение содержит ссылку на исключение, генерируемое методом invoke, которое может быть получено с помощью метода getUndeclaredThrowable. Класс исключений UndeclaredThrowableException поддерживает два конструктора: оба принимают в качестве параметров ссылку на объект Throwable, а один из них, помимо того, строку описания (тип определен в пакете java.lang.reflect).
Класс UndeclaredThrowableException унаследован от RuntimeException.
UnsupportedOperationException
Предпринята попытка выполнения операции над объектом, который ее не поддерживает (например, модификация объекта, обозначенного признаком «только для чтения»). используется также классами коллекций из состава пакета java.util как реакция на вызов методов производного класса, реализация которых не обязательна.
Класс UnsupportedOperationException унаследован от RuntimeException.
Смотрите также: Методы обработки исключений в java
An unexpected event occurring during the program execution is called an Exception. This can be caused due to several factors like invalid user input, network failure, memory limitations, trying to open a file that does not exist, etc.
If an exception occurs, an Exception object is generated, containing the Exception’s whereabouts, name, and type. This must be handled by the program. If not handled, it gets past to the default Exception handler, resulting in an abnormal termination of the program.
IllegalArgumentException
The IllegalArgumentException is a subclass of java.lang.RuntimeException. RuntimeException, as the name suggests, occurs when the program is running. Hence, it is not checked at compile-time.
IllegalArgumentException Cause
When a method is passed illegal or unsuitable arguments, an IllegalArgumentException is thrown.
The program below has a separate thread that takes a pause and then tries to print a sentence. This pause is achieved using the sleep method that accepts the pause time in milliseconds. Java clearly defines that this time must be non-negative. Let us see the result of passing in a negative value.
Program to Demonstrate IllegalArgumentException:
Java
public
class
Main {
public
static
void
main(String[] args)
{
Thread t1 =
new
Thread(
new
Runnable() {
public
void
run()
{
try
{
Thread.sleep(-
10
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
System.out.println(
"Welcome To GeeksforGeeks!"
);
}
});
t1.setName(
"Test Thread"
);
t1.start();
}
}
Output:
Exception in thread "Test Thread" java.lang.IllegalArgumentException: timeout value is negative at java.base/java.lang.Thread.sleep(Native Method) at Main$1.run(Main.java:19) at java.base/java.lang.Thread.run(Thread.java:834)
In the above case, the Exception was not caught. Hence, the program terminated abruptly and the Stack Trace that was generated got printed.
Diagnostics & Solution
The Stack Trace is the ultimate resource for investigating the root cause of Exception issues. The above Stack Trace can be broken down as follows.
Part 1: This part names the Thread in which the Exception occurred. In our case, the Exception occurred in the “Test Thread”.
Part 2: This part names class of the Exception. An Exception object of the “java.lang.IllegalArgumentException” class is made in the above example.
Part 3: This part states the reason behind the occurrence of the Exception. In the above example, the Exception occurred because an illegal negative timeout value was used.
Part 4: This part lists all the method invocations leading up to the Exception occurrence, beginning with the method where the Exception first occurred. In the above example, the Exception first occurred at Thread.sleep() method.
From the above analysis, we reach the conclusion that an IllegalArgumentException occurred at the Thread.sleep() method because it was passed a negative timeout value. This information is sufficient for resolving the issue. Let us accordingly make changes in the above code and pass a positive timeout value.
Below is the implementation of the problem statement:
Java
public
class
Main {
public
static
void
main(String[] args)
{
Thread t1 =
new
Thread(
new
Runnable() {
public
void
run()
{
try
{
Thread.sleep(
10
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
System.out.println(
"Welcome To GeeksforGeeks!"
);
}
});
t1.setName(
"Test Thread"
);
t1.start();
}
}
Output
Welcome To GeeksforGeeks!
An unexpected event occurring during the program execution is called an Exception. This can be caused due to several factors like invalid user input, network failure, memory limitations, trying to open a file that does not exist, etc.
If an exception occurs, an Exception object is generated, containing the Exception’s whereabouts, name, and type. This must be handled by the program. If not handled, it gets past to the default Exception handler, resulting in an abnormal termination of the program.
IllegalArgumentException
The IllegalArgumentException is a subclass of java.lang.RuntimeException. RuntimeException, as the name suggests, occurs when the program is running. Hence, it is not checked at compile-time.
IllegalArgumentException Cause
When a method is passed illegal or unsuitable arguments, an IllegalArgumentException is thrown.
The program below has a separate thread that takes a pause and then tries to print a sentence. This pause is achieved using the sleep method that accepts the pause time in milliseconds. Java clearly defines that this time must be non-negative. Let us see the result of passing in a negative value.
Program to Demonstrate IllegalArgumentException:
Java
public
class
Main {
public
static
void
main(String[] args)
{
Thread t1 =
new
Thread(
new
Runnable() {
public
void
run()
{
try
{
Thread.sleep(-
10
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
System.out.println(
"Welcome To GeeksforGeeks!"
);
}
});
t1.setName(
"Test Thread"
);
t1.start();
}
}
Output:
Exception in thread "Test Thread" java.lang.IllegalArgumentException: timeout value is negative at java.base/java.lang.Thread.sleep(Native Method) at Main$1.run(Main.java:19) at java.base/java.lang.Thread.run(Thread.java:834)
In the above case, the Exception was not caught. Hence, the program terminated abruptly and the Stack Trace that was generated got printed.
Diagnostics & Solution
The Stack Trace is the ultimate resource for investigating the root cause of Exception issues. The above Stack Trace can be broken down as follows.
Part 1: This part names the Thread in which the Exception occurred. In our case, the Exception occurred in the “Test Thread”.
Part 2: This part names class of the Exception. An Exception object of the “java.lang.IllegalArgumentException” class is made in the above example.
Part 3: This part states the reason behind the occurrence of the Exception. In the above example, the Exception occurred because an illegal negative timeout value was used.
Part 4: This part lists all the method invocations leading up to the Exception occurrence, beginning with the method where the Exception first occurred. In the above example, the Exception first occurred at Thread.sleep() method.
From the above analysis, we reach the conclusion that an IllegalArgumentException occurred at the Thread.sleep() method because it was passed a negative timeout value. This information is sufficient for resolving the issue. Let us accordingly make changes in the above code and pass a positive timeout value.
Below is the implementation of the problem statement:
Java
public
class
Main {
public
static
void
main(String[] args)
{
Thread t1 =
new
Thread(
new
Runnable() {
public
void
run()
{
try
{
Thread.sleep(
10
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
System.out.println(
"Welcome To GeeksforGeeks!"
);
}
});
t1.setName(
"Test Thread"
);
t1.start();
}
}
Output
Welcome To GeeksforGeeks!
Исключения
try
Оператор throw
Оператор throws
Оператор finally
Встроенные исключения Java
Создание собственных классов исключений
Исключение — это нештатная ситуация, ошибка во время выполнения программы. Самый простой пример — деление на ноль. Можно вручную отслеживать возникновение подобных ошибок, а можно воспользоваться специальным механизмом исключений, который упрощает создание больших надёжных программ, уменьшает объём необходимого кода и повышает уверенность в том, что в приложении не будет необработанной ошибки.
В методе, в котором происходит ошибка, создаётся и передаётся специальный объект. Метод может либо обработать исключение самостоятельно, либо пропустить его. В любом случае исключение ловится и обрабатывается. Исключение может появиться благодаря самой системе, либо вы сами можете создать его вручную. Системные исключения возникают при неправильном использовании языка Java или запрещённых приёмов доступа к системе. Ваши собственные исключения обрабатывают специфические ошибки вашей программы.
Вернёмся к примеру с делением. Деление на нуль может предотвратить проверкой соответствующего условия. Но что делать, если знаменатель оказался нулём? Возможно, в контексте вашей задачи известно, как следует поступить в такой ситуации. Но, если нулевой знаменатель возник неожиданно, деление в принципе невозможно, и тогда необходимо возбудить исключение, а не продолжать исполнение программы.
Существует пять ключевых слов, используемых в исключениях: try, catch, throw, throws, finally. Порядок обработки исключений следующий.
Операторы программы, которые вы хотите отслеживать, помещаются в блок try. Если исключение произошло, то оно создаётся и передаётся дальше. Ваш код может перехватить исключение при помощи блока catch и обработать его. Системные исключения автоматически передаются самой системой. Чтобы передать исключение вручную, используется throw. Любое исключение, созданное и передаваемое внутри метода, должно быть указано в его интерфейсе ключевым словом throws. Любой код, который следует выполнить обязательно после завершения блока try, помещается в блок finally
Схематически код выглядит так:
try {
// блок кода, где отслеживаются ошибки
}
catch (тип_исключения_1 exceptionObject) {
// обрабатываем ошибку
}
catch (тип_исключения_2 exceptionObject) {
// обрабатываем ошибку
}
finally {
// код, который нужно выполнить после завершения блока try
}
Существует специальный класс для исключений Trowable. В него входят два класса Exception и Error.
Класс Exception используется для обработки исключений вашей программой. Вы можете наследоваться от него для создания собственных типов исключений. Для распространённых ошибок уже существует класс RuntimeException, который может обрабатывать деление на ноль или определять ошибочную индексацию массива.
Класс Error служит для обработки ошибок в самом языке Java и на практике вам не придётся иметь с ним дело.
Прежде чем научиться обрабатывать исключения, нам (как и нормальному любопытному коту) хочется посмотреть, а что происходит, если ошибку не обработать. Давайте разделим число котов в вашей квартире на ноль, хотя мы и знаем, что котов на ноль делить нельзя!
int catNumber;
int zero;
catNumber = 1; // у меня один кот
zero = 0; // ноль, он и в Африке ноль
int result = catNumber / zero;
Я поместил код в обработчик щелчка кнопки. Когда система времени выполнения Java обнаруживает попытку деления на ноль, она создаёт объект исключения и передаёт его. Да вот незадача, никто не перехватывает его, хотя это должны были сделать вы. Видя вашу бездеятельность, объект перехватывает стандартный системный обработчик Java, который отличается вредных характером. Он останавливает вашу программу и выводит сообщение об ошибке, которое можно увидеть в журнале LogCat:
Caused by: java.lang.ArithmeticException: divide by zero at ru.alexanderklimov.test.MainActivity.onClick(MainActivity.java:79)
Как видно, созданный объект исключения принадлежит к классу ArithmeticException, далее системный обработчик любезно вывел краткое описание ошибки и место возникновения.
Вряд ли пользователи вашей программы будут довольны, если вы так и оставите обработку ошибки системе. Если программа будет завершаться с такой ошибкой, то скорее всего вашу программу просто удалят. Посмотрим, как мы можем исправить ситуацию.
Поместим проблемный код в блок try, а в блоке catch обработаем исключение.
int catNumber;
int zero;
try { // мониторим код
catNumber = 1; // у меня один кот
zero = 0; // ноль, он и в Африке ноль
int result = catNumber / zero;
Toast.makeText(this, "Не увидите это сообщение!", Toast.LENGTH_LONG).show();
} catch (ArithmeticException e) {
Toast.makeText(this, "Нельзя котов делить на ноль!", Toast.LENGTH_LONG).show();
}
Toast.makeText(this, "Жизнь продолжается", Toast.LENGTH_LONG).show();
Теперь программа аварийно не закрывается, так как мы обрабатываем ситуацию с делением на ноль.
В данном случае мы уже знали, к какому классу принадлежит получаемая ошибка, поэтому в блоке catch сразу указали конкретный тип. Обратите внимание, что последний оператор в блоке try не срабатывает, так как ошибка происходит раньше строчкой выше. Далее выполнение передаётся в блок catch, далее выполняются следующие операторы в обычном порядке.
Операторы try и catch работают совместно в паре. Хотя возможны ситуации, когда catch может обрабатывать несколько вложенных операторов try.
Если вы хотите увидеть описание ошибки, то параметр e и поможет увидеть ёго.
catch (ArithmeticException e) {
Toast.makeText(this, e + ": Нельзя котов делить на ноль!", Toast.LENGTH_LONG).show();
}
По умолчанию, класс Trowable, к которому относится ArithmeticException возвращает строку, содержащую описание исключения. Но вы можете и явно указать метод e.toString.
Несколько исключений
Фрагмент кода может содержать несколько проблемных мест. Например, кроме деления на ноль, возможна ошибка индексации массива. В таком случае вам нужно создать два или более операторов catch для каждого типа исключения. Причём они проверяются по порядку. Если исключение будет обнаружено у первого блока обработки, то он будет выполнен, а остальные проверки пропускаются и выполнение программы продолжается с места, который следует за блоком try/catch.
int catNumber;
int zero;
try { // мониторим код
catNumber = 1; // у меня один кот
zero = 1; // ноль, он и в Африке ноль
int result = catNumber / zero;
// Создадим массив из трёх котов
String[] catNames = {"Васька", "Барсик", "Мурзик"};
catNames[3] = "Рыжик";
Toast.makeText(this, "Не увидите это сообщение!", Toast.LENGTH_LONG).show();
} catch (ArithmeticException e) {
Toast.makeText(this, e.toString() + ": Нельзя котов делить на ноль!", Toast.LENGTH_LONG).show();
}
catch (ArrayIndexOutOfBoundsException e) {
Toast.makeText(this, "Ошибка: " + e.toString(), Toast.LENGTH_LONG).show();
}
Toast.makeText(this, "Жизнь продолжается", Toast.LENGTH_LONG).show();
В примере мы добавили массив с тремя элементами, но обращаемся к четвёртому элементу, так как забыли, что отсчёт у массива начинается с нуля. Если оставить значение переменной zero равным нулю, то сработает обработка первого исключения деления на ноль, и мы даже не узнаем о существовании второй ошибки. Но допустим, что в результате каких-то вычислений значение переменной стало равно единице. Тогда наше исключение ArithmeticException не сработает. Но сработает новое добавленное исключение ArrayIndexOutOfBoundsException. А дальше всё пойдёт как раньше.
Тут всегда нужно помнить одну особенность. При использовании множественных операторов catch обработчики подклассов исключений должные находиться выше, чем обработчики их суперклассов. Иначе, суперкласс будет перехватывать все исключения, имея большую область перехвата. Иными словами, Exception не должен находиться выше ArithmeticException и ArrayIndexOutOfBoundsException. К счастью, среда разработки сама замечает непорядок и предупреждает вас, что такой порядок не годится. Увидев такую ошибку, попробуйте перенести блок обработки исключений ниже.
Вложенные операторы try
Операторы try могут быть вложенными. Если вложенный оператор try не имеет своего обработчика catch для определения исключения, то идёт поиск обработчика catch у внешнего блока try и т.д. Если подходящий catch не будет найден, то исключение обработает сама система (что никуда не годится).
Оператор throw
Часть исключений может обрабатывать сама система. Но можно создать собственные исключения при помощи оператора throw. Код выглядит так:
throw экземпляр_Throwable
Вам нужно создать экземпляр класса Throwable или его наследников. Получить объект класса Throwable можно в операторе catch или стандартным способом через оператор new.
Мы могли бы написать такой код для кнопки:
Cat cat;
public void onClick(View view) {
if(cat == null){
throw new NullPointerException("Котик не инициализирован");
}
}
Мы объявили объект класса Cat, но забыли его проинициализировать, например, в onCreate(). Теперь нажатие кнопки вызовет исключение, которое обработает система, а в логах мы можем прочитать сообщение об ошибке. Возможно, вы захотите использовать другое исключение, например, throw new UnsupportedOperationException(«Котик не инициализирован»);.
В любом случае мы передали обработку ошибки системе. В реальном приложении вам нужно обработать ошибку самостоятельно.
Поток выполнения останавливается непосредственно после оператора throw и другие операторы не выполняются. При этом ищется ближайший блок try/catch соответствующего исключению типа.
Перепишем пример с обработкой ошибки.
public void onClick(View view) {
if (cat == null) {
try {
throw new NullPointerException("Кота не существует");
} catch (NullPointerException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
Мы создали новый объект класса NullPointerException. Многие классы исключений кроме стандартного конструктора по умолчанию с пустыми скобками имеют второй конструктор с строковым параметром, в котором можно разместить подходящую информацию об исключении. Получить текст из него можно через метод getMessage(), что мы и сделали в блоке catch.
Теперь программа не закроется аварийно, а будет просто выводить сообщения в всплывающих Toast.
Оператор throws
Если метод может породить исключение, которое он сам не обрабатывает, он должен задать это поведение так, чтобы вызывающий его код мог позаботиться об этом исключении. Для этого к объявлению метода добавляется конструкция throws, которая перечисляет типы исключений (кроме исключений Error и RuntimeException и их подклассов).
Общая форма объявления метода с оператором throws:
тип имя_метода(список_параметров) throws список_исключений {
// код внутри метода
}
В фрагменте список_исключений можно указать список исключений через запятую.
Создадим метод, который может породить исключение, но не обрабатывает его. А в щелчке кнопки вызовем его.
// Метод без обработки исключения
public void createCat(){
Toast.makeText(this, "Вы создали котёнка", Toast.LENGTH_LONG).show();
throw new NullPointerException("Кота не существует");
}
// Щелчок кнопки
public void onClick(View v) {
createCat();
}
Если вы запустите пример, то получите ошибку. Исправим код.
// Без изменений
public void createCat() throws NullPointerException {
Toast.makeText(this, "Вы создали котёнка", Toast.LENGTH_LONG).show();
throw new NullPointerException("Кота не существует");
}
// Щелчок кнопки
public void onClick(View v) {
try {
createCat();
} catch (NullPointerException e) {
// TODO: handle exception
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
Мы поместили вызов метода в блок try и вызвали блок catch с нужным типом исключения. Теперь ошибки не будет.
Оператор finally
Когда исключение передано, выполнение метода направляется по нелинейному пути. Это может стать источником проблем. Например, при входе метод открывает файл и закрывает при выходе. Чтобы закрытие файла не было пропущено из-за обработки исключения, был предложен механизм finally.
Ключевое слово finally создаёт блок кода, который будет выполнен после завершения блока try/catch, но перед кодом, следующим за ним. Блок будет выполнен, независимо от того, передано исключение или нет. Оператор finally не обязателен, однако каждый оператор try требует наличия либо catch, либо finally.
Существуют несколько готовых системных исключений. Большинство из них являются подклассами типа RuntimeException и их не нужно включать в список throws. Вот небольшой список непроверяемых исключений.
- ArithmeticException — арифметическая ошибка, например, деление на нуль
- ArrayIndexOutOfBoundsException — выход индекса за границу массива
- ArrayStoreException — присваивание элементу массива объекта несовместимого типа
- ClassCastException — неверное приведение
- EnumConstantNotPresentException — попытка использования неопределённого значения перечисления
- IllegalArgumentException — неверный аргумент при вызове метода
- IllegalMonitorStateException — неверная операция мониторинга
- IllegalStateException — некорректное состояние приложения
- IllegalThreadStateException — запрашиваемая операция несовместима с текущим потоком
- IndexOutofBoundsException — тип индекса вышел за допустимые пределы
- NegativeArraySizeException — создан массив отрицательного размера
- NullPointerException — неверное использование пустой ссылки
- NumberFormatException — неверное преобразование строки в числовой формат
- SecurityException — попытка нарушения безопасности
- StringIndexOutOfBounds — попытка использования индекса за пределами строки
- TypeNotPresentException — тип не найден
- UnsupportedOperationException — обнаружена неподдерживаемая операция
Список проверяемых системных исключений, которые можно включать в список throws.
- ClassNotFoundException — класс не найден
- CloneNotSupportedException — попытка клонировать объект, который не реализует интерфейс Cloneable
- IllegalAccessException — запрещен доступ к классу
- InstantiationException — попытка создать объект абстрактного класса или интерфейса
- InterruptedException — поток прерван другим потоком
- NoSuchFieldException — запрашиваемое поле не существует
- NoSuchMethodException — запрашиваемый метод не существует
- ReflectiveOperationException — исключение, связанное с рефлексией
Создание собственных классов исключений
Система не может предусмотреть все исключения, иногда вам придётся создать собственный тип исключения для вашего приложения. Вам нужно наследоваться от Exception (напомню, что этот класс наследуется от Trowable) и переопределить нужные методы класса Throwable. Либо вы можете наследоваться от уже существующего типа, который наиболее близок по логике с вашим исключением.
- final void addSuppressed(Throwable exception) — добавляет исключение в список подавляемых исключений (JDK 7)
- Throwable fillInStackTrace() — возвращает объект класса Throwable, содержащий полную трассировку стека.
- Throwable getCause() — возвращает исключение, лежащее под текущим исключение или null
- String getLocalizedMessage() — возвращает локализованное описание исключения
- String getMessage() — возвращает описание исключения
- StackTraceElement[] getStackTrace() — возвращает массив, содержащий трассировку стека и состояний из элементов класса StackTraceElement
- final Throwable[] getSuppressed() — получает подавленные исключения (JDK 7)
- Throwable initCause(Throwable exception) — ассоциирует исключение с вызывающим исключением. Возвращает ссылку на исключение.
- void printStackTrace() — отображает трассировку стека
- void printStackTrace(PrintStream stream) — посылает трассировку стека в заданный поток
- void printStackTrace(PrintWriter stream) — посылает трассировку стека в заданный поток
- void setStackTrace(StackTraceElement elements[]) — устанавливает трассировку стека для элементов (для специализированных приложений)
- String toString() — возвращает объект класса String, содержащий описание исключения.
Самый простой способ — создать класс с конструктором по умолчанию.
// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.
package ru.alexanderklimov.exception;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void testMethod() throws HungryCatException{
System.out.println("Возбуждаем HungryCatException из метода testMethod()");
throw new HungryCatException(); // конструктор по умолчанию
}
public void onClick(View view) {
try {
testMethod();
} catch (HungryCatException e) {
e.printStackTrace();
System.out.println("Наше исключение перехвачено");
}
}
class HungryCatException extends Exception{
}
}
Мы создали собственный класс HungryCatException, в методе testMethod() его возбуждаем, а по нажатию кнопки вызываем этот метод. В результате наше исключение сработает.
Создать класс исключения с конструктором, который получает аргумент-строку, также просто.
// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.
package ru.alexanderklimov.exception;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void testMethod() throws HungryCatException {
System.out.println("Возбуждаем HungryCatException из метода testMethod()");
throw new HungryCatException(); // конструктор по умолчанию
}
public void testMethod2() throws HungryCatException {
System.out.println("Возбуждаем HungryCatException из метода testMethod2()");
throw new HungryCatException("Создано во втором методе");
}
public void onClick(View view) {
try {
testMethod();
} catch (HungryCatException e) {
e.printStackTrace();
System.out.println("Наше исключение перехвачено");
}
try {
testMethod2();
} catch (HungryCatException e) {
e.printStackTrace();
}
}
class HungryCatException extends Exception {
HungryCatException() {
}
HungryCatException(String msg) {
super(msg);
}
}
}
Ещё вариант. Добавим также метод toString().
class CustomException extends Exception {
String message;
CustomException(String str) {
message = str;
}
public String toString() {
return ("Custom Exception Occurred: " + message);
}
}
// где-то вызываем
try {
throw new CustomException("This is a custom message");
} catch (CustomException e) {
System.out.println(e);
}
Теперь класс содержит два конструктора. Во втором конструкторе используется конструктор родительского класса с аргументом String, вызываемый ключевым словом super.
Перехват произвольных исключений
Можно создать универсальный обработчик, перехватывающий любые типы исключения. Осуществляется это перехватом базового класса всех исключений Exception:
cacth(Exception e) { Log.w("Log", "Перехвачено исключение"); }
Подобная конструкция не упустит ни одного исключения, поэтому её следует размещать в самом конце списка обработчиков, во избежание блокировки следующих за ней обработчиков исключений.
Основные правила обработки исключений
Используйте исключения для того, чтобы:
- обработать ошибку на текущем уровне (избегайте перехватывать исключения, если не знаете, как с ними поступить)
- исправить проблему и снова вызвать метод, возбудивший исключение
- предпринять все необходимые действия и продолжить выполнение без повторного вызова действия
- попытаться найти альтернативный результат вместо того, который должен был бы произвести вызванный метод
- сделать все возможное в текущем контексте и заново возбудить это же исключение, перенаправив его на более высокий уровень
- сделать все, что можно в текущем контексте, и возбудить новое исключение, перенаправив его на более высокий уровень
- завершить работу программы
- упростить программу (если используемая схема обработки исключений делает все только сложнее, значит, она никуда не годится)
- добавить вашей библиотеке и программе безопасности
Реклама
В neovim я получаю сообщение об ошибке при подключении nvim_dap к работающему java-процессу. jdtls запускается нормально.
Я добавляю точку останова, используя dt, затем пытаюсь подключиться к запущенному процессу Java, нажимая dc, и получаю сообщение об ошибке: —
Error executing luv callback:
...config/nvim/autoload/plugged/nvim-dap/lua/dap/session.lua:676: bad argument #2 to 'connect' (number expected, got nil)
stack traceback:
[C]: in function 'connect'
...config/nvim/autoload/plugged/nvim-dap/lua/dap/session.lua:676: in function <...onfig/nvim/autoload/plugged/nvim-dap/lua/dap/session.lua:669>
Press ENTER or type command to continue
Пожалуйста, помогите решить эту ошибку. Java lsp работает нормально, но nvim_dap не работает. Я попытался перейти по следующим ссылкам, чтобы настроить java и dap. https://github.com /mfussenegger/dotfiles/blob/master/vim/.config/nvim/lua/me/dap.lua https://github.com/s1n7ax/youtube-java- отладка/blob/main/init.lua java.lua выглядит следующим образом:
local dap = require 'dap'
local M = {}
function M.execute_buf_command(command, callback)
vim.lsp.buf_request(
0, 'workspace/executeCommand', command, function(err, _, res)
if callback then
callback(err, res)
elseif err then
print('Execute command failed: ' .. err.message)
end
end)
end
function M.execute_command(command, callback)
if type(command) == 'string' then command = { command = command } end
M.execute_buf_command(
command, function(err, res)
--assert(not err, err and (err.message or Log.ins(err)))
callback(res)
end)
end
--[[
-- Starts the dubug session and returns the port
--
-- @Param callback {function(port: number)}
--]]
function M.start_debug_session(callback)
M.execute_command('vscode.java.startDebugSession', callback)
end
--[[
-- Returns all the main classes in the project
--
-- @Param callback {function(main_classes: List<List<String>)}
-- { {
-- filePath = "/home/s1n7ax/Workspace/demo/src/main/java/com/example/demo/DemoApplication.java",
-- mainClass = "com.example.demo.DemoApplication",
-- projectName = "demo"
-- } }
--]]
function M.resolve_main_classes(callback)
M.execute_command('vscode.java.resolveMainClass', callback)
end
--[[
-- Returns classpath for the given main class
--
-- @Param main_class {string} of which classpath should be returned
-- @Param callback {function(classpath: List<List<String>>)}
-- { {},
-- {
-- "/home/s1n7ax/Workspace/demo/bin/main",
-- "/home/s1n7ax/.gradle/.../spring-boot-starter-web/2.5.4/2bef2cedf/spring-boot-starter-web-2.5.4.jar",
-- }
--]]
function M.resolve_class_path(main_class, project_name, callback)
M.execute_command(
{
command = 'vscode.java.resolveClasspath',
arguments = { main_class, project_name },
}, callback)
end
--[[
-- Returns list of main class and classpath map
--
-- @Param callback {function(classpaths: List<Map>)}
--]]
function M.resolve_class_paths(callback)
local classpaths = {}
local function resolve_all_class_paths(class_iter)
local class_info = class_iter.next()
if not class_info then return callback(classpaths) end
M.resolve_class_path(
class_info.mainClass, class_info.projectName, function(class_path)
table.insert(
classpaths,
{ class_info = class_info, class_path = class_path })
resolve_all_class_paths(class_iter)
end)
end
M.resolve_main_classes(
function(main_class_info)
local index = 1
local main_class_iter = {
next = function()
local temp_index = index
index = index + 1
return main_class_info[temp_index]
end,
}
resolve_all_class_paths(main_class_iter)
end)
end
--[[
-- Returns dap java debug configuration
--
-- @Param callback {function(config: Map)}
--]]
function M.get_dap_config(callback)
M.resolve_class_paths(
function(class_paths_info)
local conf = {}
for index, classpath_info in ipairs(class_paths_info) do
local main_class = classpath_info.class_info.mainClass
local project_name = classpath_info.class_info.projectName
local class_paths = classpath_info.class_path
table.insert(
conf, {
name = string.format(
'(%d) Launch -> %s -> %s', index, project_name,
main_class),
projectName = project_name,
mainClass = main_class,
classPaths = vim.tbl_flatten(class_paths),
modulePaths = {},
request = 'launch',
type = 'java',
javaExec = '/usr/bin/java',
})
end
callback(conf)
end)
end
function M.setup()
-- setup_widgets()
dap.listeners.after.event_initialized['me-keys'] = function()
api.nvim_set_keymap("n", "<down>", "<cmd>lua require('dap').step_over()<CR>", {noremap = true, silent = true})
api.nvim_set_keymap("n", "<left>", "<cmd>lua require('dap').step_out()<CR>", {noremap = true, silent = true})
api.nvim_set_keymap("n", "<right>", "<cmd>lua require('dap').step_into()<CR>", {noremap = true, silent = true})
end
dap.listeners.after.event_terminated['me-keys'] = function()
api.nvim_del_keymap("n", "<down>")
api.nvim_del_keymap("n", "<left>")
api.nvim_del_keymap("n", "<right>")
end
dap.defaults.fallback.terminal_win_cmd = 'tabnew'
dap.configurations.java = {
{
type = 'java';
request = 'attach';
name = "Debug (Attach) - Remote";
hostName = "127.0.0.1";
port = 5005;
},
}
require('dap.ext.vscode').load_launchjs()
end
M.setup()
dap.adapters.java = function(callback)
M.start_debug_session(
function(port)
callback({ type = 'server', host = '127.0.0.1', port = port })
end)
end
local on_attach = function(client, bufnr)
if client.name == 'java' then
M.get_dap_config(
function(conf)
dap.configurations.java = conf
print('Debugger is ready')
end)
end
local function buf_set_keymap(...)
vim.api.nvim_buf_set_keymap(bufnr, ...)
end
local function buf_set_option(...)
vim.api.nvim_buf_set_option(bufnr, ...)
end
-- Enable completion triggered by <c-x><c-o>
buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
-- Mappings.
local opts = { noremap = true, silent = true }
-- See `:help vim.lsp.*` for documentation on any of the below functions
buf_set_keymap('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>', opts)
buf_set_keymap('n', 'gd', '<cmd>lua vim.lsp.buf.definition()<CR>', opts)
buf_set_keymap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<CR>', opts)
buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
buf_set_keymap(
'n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
buf_set_keymap(
'n', '<space>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>',
opts)
buf_set_keymap(
'n', '<space>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>',
opts)
buf_set_keymap(
'n', '<space>wl',
'<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>',
opts)
buf_set_keymap(
'n', '<space>D', '<cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
buf_set_keymap('n', '<space>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
buf_set_keymap(
'n', '<space>ca', '<cmd>lua vim.lsp.buf.code_action()<CR>', opts)
buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
buf_set_keymap(
'n', '<space>e',
'<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>', opts)
buf_set_keymap(
'n', '[d', '<cmd>lua vim.lsp.diagnostic.goto_prev()<CR>', opts)
buf_set_keymap(
'n', ']d', '<cmd>lua vim.lsp.diagnostic.goto_next()<CR>', opts)
buf_set_keymap(
'n', '<space>q', '<cmd>lua vim.lsp.diagnostic.set_loclist()<CR>', opts)
buf_set_keymap(
'n', '<space>f', '<cmd>lua vim.lsp.buf.formatting()<CR>', opts)
end
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities = require('cmp_nvim_lsp').update_capabilities(capabilities)
-- If you started neovim within `~/dev/xy/project-1` this would resolve to `project-1`
local project_name = vim.fn.fnamemodify(vim.fn.getcwd(), ':p:h:t')
local workspace_dir = '/Users/amansingh/.workspace/' .. project_name
local config = {
cmd = {'sh','jdtls_launch', workspace_dir},
root_dir = require('jdtls.setup').find_root({'.git','mvnw','gradlew'}),
capabilities = capabilities,
on_attach = on_attach
}
config['init_options'] = {
bundles = {
vim.fn.glob(
'/Users/amansingh/' ..
'development/com.microsoft.java.debug.plugin-0.35.0.jar'),
},
}
require('jdtls').start_or_attach(config)
vim.api.nvim_exec(
[[
nnoremap <silent> <leader>dc :lua require'dap'.continue()<CR>
nnoremap <silent> <F10> :lua require'dap'.step_over()<CR>
nnoremap <silent> <F11> :lua require'dap'.step_into()<CR>
nnoremap <silent> <F12> :lua require'dap'.step_out()<CR>
nnoremap <silent> <leader>dt :lua require'dap'.toggle_breakpoint()<CR>
nnoremap <silent> <leader>B :lua require'dap'.set_breakpoint(vim.fn.input('Breakpoint condition: '))<CR>
nnoremap <silent> <leader>lp :lua require'dap'.set_breakpoint(nil, nil, vim.fn.input('Log point message: '))<CR>
nnoremap <silent> <leader>dr :lua require'dap'.repl.open()<CR>
nnoremap <silent> <leader>dl :lua require'dap'.run_last()<CR>
]], false)