Страницы

Поиск по вопросам

Показаны сообщения с ярлыком try-catch. Показать все сообщения
Показаны сообщения с ярлыком try-catch. Показать все сообщения

воскресенье, 8 марта 2020 г.

Выполнится ли блок finally?

#c_sharp #try_catch


static void Main(string[] args)
{
    StreamWriter file = new StreamWriter("file.txt");
    try
    {
        throw new DivideByZeroException();
    }
    catch (StackOverflowException e)
    {
        Console.WriteLine("Error: " + e.Message);
    }
    finally
    {
        file.WriteLine("Error");
        file.Close(); 
    }
    Console.ReadKey();

}

    


Ответы

Ответ 1



A-a-a, я, кажется, начинаю понимать, что Вы имели в виду. Выполнение finally не зависит от типа исключения указанного в catch. Ваш код эквивалентен: try { try { throw new DivideByZeroException(); } catch (StackOverflowException e) { ... } } finally { ... }

Ответ 2



При возникновении исключения общеязыковая среда выполнения (CLR) ищет оператор catch, который обрабатывает это исключение. Если текущий выполняемый метод не содержит такой блок catch, среда CLR выполняет поиск в методе, который вызвал текущий метод, и так далее вверх по стеку вызовов. Если блок catch не находится, то среда CLR отображает пользователю сообщение о необработанном исключении и останавливает выполнение программы. (c) MSDN По finally: С помощью блока finally можно выполнить очистку всех ресурсов, выделенных в блоке try, и можно запускать код даже при возникновении исключения в блоке try. Как правило, операторы блока finally выполняются, когда элемент управления покидает оператор try. Передача управления может возникать в результате выполнения нормального выполнения, break, continue, goto или оператора return, или распространения исключения из оператора try. В рамках обработки исключений, связанный блок finally гарантированно будет выполнен. Однако если исключения необработано, то выполнение блока finally зависит от того, как активирована операция очистки исключения. Это, в свою очередь, зависит от того, как настроен компьютер. Дополнительные сведения см. в статье Обработка необработанных исключений в CLR. (c) MSDN Таким образом выходит, что выполнение блока finally{} происходит после выхода из блока try{} В случае если в try{} происходит ошибка которая не перехватывается ни одним из catch{} в дереве вызовов и не может быть проигнорирована ( системный диалог об ошибке с "продолжить") то выполнение из блока try{} не выходит, и, соответственно, finally{} не отрабатывает. Если выход за try{} возможен т.к. есть перехват исключения выше по стеку вызовов, то сначала выполняется его блок finally{}, а уже за тем отрабатывает блок catch{} перехватывающий исключение. Если ошибка игнорируется то отрабатывает блок finally{} и выполнение программы продолжается далее по коду...

суббота, 7 марта 2020 г.

блоки try-catch. Обработка исключений

#java #исключения #try_catch


правильно ли я понимаю, что если первое закрытие выбросит ошибку, то остальные даже
и не вызовутся? подскажите как ПРАВИЛЬНО исправить, а главное почему именно так!

private void closeStatement() throws DaoException, SQLException {
    try {
        getByIdStmt.close();
    } catch (Exception e) {
        throw new DaoException("Error! getByIdStmt is not closed");
    }
    try {
        updateStmt.close();
    } catch (Exception e) {
        throw new DaoException("Error! updateStmt is not closed");
    }
    try {
        addStmt.close();
    } catch (Exception e) {
        throw new DaoException("Error! addStmt is not closed");
    }
    try {
        deleteStmt.close();
    } catch (Exception e) {
        throw new DaoException("Error! deleteStmt is not closed");
    }
    System.out.println("Statement close");
}

    


Ответы

Ответ 1



Возможно, так: private void closeStatement() throws DaoException, SQLException { ArrayList err = new ArrayList(); try { getByIdStmt.close(); } catch (Exception e) { err.add("getByIdStmt"); } try { updateStmt.close(); } catch (Exception e) { err.add("updateStmt"); } try { addStmt.close(); } catch (Exception e) { err.add("addStmt"); } try { deleteStmt.close(); } catch (Exception e) { err.add("deleteStmt"); } if (!err.isEmpty()) { throw new DaoException("Error! "+String.join(", ", err)+" not closed"); } System.out.println("Statement close"); } Поочерёдно пытаемся закрыть все statement, неудачи собираем. Потом выбрасываем общее для всех ошибок исключение.

суббота, 15 февраля 2020 г.

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

#cpp #исключения #try_catch


Как обработать исключение, которое возникает при попытке инициализировать значение
за  пределами массива, или при чтении из-за его пределов. Пробовал в catch писать "exception
e", но оно не ловит.
    


Ответы

Ответ 1



если это встроенный c++ массив то можно ставить ассерты перед каждым доступом к его элементу - #define array_size 100 int v[array_size]; int i = 100; assert(i >= 0 && i < array_size); // бросит исключение v[i] = 123; если у вас std::vector то как уже сказали в комментариях - воспользоваться функцией членом std::vector::at которая гарантированно бросит исключение при выходе за пределы вектора. std::vector v(5); v.at(5) = 1.0f; // бросит исключение

Ответ 2



На самом деле в случае выхода за границу массива происходит исключение уровня операционной системы, после чего программе присылается сигнал об этом, и она падает (в комментариях меня поправят, если это не так, но общий смысл такой). Корректная реакция на такие сигналы - завершение программы, поскольку они вызываются недопустимыми операциями и после них программа может не находится в консистентном состоянии. Однако, если очень хочется, то можно такую ошибку отловить и продолжить работу (при этом следует очень хорошо понимать зачем и почему понадобилось так делать, поскольку затея эта целиком и полностью не здоровая). В основе обработки таких ошибок лежат функции setjmp и longjmp, позволяющие сохранить состояние программы и вернутся к сохраненному ранее состоянию. Так же нужно отловить сигнал операционной системы, что делается везде по-своему (Для POSIX-систем достаточно обычных обработчиков сигналов, для windows стоит использовать Structured Exception Handling или Vectored Exception Handling). Итак. Регистрируем обработчик (пример для POSIX). struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = signalHandler; sigaction(SIGSEGV, &act, 0); В обработчике сигнала возвращаемся к сохраненному состоянию и передаем не нулевое значение в качестве возвращаемого для setjmp: jmp_buf env; static void signalHandler(int signum) { longjmp(env, 1); } Перед входом в опасный блок сохраняем состояние программы: try { if (setjmp(env)) throw std::runtime_error("Some shit"); // Действия, которые могут уронить программу Ловим брошенное исключение: } catch (std::runtime_error & e) { // Что-то делаем } Как оно работает. Функция setjmp при сохранении возвращает 0 - исключение не кидается. Если дальше происходит ошибка, то longjmp возвращает выполнение к setjmp, которое в этот момент вернет 1 - бросится исключение, которое можно обработать. Данный пример дает лишь общее представление о логике обработки таких ошибок, для использования его на практике, его стоит доработать. Более полное описание чего куда и зачем можно найти тут: Habrahabr: Обработка многократно возникающих SIGSEGV-подобных ошибок

суббота, 8 февраля 2020 г.

Java. Задание занчения (final) переменной в try-блоке и ее дальнейшее использование и видимость

#java #переменные #инициализация #try_catch


Проблема заключается в необходимости задания значения final переменной (connectionSocket2)
в try-блоке. В дальнейшей части кода (в части run()) этого не видно и возникает как
бы ошибка, что та переменная не определена:

        final Socket connectionSocket;
        try { connectionSocket = welcomeSocket.accept(); }



  The local variable connectionSocket2 may not have been initialized


убрать final не могу, так как (в части run()) дает ошибку 


  Cannot refer to the non-final local variable connectionSocket defined
  in an enclosing scope


            Socket connectionSocket2=null;
            try { connectionSocket2 = welcomeSocket.accept();
            } catch (IOException e2) { e2.printStackTrace(); }
            final Socket connectionSocket=connectionSocket2; try{connectionSocket2.close();}catch(IOException
e1){e1.printStackTrace();}

            service.submit(new Runnable() {
                public void run() {
                    while (true) {
                        BufferedReader inFromClient=null;
                        DataOutputStream outToClient=null;
                        try{
                           inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
                           outToClient = new DataOutputStream(connectionSocket.getOutputStream());
                           outToClient.writeBytes(inFromClient.readLine());
                        } catch(IOException ioe) {} }}});


Статической делать не могу - для каждого потока создается свое соединение, как бы
свой экземпляр этой переменной.

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

Как правильно, профессионально быть в этой ситуации? Модно ли как-то сказать компилятору,
что переменная на самом деле уже определена в try блоке и ему нечего "волноваться"?
(типа динамическая переменная, как в .Net)
    


Ответы

Ответ 1



Ответ-вопросник и очередной наброс на медальку. Итак, у вас было что-то вот такое: public class ICanIntoSockets { public static void main( String[] args ) throws IOException { ServerSocket welcomeSocket = new ServerSocket(10000); ExecutorService service = Executors.newCachedThreadPool(); doWork( welcomeSocket, service ); } public static void doWork( ServerSocket welcomeSocket, ExecutorService service ) { try { while (true) { final Socket connectionSocket = welcomeSocket.accept(); service.execute( () -> { try ( Socket socket = connectionSocket; BufferedReader inFromClient = new BufferedReader( new InputStreamReader(socket.getInputStream())); DataOutputStream outToClient = new DataOutputStream( socket.getOutputStream())) { outToClient.writeBytes(inFromClient.readLine()); } catch (IOException ioe) { ioe.printStackTrace(); } }); } } catch ( IOException ex ) { ex.printStackTrace(); } } } но try - плохо, и торморзит на тысячах подключений (тесты где?), поэтому вы решили от него избавиться. Ява - убогий язык, в ней зачем-то придумали Checked Exceptions и напихали во все места в стандартной библиотеке, поэтому совсем без try - никак: public static void doWork( ServerSocket welcomeSocket, ExecutorService service ) { while (true) { final Socket connectionSocket; try { connectionSocket = welcomeSocket.accept(); } catch (IOException ex) { ex.printStackTrace(); } service.execute(() -> { try ( Socket socket = connectionSocket; // The local variable connectionSocket may not have been initialized BufferedReader inFromClient = new BufferedReader( new InputStreamReader(socket.getInputStream())); DataOutputStream outToClient = new DataOutputStream(socket.getOutputStream())) { outToClient.writeBytes(inFromClient.readLine()); } catch (IOException ioe) { ioe.printStackTrace(); } }); } } Зло загнано в угол в одной строчке кода! Но компилятор почему-то считает, что переменная connectionSocket может быть не инициализирована. Почему? Потому что есть путь выполнения программы, при которой она действительно не инициализируется: когда welcomeSocket.accept() выбрасывает исключение. Метод не возвращает значение - значение переменной не присваивается. Что же делать? Не надо продолжать выполнение итерации, ваш код все равно не сможет работать дальше без клиентского сокета. Сделайте внутри catch-блока return, break, continue (в надежде, что следующий accept не выбросит исключение, что вряд ли). Если код непременно должен продолжаться дальше - присвойте connectionSocket null и где-то сделайте проверку. Предложенный вариант с массивом - это либо то самое создание объектов и выделение памяти, с которым вы сражаетесь, либо потеря подключений и обработка одного подключения несколько раз, смотря где вы этот массив объявите.

Ответ 2



Можно обёртку сделать: public class MySocket{ private Socket mSocket; public MySocket(){ } public void setSocket(Socket socket){ mSocket = socket; } public Socket getSocket(){ return mSocket; } } И создать его экземпляр: final MySocket connectionSocket = new MySocket(); И дальше: try{ connectionSocket.setSocket(welcomeSocket.accept()); } catch (IOException e2) { e2.printStackTrace(); } И внутри Runnable обращаться к connectionSocket.getSocket().

Ответ 3



создайте final Socket[] на один элемент и в пишите в него.

суббота, 1 февраля 2020 г.

разница в throw, throw new, throw ex

#c_sharp #net #исключения #try_catch


В чем все таки разница и зачем вообще бросать исключение?
Я так понимаю если у нас в где-то вызывается метод в котором потенциально может быть
ошибка мы должны от туда "бросать" исключение в место от куда метод не посредственно
вызывается,
    


Ответы

Ответ 1



Если совсем упрощать, то есть всего две конструкции, throw e и throw. Первая - throw e - берет объект исключения и бросает его. Этот объект поймает первый соответствующий catch выше по стеку. В момент бросания к исключению привязывается стек вызовов, от того места, где был вызван throw e и выше. Поймав этот e выше, вы можете узнать точное место, где был вызван throw e. Вторая - throw - может использоваться только в catch, и она пробрасывает пойманное этим catch исключение выше так, как будто вы его не поймали. Простой пример private static void B() { throw new Exception(); } private static void A() { try { B(); } catch (Exception e) { throw; } } public static void Main(string[] args) { try { A(); } catch (Exception e) { Console.WriteLine(e); } } Метод A ловит исключение, но делает вид что не поймал (вызывает throw). Поэтому на консоль выводится System.Exception: Exception of type 'System.Exception' was thrown. at ConsoleApp13.Program.B() in ... at ConsoleApp13.Program.A() in ... at ConsoleApp13.Program.Main(String[] args) in ... Если же метод A переписать как private static void A() { try { B(); } catch (Exception e) { throw e; } } То информация о том, что исключение было создано и брошено в B, потеряется: System.Exception: Exception of type 'System.Exception' was thrown. at ConsoleApp13.Program.A() in at ConsoleApp13.Program.Main(String[] args) in То поведение будет таким же, как если бы в A было написано просто throw new Exception();

пятница, 24 января 2020 г.

Влияет ли блок try на производительность кода в С++, если исключений не возникает?

#cpp #исключения #производительность #try_catch


Прошу прощения если я задаю глупый вопрос, но мне нужно знать точно. Если я пишу
подобный код на С++:

int main() try {
.....
}
catch (const std::bad_alloc& e) {
    ...
}
...
catch (...) {
    cout << "Was throw exception" << endl;
    system("pause");
}


Будет ли скомпилированный в блоке try код отличным от такого же кода без блока try?
Может ли блок try оказывать какое либо влияние на производительность помимо ситуаций
когда происходят исключения? 
    


Ответы

Ответ 1



Откровенно говоря, не очень понятно, как именно провести эксперимент... Так что это не более чем иллюстрация, по которой трудно делать выводы. На такой функции-пустышке на VC++ 2017 попробовал - int main(int argc, const char * argv[]) { { muTimer mt; for(int i = 0; i < 1000000; ++i) { try { f(i); } catch(...) {} } cout << mt.stop().duration() << endl; } { muTimer mt; for(int i = 0; i < 1000000; ++i) { f(i); } cout << mt.stop().duration() << endl; } } int total; void f(int i) { total += i; } Получилось примерно 4 миллисекунды на 0.6. Но, думаю, что при серьезных функциях соотношение будет куда ближе к 1:1 :)

четверг, 2 января 2020 г.

Оператор try c ресурсами

#java #исключения #try_catch


Зачем нужен усовершенствованный и появившийся в JDK 7 оператор try-c-ресурсами?

try (спецификация_ресурса) {
//использование ресурса
{

    


Ответы

Ответ 1



Оператор try-c-ресурсами реализует принцип автоматического управления ресурсами, целью которого является избежать, например, утечек памяти, в случаях когда ресурс по каким-то причинам не освобождается, если он больше не нужен. Неудачный исход закрытия файла может привести к "утечкам памяти", поскольку неиспользуемые ресурсы оперативной памяти останутся выделенными.(стр 365) try ( FileInputStream res = new FileInputStream(args[O])) { //использование ресурса } Оператор try-c-ресурсами позволяет объявить и проинициализировать ресурс (в круглых скобках после оператора try), создав переменной ресурса локальный контекст в блоке try. По завершении этого блока переменная удаляется, а значит и ресурс автоматически закрывается. Отсюда отпадает необходимость явного закрытия ресурса методом close() в блоке оператора finally.

Ответ 2



try-catch with resources был придумал лишь для того, чтобы избежать шаблонного кода. Давайте попробуем написать, простой метод, для чтения первой строки из файла. До java 7 он выглядел бы следующим образом: private static String readFirstLine(String fileName) { BufferedReader reader = null; String line = null; try { reader = new BufferedReader(new FileReader(fileName)); line = reader.readLine(); reader.close(); } catch (IOException e) { try { reader.close(); } catch (IOException e1) { e1.printStackTrace(); } } return line; } Заметили, что в блоке catch нам нужен еще один блок для обработки исключений, т.к. мы должны закрыть ресурс, но операция закрытия в свою очередь тоже может выбросить исключение. Не стоит так же забывать, что try-catch with resources позволяет не думать об освобождении ресурсов. Как только выполнение программы покидает область видимости ресурса/ресурсов, у них автоматические вызывается метод java.lang.AutoCloseable.close() По сути, данную конструкцию можно представить, как метод, который принимает на вход какой то блок кода, требующий выполнения и список ресурсов, которые необходимо освободить после его выполнения. private static void invoke(Callable task, Closeable... resources) throws Exception { Exception exception = null; try { task.call(); } catch (Exception e) { exception = e; } finally { for (Closeable closeable : resources) try { closeable.close(); } catch (Exception e) { if (exception == null) exception = e; else exception.addSuppressed(e); } } if (exception != null) throw exception; }

четверг, 19 декабря 2019 г.

Отличие try…catch от throws

#java #исключения #try_catch


В чем принципиальное отличие 

try {

}catch(Exception e){

}


от throws
    


Ответы

Ответ 1



При обработке исключений всегда есть 2 варианта : либо пробрасываем выше (т.е. добавляем throws к сигнатуре метода), либо обрабатываем "на месте", используя try-catch

Ответ 2



Вопрос в том где вам удобнее произвести эту обработку. try-catch как раз для этой обработки и служит, но не всегда удобно обрабатывать исключение в том месте где оно бросается. throws позволяет не обрабатывать исключение в том месте которое его вызывает, а переложить эту работу на то место в коде где вы будете вызывать метод через сигнатуру которого вы это исключение пробросили. На пример: a() { try { // какой-то код который может выбросить исключение } catch (Exception e) { ... } } b() { a(); // и тут не каких исключений не надо ловить вы его уже поймали } Или если вы не хотите ловить в методе a() то вы можете сделать так: a() throws Exception { // какой-то код который может выбросить исключение но мы его пробрасываем } b() { try { a();// и ловим тут потому что в методе a() мы это делать не стали } catch (Exception e) { ... } } Во втором примере мы могли бы еще дальше его пробрасывать написав b() throws Exception вплоть до метода main и вообще его не ловить, но так лучше не делать. То есть исключение это места где java говорит: тут может быть проблема, а вы должны что-то ответить, на пример: да здесь и обработаем и пишите try-catch или нет здесь не хочу давай потом и с помощью throws откладываете решение.

Ответ 3



Тоже возник подобный вопрос, решил потестить. Вот пример кода: public class Exeptions { static void throwOne() { // не указан throws System.out.println("В теле метода throwOne()"); throw new NullPointerException("нулпоинтер"); } public static void main(String[] args) { try { throwOne(); } catch (NullPointerException e) { e.printStackTrace(); } System.out.println("Возвращение в main"); } } Результат: В теле метода throwOne() java.lang.NullPointerException: нулпоинтер at Exeptions.throwOne(Exeptions.java:6) at Exeptions.main(Exeptions.java:16) Возвращение в main Как видно все прекрасно скомпилировалось, но если выкинуть любое проверяемое исключение и не прописать throws - компилятор выдаст ошибку. Итог: "обязательно указывать throws для всех исключений, кроме тех, которые относятся к классам Error и RuntimeException или любым их подклассам. Все остальные исключения, которые может сгенерировать метод, должны быть объявлены в операторе throws. Если этого не сделать, то во время компиляции возникнет ошибка." - Шилдт.

среда, 18 декабря 2019 г.

try/catch вместо if null

#java #if #try_catch


Часто бувает несколько и больше аргументов в условии которые необходимо проверить
на null. Мне надоело перечислять if(a!=null && b!=null || c!=null) и т.д. Я стал просто
обрамлять в try/catch и если что-то не так то просто вывожу сообщение, что одно из
условий отсутствует. Понятно что в некоторых случаях необходимо знать, что я получаю
и приходится использовать if.

Но все же является такая практика с t/c нормальной?
    


Ответы

Ответ 1



Примените что-то подобное: private boolean isNull(Object... objects) { if (objects != null) { for (Object object : objects) { if(object==null) return true; } } return false; } //использование if(isNull(a, b, c)) //blah-blah

Ответ 2



Вопрос не в длине кода. Проверка на null является правильным, хорошим стилем. Дело в том, что игнорируя проверку на null, вы тем самым подавляете не только эти, ожидаемые вами ошибки, но и все другие потенциальные баги в вашей программе. Проверка параметров вручную позволит приложению упасть в случае, если где-то в другом месте у вас ошибка. Если же вы будете ловить все ошибки скопом, то у вас ошибка в другом месте программы, приводящая к такому же исключению, будет поймана и выдаст ложное сообщение об ошибке.

Ответ 3



Конструкция try/catch обходится дороже. Приведу тест замера времени для 1000000000 вызовов методов проверяющих аргумент на null явно и в попытке и выведу результат замера в консоль: public class Test { public static void main(String[] args) { long start, end; start = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) method(null); end = System.currentTimeMillis(); System.out.println("Check null: " + (end-start)); start = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) methodWithTry(null); end = System.currentTimeMillis(); System.out.println("Try/catch: " + (end-start)); } public static int method(String s) { if (s != null) { return s.length(); } return 0; } public static int methodWithTry(String s) { try { return s.length(); } catch (NullPointerException e) { return 0; } } } Результат: Check null: 15 Try/catch: 1404 UPD: Комментарий Artem Konovalov подтвердился. Судя по всему мой код был автоматически оптимизирован из-за того, что не был использован результат методов. Скорректированный код дает иные результаты: public class Test { public static void main(String[] args) { int c = 0; long start, end; start = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) if (i%2==0) { c += method(null); } else { c += method(i); } end = System.currentTimeMillis(); System.out.println("Check null: " + (end-start)); start = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) if (i%2==0) { c += methodWithTry(null); } else { c += methodWithTry(i); } end = System.currentTimeMillis(); System.out.println("Try/catch: " + (end-start)); } public static int method(Integer i) { if (i != null) { return i.intValue(); } return 0; } public static int methodWithTry(Integer i) { try { return i.intValue(); } catch (NullPointerException e) { return 0; } } Результат: Check null: 1702 Try/catch: 3654

Ответ 4



Однозначно, сказать нельзя, какой вариант лучше. В этой ситуации стоит учитывать несколько моментов. Исключения, как правило, используются для необычных ситуаций, когда выполнение программы пошло не так, как задумывал программист - получены некорректные параметры, внешние ошибки и пр. Из этого можно вывести, что: Если вы пишите код, который будет доступен для вызова сторонними разработчиками, то выкидывание NullPointerException вполне оправдано. Если этот код, является частью внутреннего компонента, то использование блока try-catch-finally, не вполне оправдано. Получение null, говорит о том, что код некорректен, т.е. такая ситуация ненормальна. В идеале, в процессе отладки null проверяется assert'ами и все подобные ситуации вылавливаются в программе. Еще один довод против исключений, это более худная производительность. В моем тесте, разница была порядка 2x.

среда, 4 декабря 2019 г.

Какое общее правило, когда использовать try catch? [дубликат]

#алгоритм #try_catch



    На данный вопрос уже ответили:
    
        
            Грамотное использование try-catch
                
                    4 ответа
                
        
    
    
На собеседовании мне задали вопрос, какое есть общее правило, когда делать try и catch.
Я ответил, когда есть работа с внешними ресурсами, где возникновение ошибки не зависит
от программиста. Например, когда есть работа с файлами или БД (файл может не существовать,
на диске может закончиться место, коннект к БД может не пройти)
Ответ оказался не полным.

Якобы есть какое-то правило, когда нужно использовать try catch

Сам я склоняюсь к тому, что правильный ответ: использовать try catch надо, когда
нельзя обойтись проверками if/else
А что думаете вы? Какой правильный ответ?

Вопрос касается любого языка.
    


Ответы

Ответ 1



Я не знаю, какой ответ хотели услышать от вас на собеседовании, и мне кажется, что стопроцентно верного критерия быть не может. Моё мнение: нужно ловить исключение в том месте, где вы знаете, что с ним делать. Поясню. Допустим, у вас есть функция открытия файла, файла не нашлось, и она выбрасывает исключение. Что делать в этой точке? Это важная операция, без информации из файла продолжать нельзя, так что нужно проинформировать пользователя и завершить программу? Или это файл конфигурации, которого в начале работы программы нету, и его нужно будет создать с данными по умолчанию? В функции открытия файла вы этого не знаете. Поэтому исключение ловить не надо, дайте ему пролететь на более высокий уровень. А вот на уровне более крупноблочной логики, которая запустила операцию чтения конфигурации, вполне можно про приходу исключения при открытии файла отловить его и просто создать конфигурацию по умолчанию. Такая одноуровневая схема может оказаться слишком простой, и вам придётся на пути перепаковывать исключение, добавляя в него смысла. Например, при чтении числа из строки произошло исключение из-за несоответствия формата. Вы в этой точке не знаете, фатальна ли эта проблема, и просто пропускаете исключение дальше. Логика более высокого уровня знает, что происходит операция чтения конфигурационных данных, которая почему-то завершилась с исключением. В этой точке логика программы имеет возможность решить, что игнорировать проблему нельзя, и она бросает более высокоуровневое исключение, которое означает «чтение конфигурации завершилось аварийно». Это исключение, в свою очередь, ловит бизнес-логика верхнего уровня, которая сообщает юзеру о потере конфигурационного файла и пересоздаёт его заново. В любом случае, преждевременный отлов исключений на слишком «внутреннем» уровне вреден, потому что программа в такой точке обычно не может сделать ничего разумного.

Ответ 2



Вопрос именно так стоит? try и catch? Не исключения вообще? Тогда - там, где возможна генерация исключения, которое может быть разумно обработано вашим кодом. Если исключение не может быть сгенерировано - try/catch ни к чему :) Если вы не можете его обработать - тоже нет смысла его ловить, лучше передать дальше.

воскресенье, 1 декабря 2019 г.

try-catch против if-else

#c_sharp #исключения #try_catch


Я сейчас изучаю C# по учебнику Шилдта, а он учит заключать все узкие моменты в try-catch.

Это нормальная практика ветвления кода, или лучше пользоваться if-else? Я, конечно,
понимаю разницу между ошибками и исключениями. Но теперь у меня расплывается граница
между некоторыми исключениями и обычными ветвлениями в коде.

Например операция деления одного числа на другое подразумевает, что пользователь
может (попробовать) поделить число на ноль. С одной стороны результат этой операции
будет исключением, которое можно обработать. С другой стороны можно и не доводить дело
до исключения, заранее проверяя вводимые числа.  

Как принято поступать в обществе профессиональных программистов?
    


Ответы

Ответ 1



Вообще подмена исключений условными блоками - не самая здравая идея. Любая функция (метод) в принципе должна выполнять одну возложенную на нее задачу. Если по тем или иным причинам задача выполнена быть не может, то должно быть брошено исключение. Сам метод в общем случае не должен заниматься обработкой собственных исключений, для этого есть вызывающий его код. Метод должен либо выполнить задачу, либо сообщить о невозможности ее выполнения. Вернемся к вашему примеру: Например операция деления одного числа на другое подразумевает, что пользователь может (попробовать) поделить число на ноль. С одной стороны результат этой операции будет исключением, которое можно обработать. С другой стороны можно и не доводить дело до исключения, заранее проверяя вводимые числа. В этом случае должно быть именно вызвано исключение - ваш метод получил некорректные входные данные, и не может правильно произвести операцию деления. Тут интересна такая ваша фраза: С другой стороны можно и не доводить дело до исключения, заранее проверяя вводимые числа. Можно. Но что должен делать код дальше, если проверка не прошла? Вернуть некое магическое значение типа -1 или 0? Это будет некорректно с точки зрения логики. Вывести сообщение об ошибке? Это будет попахивать ошибкой проектирования - отвечать за вывод сообщений об ошибках должен совсем другой код. Появится связность кода, а это очень плохо. Помимо того, существуют такие исключительные ситуации, в которых никакие if-else не помогут. Скажем, не удалось открыть соединение базой данных. Что программа должна делать дальше? Войти в условие и попытаться еще раз открыть его, а затем еще, еще и еще? Вряд ли. Ну а что касается if-else, то их имеет смысл использовать там, где "не сработавший" вариант - всего лишь одно из возможных корректных состояний программы. Резюмирую - метод должен либо выполнить задачу, либо сообщить о невозмождности ее выполнения. Обрабатывать собственные исключения чаще всего не нужно. Следует пробрасывать их вверх. Весьма рекомендую также прочесть у Рихтера главу, посвященную исключениям. Да и вообще саму эту книгу

Ответ 2



Нет, я не согласен с Шилдтом. Обычно код структурируется таким образом, что: Большинство операций имеют право выбросить исключение. Они не ловят исключения вызываемого кода, кроме редких случаев, где это действительно нужно. Если у вас происходит ручное управление ресурсами, вам скорее всего пригодится try/finally, а не try/catch try/catch оборачивает как можно большие, внешние блоки программной логики. Например, итерацию главного цикла. По поводу того, где использовать исключения, а где if/else: если операция может ожидаемо завершиться неудачей, используйте ветвление. Если операция завершается неудачно лишь в исключительных случаях, используйте исключения. Пример: если пользователь ввёл текст в editbox, вы не можете исходить из того, что он ввёл число. Используйте такой код: if (int.TryParse(s, out value)) return value; else // покажите message box и не закрывайте диалог В случае, если значение читается из конфигурационного файла, нечисловое значение там, где ожидается число — серьёзная проблема, и код соответственно меняется: return int.Parse(s); // если там не число, бросаем исключение, которое // будет поймано на верхнем уровне операцией чтения конфигурации Дополнительное чтение по теме: http://www.artima.com/intv/handcuffs.html

Ответ 3



Ветвление - это нормальное поведение программы. Исключения указывают на потенциальную деформацию логической целостности некой модели, от чего ее нужно спасать (закрывать соединения, прекращать работу с объектом и т.п.). Вот в C++ как вы и сказали, исключения добавлены как вспомогательный не обязательный механизм. Но try-catch зачастую читается куда лучше, чем хитроумный контроль за валидностью объекта по многим критериям, специальным переменным.

пятница, 29 ноября 2019 г.

Разница между catch, catch(Exception) и catch(Exception ex)

#c_sharp #исключения #try_catch #c_sharp_faq


Допустим, я не планирую использовать переменную ex и мне надо, чтобы обрабатывалась
любая ошибка.

try
{
    ...
}
catch(Exception ex)
{
    return;
}


Надо ли в таком случае объявлять переменную ex?

Или можно сделать так:

try
{
    ...
}
catch(Exception)
{
    return;
}


Или вообще вот так:

try
{
    ...
}
catch
{
    return;
}


В чем разница и как правильнее?
    


Ответы

Ответ 1



Переменную нужно объявлять, если в дальнейшем планируется её как-то использовать. Если важен только сам факт перехвата - достаточно указать всего лишь тип. Различие в catch(Exception) и пустом catch имеет место быть, если нужно перехватывать не CLS-совместимые исключения. Более подробнее об этом можно почитать на msdn. По ссылке как раз видно, что есть смысл и в таком коде: catch(Exception) { ... } catch { ... }

Ответ 2



Исключения также можно выстраивать одно за другим по мере увеличения. Если error не поппадает ни в одно исключений, то обезательно попадет в catch (Exception ex) как показанно на примере ниже. finally блок выполняется в при любых условиях. Console.WriteLine("Enter a number:"); while (true) { try { int yourNum = Convert.ToInt32(Console.ReadLine()); if (yourNum < 1 || yourNum > 10) { throw new Exception("Number must be between 1 and 10"); } Console.WriteLine("Your number is {0} !", yourNum); break; } // ловит ошибку неправильного формата. catch (FormatException) { Console.WriteLine("Not a number. Please try again"); } // ловит ошибку если число не попадает в допусимый ряд int catch (OverflowException) { Console.WriteLine("Not a valid integer. Pelase try again"); } // если ни один из предыдущих catch не скработал ловим изящно (gracefully) в ex переменную где ex.ToString() выводит нам на экран в string формате catch (Exception ex) { Console.WriteLine(ex.ToString()); } // код выполняется независимо есть ли ошибка или нет. finally { Console.WriteLine("Thanks for playing!"); } }

Ответ 3



Если вы хотите отловить любое исключение и контекст не важен, пишите: try { //... } catch { //... } Если важен тип исключения то: try { //... } catch (Exception) { //... } Но если логика завязана ещё и на данных в классе исключения то соответственно: try { //... } catch (Exception ex) { //... }

Ответ 4



1) Ловим конкретный тип исключения и заносим его в переменную. Переменную можно проанализировать в блоке и ,например, попробовать восстановить правильный ход программы 2) Ловим конкретный тип исключения, но само исключение не анализируем 3) Не уверен, но скорее всего ловятся абсолютно все исключения. P.S Так как все исключения наследуются от Exception, то 2 и 3 примеры аналогичны.

среда, 27 ноября 2019 г.

Грамотное использование try-catch

#c_sharp #исключения #try_catch


Вычитал, что использование try-catch весьма ресурсоёмко. Так ли это?

Если так, то как следует грамотно использовать try-catch?

Теоретически ведь можно практически всё делать по старинке, через коды возврата,
минуя использование try-catch, но тогда код пострадает в плане читаемости из-за громоздких
последовательностей if или switch. 
    


Ответы

Ответ 1



Для начала определите для себя, что такое «ресурсоёмко». Любой вопрос производительности стоит рассматривать в контексте с производительностью всей остальной программы. Если у вас алгоритм на целочисленной арифметике, то в нём try/catch может заметно замедлять производительность (а может и не замедлять). Если у вас идёт запись в файлы или обращение к базе данных, то обработка исключения будет на порядки быстрее остальных операций, поэтому нет никакого смысла её оптимизировать. Обычно try/catch нисколько не замедляет программу, если исключений фактически нет. То есть кидая исключение только в случае ошибки, вы не потеряете в производительности, когда ошибок нет. Если же ошибка произошла, то работа вашего алгоритма всё равно будет прервана, поэтому не так важно, что вы один раз потеряете дополнительно пару микросекунд (вряд ли больше) перед выдачей ошибки пользователю. Вам стоит беспокоиться, только если вы в цикле кидаете миллион исключений, потом их ловите, игнорируете и переходите на следующую итерацию. Но такой код как раз уже попахивает: получается, вы используете исключения для управления потоком вычислений, а не для информирования об исключительной ситуации. Но даже в такой ситуации JIT-компилятор может сообразить. Если в пределах заинлайненного кода он увидит и выбрасывание исключения и поимку и заметит, что при поимке вы игнорируете исключение (в частности, не читаете стектрейс из него), то он потенциально может заменить выбрасывание исключения на обычный goto, не создавая объект исключения вообще. Вообще обычно самое медленное в исключении — это создание стектрейса. Общее правило: пишите код так, как рекомендуют авторы языка и признанные специалисты в данной области. Если производительность кода вас не устраивает, профилируйте его, находите узкие места и оптимизируйте именно их (возможно, отступая от красоты кода в угоду скорости). Но не оптимизируйте то, что занимает полпроцента от общего времени выполнения. Не надо оптимизировать преждевременно.

Ответ 2



Applications and libraries should not use return codes to communicate errors. Вы подходите к проблеме не с той стороны. Настоящая выбор - это не "использовать ли try/catch или код возврата". А, скорее "выбросить исключение или вернуть код". Есть пара основных правил: исключения не должны использоваться для нормального control flow. исключения в коде должны всегда обозначать ошибку - исключительную ситуацию - что-то пошло не так, как планировалось. в случае ошибки нужно всегда использовать использовать исключение, а не код возврата. Все сводится к определению "как планировалось" и "что ожидалось", "произошла ли ошибка, или все идет нормально" в конкретном контексте. Вот пара примеров: Разработчик вызывает File.OpenRead. Вряд ли он ожидает, что файла нет, или что для открытия не хватит прав. Поэтому File.OpenRead должен бросить исключение (что он и делает). Разработчик достает значение из кэша - вызовом Page.Cache["news"]. Ожидает ли он, что значения в кэше не окажется - скорее всего да, причем даже в случае если 5 минут назад значение в кэше было. Чего он точно не ожидает - так это исключения и необходимости оборачивать обращения к кэшу в try/catch. Ловить ли исключения? Зависит от того, что вы собираетесь с ними делать. Есть всего несколько возможных причин ловить исключения: Ваш код может восстановиться после исключения - нормально продолжить работу. Это достаточно редкая ситуация. Обычно восстановление сводится к попытке повторить упавший вызов - и применимо оно только у удаленным сервисам, вроде баз данных. Типичный пример - ретрай команды к SQL Server при получении дедлока. Ваш код может добавить ценные данные к исключению - дописать что-то, что облегчит дальнейшую отладку. В таком случае исключение надо поймать и бросить новое исключение со старым в качестве InnerException. Ваш код - это код верхнего уровня, например, UI или основной метод worker-а. Тогда в нем стоит поймать исключение, записать его в лог и показать пользователю красивое сообщение об ошибке (если пользователь есть). Во всех остальных случаях никакого смысла ловить исключения нет. Все это достаточно подробно расписано в MSDN, Design Guidelines for Exceptions

Ответ 3



Это справедливо только в теории, или в экстремальных случаях вроде циклов с огромным количеством итераций. Можно придумать еще ряд примеров, где использование try будет нежелательно из-за медлительности, но все это - достаточно редкие случаи, в большинстве своем означающие, что либо автор кода пишет очень плохой код, который нуждается в оптимизации и/или рефакторинге, либо хочет использовать c# для каких-то чересчур чувствительных в плане производителности задач, и тогда, вероятно, C# и управляемый код - не лучший выбор. А вот в 99% случаев опасения по поводу "медлительности" try/catch - это экономия на спичках и добровольное лишение себя возможности писать легко поддерживаемый код (все эти мучения с кодами возврата способны принести немало головной боли). Маленький эксперимент. Выполните у себя вот этот код static void SomeAction() { var rand = new Random(); for (int i = 0; i < 1000; i++) rand.Next(); } static void Handle() { // просто заглушка } static void WithException(int iterations) { var watch = Stopwatch.StartNew(); try { for (int i = 0; i < iterations; i++) SomeAction(); throw new Exception(); } catch (Exception e) { Handle(); } watch.Stop(); NumberFormatInfo nfi = (NumberFormatInfo) CultureInfo.InvariantCulture.NumberFormat.Clone(); nfi.NumberGroupSeparator = " "; Console.WriteLine("with exception {1} iteration {0} ms", watch.ElapsedMilliseconds, iterations.ToString("n0", nfi)); Console.WriteLine(); } static void WithoutException(int iterations) { var watch = Stopwatch.StartNew(); for (int i = 0; i < iterations; i++) SomeAction(); Handle(); watch.Stop(); NumberFormatInfo nfi = (NumberFormatInfo) CultureInfo.InvariantCulture.NumberFormat.Clone(); nfi.NumberGroupSeparator = " "; Console.WriteLine("without exception {1} iteration {0} ms", watch.ElapsedMilliseconds, iterations.ToString("n0", nfi)); } static void Main(string[] args) { WithoutException(1); // этот и следующий вызов для "прогрева" WithException(1); WithoutException(1); WithException(1); WithoutException(1000); WithException(1000); WithoutException(100000); WithException(100000); WithoutException(500000); WithException(500000); Console.ReadLine(); } и посмотрите результаты (можете попробовать выполнить его прямо на ideone, но он скорее всего отвалится с таймаутом из-за большого количества итераций) Мои результаты были таковы: Как можно видеть, время выполнения кода, выбрасывающего и обрабатывающего исключение ничтожно отличается от кода без исключений. А вот удобство обработки ошибок на порядок выше. Конечно, тест кустарный и далеко не идеален, но уверяю вас, в 99% случаев проблема производительности выбрасывания и обработки исключений не стоит выеденного яйца.

Ответ 4



Когда говорят о ресурсоёмкости, надо понимать, по сравнению с чем. Если мы сравниваем с одним сложением — try/catch более затратен. Если мы сравниваем с чтением байта из файла — намного менее затратен. Исходя из этого, давайте разобьём вашу программу на части. UI. Когда мы говорим о UI, в основном время теряется на ожидании ввода/реакции пользователя. Это время на несколько порядков больше, чем выброс/обработка исключения. Поэтому использование исключений в UI-коде — нормальная вещь. Уровень бизнес-логики, контроллеры, вью-модели и такое прочее. Flow программы представляет собой не более чем одно новое состояние в секунду — иначе пользователь просто не успеет разобраться, что же произошло. Это значит, что для управления flow прекрасно могут применяться исключения. То же касается кода, коммуницирующего с UI. Модели. Вот здесь, конечно, выбрасывание исключений может оказаться невыгодным. В любом случае, вам нужно посмотреть на то, чем занимается данная модель, и как часто возникают ошибочные ситуации. Если это чтение файла, или чтение данных из интернета, то опять-таки накладные расходы на коммуникацию с внешним миром настолько велики, что нет смысла экономить на спичках. А вот если узкое место вашей модели — процессорное время (например, это числомолотилка), то здесь уже время, затраченное на обработку исключения, может оказаться сравнимым с типичным временем обработки элемента, и значит, придётся внимательнее планировать стратегию реакции на ошибки. В этом случае, однако, даже если вы будете применять коды ошибок внутри модели, имеет смысл сообщать о суммарной ошибке наверх именно при помощи исключения. В любом случае, я бы предостерёг вас от преждевременной оптимизации. В подавляющем большинстве случаев узким местом будет вовсе не обработка исключений. Поэтому пишите ваш код с исключениями, и если вас не удовлетворяет производительность, проведите профилирование. Только оно сможет сказать вам, что же реально нужно улучшить. Если окажется, что проблема в исключениях, лишь тогда есть смысл избавляться от них.

воскресенье, 24 ноября 2019 г.

Что использовать правильней: if(), или try-catch?


Например что использовать, когда нужно создавать колонку в таблице только в том случае, если такой колонки в ней нет?

Я могу, как написать код, который будет проверять, существует ли колонка, и лиш
потом добавлять без ошибок, так могу и без проверки пытаться добавить колонку, обернув метод в try-catch (если есть — перехватится исключение; если нет — колонка добавится).

Результат работы будет одинаковым.

И таких примеров можно привести массу, например можно проверять файлы на существование, и только потом делать копирование, а можно перехватывать исключения.

Какой метод более грамотный, или правильный?
    


Ответы

Ответ 1



Исключения позволяют сделать код чище и понятнее, поскольку с их помощью можно разделит выполнение действий и обработку ошибок. В книге Мартина «Чистый код» этот аспект описан самым первым. При этом, по моему опыту, надо именно разделять код: выносить блок try/catch в отдельны метод. Программист, который будет разбираться с вашей программой, скажет вам «спасибо». Эта конструкция весьма громоздка, даже в простой форме try/finally, и в середине большого метода озадачит кого угодно. Второй плюс исключений в том, что они позволяют передавать дополнительную информацию Функция atoi из C ничего не могла сказать о том, почему именно не удалось конвертировать строку в целое число. int result; result = atoi("123"); /* в result 123 */ . . . result = atoi("foo"); /* что в result? */ В таких языках, как Java и C# вы можете добавить в свой класс исключений необходимы свойства, сочетая какие-нибудь коды ошибок с контекстами вызова и ещё чем-нибудь. Пример: . . . catch (SqlException e) { Console.WriteLine("Ошибка '{2}' в строке {0} процедуры {1}", e.LineNumber, e.Procedure, e.Message); } . . . Разработчики, которые давно и прочно перешли на исключения, делают свой код ещё чище, не возвращая никаких кодов ошибок, в частности, пресловутого null: // Что будет, если в хранилище нет пользователя с указанным userid? // Вернёт null или сгенерирует исключение? User user = userRepository.GetById(userId); В настоящее время считается, что правильнее создавать исключение (за аргументам снова отсылаю к книге «Чистый код»). Если метод используется для проверки наличия пользователя, его рекомендуют переделать в форму TryX. Она неуклюжа, но уже привычна, по крайней мере, для программистов .NET: User user; if (userRepository.TryGetById(userId, out user)) { . . . } Что более ценно, она однозначна: смотря на код, вы не думаете: «а что, если такого пользователя нет?» Теперь посмотрим на ситуацию с другой стороны — а когда не надо использовать исключения На мой взгляд, тогда, когда они затрудняют понимание кода. Если ситуация не исключительная, тогда в тексте программы должна быть обычная проверка. Например, приложение для нового документа генерирует имена Untitled.foo, Untitled1.foo, Untitled2.foo и т.д. Та ситуация, что файл с таким именем уже существует, является вполне обычной, н исключительной, поэтому и реализовать код корректнее с помощью обычной проверки: public string GetNewDocumentName(string prefix) { var filename = prefix + ".foo"; if (!File.Exists(filename)) return filename; int suffix = 0; do { filename = prefix + (++suffix).ToString() + ".foo"; } while (File.Exists(filename)); return filename; } Этот код не только быстрее, чем аналогичный с использованием исключений, но, чт важнее, понятнее другим программистам, потому что неявно передаёт им дополнительную информацию: эта штука будет случаться регулярно, и мы к этому готовы. А вот, например, невероятная ситуация, что в папке скопилось 2 миллиарда untitled-файлов — несомненное исключение. public string GetNewDocumentName(string prefix) { var filename = prefix + ".foo"; if (!File.Exists(filename)) return filename; int suffix = 0; do { if (suffix == int.MaxValue) throw new InvalidOperationException("You're crazy!"); filename = prefix + (++suffix).ToString() + ".foo"; } while (File.Exists(filename)); return filename; } Такой код выглядит более запутанным. К счастью, мы можем часть проверок возложить на компилятор C#: public string GetNewDocumentName(string prefix) { var filename = prefix + ".foo"; if (!File.Exists(filename)) return filename; int suffix = 0; do checked { filename = prefix + (suffix++).ToString() + ".foo"; } while (File.Exists(filename)); return filename; } Откуда возникает ещё одно правило: код можно сделать чище, если знать язык, платформу, библиотеку, и опираться на их исключения. Выше я написал, что исключения выполняются медленнее, чем проверки, и хочу уточнит свою мысль: не надо опираться на производительность при принятии решения. Правильна передача смысла другому программисту, чистота кода — то, к чему следует стремится. Разница в производительности, хотя и существует, никогда не была настолько большой, чтобы пользователи её замечали. Ну, если только вы не пишите код для самого вложенного цикла в каком-нибудь графическом движке.

Ответ 2



Предварительная проверка быстрее работает и зачастую является более точной. Но только обработка исключений дает полную гарантию. Пример: простое создание файла. Ошибок тут возможно - море: в имени могут быть запрещенные символы (набор разрешенных символов зависит от файловой системы!); полный путь к файлу может оказаться слишком длинным; файл мог быть уже создан; может не быть доступа для создания файлов; диск может быть защищен от записи или вообще не поддерживать ее (CD-ROM тому пример). Все эти варианты можно проверить заранее - и выдать пользователю понятное сообщение на русском языке. Но есть ситуации, которые ни одна предварительная проверка не отловит: файл может быть создан другой программой сразу после проверки; файл может быть заблокирован антивирусом; если файл создается на сетевом ресурсе - может "отвалиться" сеть.

среда, 10 июля 2019 г.

Конструкция try/catch. Проблемы с FileInputStream

Требуется считать xls файл. Но try никогда не выполняется, а выполняется условие из catch. В итоге bb={“0,0,0,0”}. Не могу понять, что я делаю не так. Файл лежит в папке проекта.
Перемещение файла в другое место, изменение имени ничего не дало. Думала, что дело в том, что это xls, но даже с txt тоже самое.
Book bb = new Book(); String[] mas = bb.boob();
public class Book { public String[] data = new String[4];
public String[] boob() { try(FileInputStream fis = new FileInputStream("list.xls")) { //Workbook wb = new HSSFWorkbook(fis); for(int i=0; i<4; i++){ data[i] = "1"; } fis.close(); return data; } catch (IOException e){ String[] d ={"0","0","0","0"}; return d;} } }


Ответ

Надо было файл открывать используя assets. Например, fis = getAssets().open("list.xls");

четверг, 23 мая 2019 г.

блоки try-catch. Обработка исключений

правильно ли я понимаю, что если первое закрытие выбросит ошибку, то остальные даже и не вызовутся? подскажите как ПРАВИЛЬНО исправить, а главное почему именно так!
private void closeStatement() throws DaoException, SQLException { try { getByIdStmt.close(); } catch (Exception e) { throw new DaoException("Error! getByIdStmt is not closed"); } try { updateStmt.close(); } catch (Exception e) { throw new DaoException("Error! updateStmt is not closed"); } try { addStmt.close(); } catch (Exception e) { throw new DaoException("Error! addStmt is not closed"); } try { deleteStmt.close(); } catch (Exception e) { throw new DaoException("Error! deleteStmt is not closed"); } System.out.println("Statement close"); }


Ответ

Возможно, так:
private void closeStatement() throws DaoException, SQLException { ArrayList err = new ArrayList(); try { getByIdStmt.close(); } catch (Exception e) { err.add("getByIdStmt"); } try { updateStmt.close(); } catch (Exception e) { err.add("updateStmt"); } try { addStmt.close(); } catch (Exception e) { err.add("addStmt"); } try { deleteStmt.close(); } catch (Exception e) { err.add("deleteStmt"); } if (!err.isEmpty()) { throw new DaoException("Error! "+String.join(", ", err)+" not closed"); } System.out.println("Statement close"); }
Поочерёдно пытаемся закрыть все statement, неудачи собираем. Потом выбрасываем общее для всех ошибок исключение.

среда, 24 апреля 2019 г.

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

Как обработать исключение, которое возникает при попытке инициализировать значение за пределами массива, или при чтении из-за его пределов. Пробовал в catch писать "exception e", но оно не ловит.


Ответ

если это встроенный c++ массив то можно ставить ассерты перед каждым доступом к его элементу -
#define array_size 100 int v[array_size];
int i = 100; assert(i >= 0 && i < array_size); // бросит исключение v[i] = 123;
если у вас std::vector
то как уже сказали в комментариях - воспользоваться функцией членом std::vector::at которая гарантированно бросит исключение при выходе за пределы вектора.
std::vector v(5); v.at(5) = 1.0f; // бросит исключение

пятница, 12 апреля 2019 г.

Java. Задание занчения (final) переменной в try-блоке и ее дальнейшее использование и видимость

Проблема заключается в необходимости задания значения final переменной (connectionSocket2) в try-блоке. В дальнейшей части кода (в части run()) этого не видно и возникает как бы ошибка, что та переменная не определена:
final Socket connectionSocket; try { connectionSocket = welcomeSocket.accept(); }
The local variable connectionSocket2 may not have been initialized
убрать final не могу, так как (в части run()) дает ошибку
Cannot refer to the non-final local variable connectionSocket defined in an enclosing scope
Socket connectionSocket2=null; try { connectionSocket2 = welcomeSocket.accept(); } catch (IOException e2) { e2.printStackTrace(); } final Socket connectionSocket=connectionSocket2; try{connectionSocket2.close();}catch(IOException e1){e1.printStackTrace();}
service.submit(new Runnable() { public void run() { while (true) { BufferedReader inFromClient=null; DataOutputStream outToClient=null; try{ inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream())); outToClient = new DataOutputStream(connectionSocket.getOutputStream()); outToClient.writeBytes(inFromClient.readLine()); } catch(IOException ioe) {} }}});
Статической делать не могу - для каждого потока создается свое соединение, как бы свой экземпляр этой переменной.
Приведенный код работает, использовал вторую переменную для передачи ей значения и дальнейшего использования именной второй переменной. Но это выглядит плохо.
Как правильно, профессионально быть в этой ситуации? Модно ли как-то сказать компилятору, что переменная на самом деле уже определена в try блоке и ему нечего "волноваться"? (типа динамическая переменная, как в .Net)


Ответ

Ответ-вопросник и очередной наброс на медальку.
Итак, у вас было что-то вот такое:
public class ICanIntoSockets {
public static void main( String[] args ) throws IOException { ServerSocket welcomeSocket = new ServerSocket(10000); ExecutorService service = Executors.newCachedThreadPool();
doWork( welcomeSocket, service ); }
public static void doWork( ServerSocket welcomeSocket, ExecutorService service ) { try { while (true) { final Socket connectionSocket = welcomeSocket.accept();
service.execute( () -> { try ( Socket socket = connectionSocket; BufferedReader inFromClient = new BufferedReader( new InputStreamReader(socket.getInputStream())); DataOutputStream outToClient = new DataOutputStream( socket.getOutputStream())) {
outToClient.writeBytes(inFromClient.readLine()); } catch (IOException ioe) { ioe.printStackTrace(); } }); } } catch ( IOException ex ) { ex.printStackTrace(); } } }
но try - плохо, и торморзит на тысячах подключений (тесты где?), поэтому вы решили от него избавиться. Ява - убогий язык, в ней зачем-то придумали Checked Exceptions и напихали во все места в стандартной библиотеке, поэтому совсем без try - никак:
public static void doWork( ServerSocket welcomeSocket, ExecutorService service ) { while (true) { final Socket connectionSocket; try { connectionSocket = welcomeSocket.accept(); } catch (IOException ex) { ex.printStackTrace(); }
service.execute(() -> { try ( Socket socket = connectionSocket; // The local variable connectionSocket may not have been initialized BufferedReader inFromClient = new BufferedReader( new InputStreamReader(socket.getInputStream())); DataOutputStream outToClient = new DataOutputStream(socket.getOutputStream())) {
outToClient.writeBytes(inFromClient.readLine()); } catch (IOException ioe) { ioe.printStackTrace(); } }); } }
Зло загнано в угол в одной строчке кода! Но компилятор почему-то считает, что переменная connectionSocket может быть не инициализирована. Почему? Потому что есть путь выполнения программы, при которой она действительно не инициализируется: когда welcomeSocket.accept() выбрасывает исключение. Метод не возвращает значение - значение переменной не присваивается. Что же делать?
Не надо продолжать выполнение итерации, ваш код все равно не сможет работать дальше без клиентского сокета. Сделайте внутри catch-блока return, break, continue (в надежде, что следующий accept не выбросит исключение, что вряд ли). Если код непременно должен продолжаться дальше - присвойте connectionSocket null и где-то сделайте проверку.
Предложенный вариант с массивом - это либо то самое создание объектов и выделение памяти, с которым вы сражаетесь, либо потеря подключений и обработка одного подключения несколько раз, смотря где вы этот массив объявите.

понедельник, 18 марта 2019 г.

Влияет ли блок try на производительность кода в С++, если исключений не возникает?

Прошу прощения если я задаю глупый вопрос, но мне нужно знать точно. Если я пишу подобный код на С++:
int main() try { ..... } catch (const std::bad_alloc& e) { ... } ... catch (...) { cout << "Was throw exception" << endl; system("pause"); }
Будет ли скомпилированный в блоке try код отличным от такого же кода без блока try? Может ли блок try оказывать какое либо влияние на производительность помимо ситуаций когда происходят исключения?


Ответ

Откровенно говоря, не очень понятно, как именно провести эксперимент... Так что это не более чем иллюстрация, по которой трудно делать выводы.
На такой функции-пустышке на VC++ 2017 попробовал -
int main(int argc, const char * argv[]) { { muTimer mt; for(int i = 0; i < 1000000; ++i) { try { f(i); } catch(...) {} } cout << mt.stop().duration() << endl; } { muTimer mt; for(int i = 0; i < 1000000; ++i) { f(i); } cout << mt.stop().duration() << endl; } }
int total;
void f(int i) { total += i; }
Получилось примерно 4 миллисекунды на 0.6. Но, думаю, что при серьезных функциях соотношение будет куда ближе к 1:1 :)

среда, 9 января 2019 г.

Оператор try c ресурсами

Зачем нужен усовершенствованный и появившийся в JDK 7 оператор try-c-ресурсами?
try (спецификация_ресурса) { //использование ресурса {


Ответ

Оператор try-c-ресурсами реализует принцип автоматического управления ресурсами, целью которого является избежать, например, утечек памяти, в случаях когда ресурс по каким-то причинам не освобождается, если он больше не нужен.
Неудачный исход закрытия файла может привести к "утечкам памяти", поскольку неиспользуемые ресурсы оперативной памяти останутся выделенными.(стр 365)
try ( FileInputStream res = new FileInputStream(args[O])) {
//использование ресурса
}
Оператор try-c-ресурсами позволяет объявить и проинициализировать ресурс (в круглых скобках после оператора try), создав переменной ресурса локальный контекст в блоке try. По завершении этого блока переменная удаляется, а значит и ресурс автоматически закрывается.
Отсюда отпадает необходимость явного закрытия ресурса методом close() в блоке оператора finally