General exception ошибка java

Problem

When Sun Java version 6 update 12 or 13 is installed on a client system used to open a Remote Control session to a Remote Supervisor Adapter (RSA) II card, the session fails with the following message:

Application Error General Exception error message.

The error message will display java.lang.NullPointerException.

If the Remote Control window is closed, the RSA II web session continues to operate.

The symptom has been observed with Microsoft Internet Explorer and Mozilla Firefox browsers on Microsoft Windows clients connected to RSA equipped System x3550, x3650, and x3850 M2. It is likely that other client system Operating Systems (OS) and other RSA equipped systems are also affected.

Resolving The Problem

Source

RETAIN tip: H195390

Symptom

When Sun Java version 6 update 12 or 13 is installed on a client
system used to open a Remote Control session to a Remote Service
Adapter (RSA) II card, the session fails with the following
message:

  Application Error General Exception
error message.

The error message will display
java.lang.NullPointerException.

If the Remote Control window is closed, the RSA II web session
continues to operate.

The symptom has been observed with Microsoft Internet Explorer
and Mozilla Firefox browsers on Microsoft Windows clients connected
to RSA equipped System x3550, x3650, and x3850 M2. It is likely
that other client system OSs and other RSA equipped systems are
also affected.

Affected configurations

The system may be any of the following IBM Servers:

  • System x3755, type 7163, any model
  • System x3755, type 8877, any model
  • System x3800, type 8865, any model
  • System x3800, type 8866, any model
  • System x3850 M2, type 7141, any model
  • System x3850 M2, type 7144, any model
  • System x3850 M2, type 7233, any model
  • System x3850 M2, type 7234, any model
  • System x3850, type 8863, any model
  • System x3850, type 8864, any model
  • System x3950 M2, type 7141, any model
  • System x3950 M2, type 7233, any model
  • System x3950, type 8872, any model
  • System x3950, type 8878, any model
  • System x3200, type 4362, any model
  • System x3200, type 4363, any model
  • System x3250, type 4364, any model
  • System x3250, type 4365, any model
  • System x3400, type 7973, any model
  • System x3400, type 7974, any model
  • System x3400, type 7975, any model
  • System x3400, type 7976, any model
  • System x3500, type 7977, any model
  • System x3550, type 7978, any model
  • System x3650, type 1914, any model
  • xSeries 226, type 8488, any model
  • xSeries 226, type 8648, any model

The system is configured with one or more of the following IBM
Options:

  • Remote Supervisor Adapter II, option 13N0382
  • Remote Supervisor Adapter II, option 39Y9566
  • Remote Supervisor Adapter II, option 59P2984
  • Remote Supervisor Adapter II, option 59P2986
  • Remote Supervisor Adapter II, option 59P2987
  • Remote Supervisor Adapter II, option 59P2988
  • Remote Supervisor Adapter II, option 59P2989
  • Remote Supervisor Adapter II, option 59P2990
  • Remote Supervisor Adapter II, option 59P2991
  • Remote Supervisor Adapter II, option 59P2992
  • Remote Supervisor Adapter II, option 59P2993
  • Remote Supervisor Adapter II, option 59P2994
  • Remote Supervisor Adapter II, option 59P2995
  • Remote Supervisor Adapter II, option 59P2996
  • Remote Supervisor Adapter II, option 59P2997
  • Remote Supervisor Adapter II, option 73P9341

This tip is not software specific.

Workaround

Download and install the latest level of the RSA firmware for
the system.

The file is available on the ‘Software and device drivers —
IBM System x’ web page, at the following URL:

  • http://www.ibm.com/support/docview.wss?uid=psg1MIGR-4JTS2T

If the latest version of RSA II firmware available from the IBM
support site does not correct this issue, then downgrade the client
system to Java version 6 update 11. This version may be accessed
from the following URL:

  • http://java.sun.com/products/archive/

Additional information

This issue has been addressed in the common code base for RSA
firmware. It will be incorporated in subsequent RSA firmware
releases for each product as they occur.

Document Location

Worldwide

Operating System

System x:Operating system independent / None

Older System x:Operating system independent / None

System x Hardware Options:Operating system independent / None

[{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»HW20N»,»label»:»Older System x->xSeries 226″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU00ONM»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->59P2984″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU00OZR»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->59P2996″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU00OZS»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->59P2986″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU00OZT»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->59P2987″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU00OZU»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->59P2988″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU00OZV»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->59P2989″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU00OZW»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->59P2990″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU00OZX»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->59P2991″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU00OZY»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->59P2992″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU00OZZ»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->59P2994″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU00PAQ»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->59P2995″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU00PAR»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->59P2993″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU00PAS»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->59P2997″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU00SHW»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->13N0382″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU01BUQ»,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->73P9341″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU01ZJK»,»label»:»System x->System x3400->7973″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU01ZYN»,»label»:»System x->System x3400->7975″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU01ZYQ»,»label»:»System x->System x3400->7976″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU01ZYT»,»label»:»System x->System x3400->7974″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU02EFQ»,»label»:»System x->System x3800->8866″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU02EFV»,»label»:»System x->System x3850->8864″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU02EHK»,»label»:»System x->System x3950->8878″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU02EZZ»,»label»:»System x->System x3200->4362″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU02FAT»,»label»:»System x->System x3200->4363″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU02GIA»,»label»:»System x->System x3250->4364″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU02GIJ»,»label»:»System x->System x3250->4365″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU02YET»,»label»:»System x->System x3850 M2->7141″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU02YTZ»,»label»:»System x->System x3850 M2->7144″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU03EHM»,»label»:»System x->System x3950 M2->7141″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU03IIX»,»label»:»System x->System x3755->7163″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU03NTU»,»label»:»System x->System x3850 M2->7233″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QU03NTW»,»label»:»System x->System x3950 M2->7233″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU03NUA»,»label»:»System x->System x3850 M2->7234″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU054″,»label»:»Systems w\/TPS»},»Product»:{«code»:»QU03NUC»,»label»:»System x->System x3950 M2->7234″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QUOEDID»,»label»:»System x->System x3800->8865″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QUOEDIF»,»label»:»System x->System x3850->8863″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QUOEF1K»,»label»:»System x->System x3500->7977″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QUOEF4I»,»label»:»System x->System x3550->7978″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QUOEJ86″,»label»:»System x Hardware Options->Remote Supervisor Adapter (RSA)->Remote Supervisor Adapter II->39Y9566″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QUOEOZM»,»label»:»System x->System x3755->8877″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}},{«Type»:»HW»,»Business Unit»:{«code»:»BU016″,»label»:»Multiple Vendor Support»},»Product»:{«code»:»QUOER3U»,»label»:»System x->System x3950->8872″},»Platform»:[{«code»:»PF025″,»label»:»Platform Independent»}],»Line of Business»:{«code»:»»,»label»:»»}}]

Одна из неожиданных ошибок — NullPointerException, когда пользователь ничего не делал, а «оно само», при входе на портал онлайн банки использующего TumarCSP.

При этом кнопка Вход не появляется.

Application Error General Exception

Name:cptumar NullPointerException:nullОшибка Application Error General Exception Name: cptumar NullPointerException:null - Mhelp.kzОшибка возникла в ОС Windows 7 x64 и браузере Internet Exlorer 8.

Проблему вызвало обновление антивируса Avast до полной своей версии с подключением расширенных компонентов защиты.

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

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

Отключив антивирус, мы видим появление окна входа в систему.

Исправление ошибок БТА онлайн - Mhelp.kz

[nx_heading style=»coloredline» heading_tag=»h4″ size=»24″ align=»left»]От автора:[/nx_heading]

Если проблема решена, один из способов сказать «Спасибо» автору — здесь.

Если же проблему разрешить не удалось и появились дополнительные вопросы, задать их можно на нашем форуме, в нашей группе Whatsapp.

Или же, воспользуйтесь нашей услугой «Удаленная помощь» доверив решение проблемы специалисту.

[nx_box title=»Поделиться этой статьей» style=»glass» box_color=»#ED303C»]Если данная статья вам помогла и вы хотели бы в ответ помочь проекту Mhelp.kz, поделитесь этой статьей с другими:

[/nx_box]

Consider this simple program. The program has two files:

File Vehicle.java

class Vehicle {
    private int speed = 0;
    private int maxSpeed = 100;

    public int getSpeed()
    {
        return speed;
    }

    public int getMaxSpeed()
    {
        return maxSpeed;
    }

    public void speedUp(int increment)
    {
        if(speed + increment > maxSpeed){
            // Throw exception
        }else{
            speed += increment;
        }
    }

    public void speedDown(int decrement)
    {
        if(speed - decrement < 0){
            // Throw exception
        }else{
            speed -= decrement;
        }
    }
}

File HelloWorld.java

public class HelloWorld {

    /**
     * @param args
     */
    public static void main(String[] args) {

        Vehicle v1 = new Vehicle();
        Vehicle v2 = new Vehicle();

            // Do something

            // Print something useful, TODO
        System.out.println(v1.getSpeed());
    }

}

As you can see in the first class, I have added a comment («// throw exception») where I would like to throw an exception. Do I have to define my own class for exceptions or is there some general exception class in Java I can use?

Peter Mortensen's user avatar

asked Aug 4, 2011 at 13:51

Richard Knop's user avatar

Richard KnopRichard Knop

81.2k149 gold badges392 silver badges552 bronze badges

4

You could create your own Exception class:

public class InvalidSpeedException extends Exception {

  public InvalidSpeedException(String message){
     super(message);
  }

}

In your code:

throw new InvalidSpeedException("TOO HIGH");

answered Aug 4, 2011 at 13:55

Fortega's user avatar

0

You could use IllegalArgumentException:

public void speedDown(int decrement)
{
    if(speed - decrement < 0){
        throw new IllegalArgumentException("Final speed can not be less than zero");
    }else{
        speed -= decrement;
    }
}

answered Aug 4, 2011 at 13:53

Maurício Linhares's user avatar

Maurício LinharesMaurício Linhares

39.9k14 gold badges121 silver badges158 bronze badges

2

Well, there are lots of exceptions to throw, but here is how you throw an exception:

throw new IllegalArgumentException("INVALID");

Also, yes, you can create your own custom exceptions.

A note about exceptions. When you throw an exception (like above) and you catch the exception: the String that you supply in the exception can be accessed throw the getMessage() method.

try{
    methodThatThrowsException();
}catch(IllegalArgumentException e)
{
  e.getMessage();
}

Peter Mortensen's user avatar

answered Aug 4, 2011 at 13:52

RMT's user avatar

RMTRMT

7,0404 gold badges25 silver badges37 bronze badges

9

It really depends on what you want to do with that exception after you catch it. If you need to differentiate your exception then you have to create your custom Exception. Otherwise you could just throw new Exception("message goes here");

answered Aug 4, 2011 at 13:54

Vlad's user avatar

VladVlad

10.6k2 gold badges36 silver badges38 bronze badges

3

The simplest way to do it would be something like:

throw new java.lang.Exception();

However, the following lines would be unreachable in your code. So, we have two ways:


  1. Throw a generic exception at the bottom of the method.
  2. Throw a custom exception in case you don’t want to do 1.

Peter Mortensen's user avatar

answered Nov 30, 2016 at 11:14

Sudip Bhandari's user avatar

Sudip BhandariSudip Bhandari

2,1751 gold badge27 silver badges26 bronze badges

Java has a large number of built-in exceptions for different scenarios.

In this case, you should throw an IllegalArgumentException, since the problem is that the caller passed a bad parameter.

answered Aug 4, 2011 at 13:53

SLaks's user avatar

SLaksSLaks

869k176 gold badges1909 silver badges1967 bronze badges

1

You can define your own exception class extending java.lang.Exception (that’s for a checked exception — these which must be caught), or extending java.lang.RuntimeException — these exceptions does not have to be caught.

The other solution is to review the Java API and finding an appropriate exception describing your situation: in this particular case I think that the best one would be IllegalArgumentException.

Peter Mortensen's user avatar

answered Aug 4, 2011 at 13:55

omnomnom's user avatar

omnomnomomnomnom

8,9214 gold badges41 silver badges50 bronze badges

It depends. You can throw a more general exception, or a more specific exception. For simpler methods, more general exceptions are enough. If the method is complex, then, throwing a more specific exception will be reliable.

Peter Mortensen's user avatar

answered Aug 4, 2011 at 13:56

Abimaran Kugathasan's user avatar

Время на прочтение
7 мин

Количество просмотров 89K

Привет, Хабр! Представляю вашему вниманию перевод статьи Fixing 7 Common Java Exception Handling Mistakes автора Thorben Janssen.

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

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

Ошибка 1: объявление java.lang.Exception или java.lang.Throwable

Как вы уже знаете, вам нужно либо объявить, либо обработать проверяемое исключение. Но проверяемые исключения — это не единственные, которые вы можете указать. Вы можете использовать любой подкласс java.lang.Throwable в предложении throws. Таким образом, вместо указания двух разных исключений, которые выбрасывает следующий фрагмент кода, вы можете просто использовать исключение java.lang.Exception в предложении throws.

public void doNotSpecifyException() throws Exception {
doSomething();
}
public void doSomething() throws NumberFormatException, IllegalArgumentException {
// do something
}

Но это не значит, что вы должны это сделать. Указание Exeption или Throwable делает почти невозможным правильное обращение с ними при вызове вашего метода.Единственная информация, которую получает вызывающий вами метод, заключается в том, что что-то может пойти не так. Но вы не делитесь какой-либо информацией о каких-либо исключительных событиях, которые могут произойти. Вы скрываете эту информацию за обобщенными причинами выброса исключений.Становится еще хуже, когда ваше приложение меняется со временем. Выброс обобщенных исключений скрывает все изменения исключений, которые вызывающий должен ожидать и обрабатывать. Это может привести к нескольким непредвиденным ошибкам, которые необходимо найти в тестовом примере вместо ошибки компилятора.

Используйте конкретные классы

Гораздо лучше указать наиболее конкретные классы исключений, даже если вам приходится использовать несколько из них. Это сообщает вызывающему устройству, какие исключительные событий нужно обрабатывать. Это также позволяет вам обновить предложение throw, когда ваш метод выдает дополнительное исключение. Таким образом, ваши клиенты знают об изменениях и даже получают ошибку, если вы изменяете выбрасываемые исключения. Такое исключение намного проще найти и обработать, чем исключение, которое появляется только при запуске конкретного тестового примера.

public void specifySpecificExceptions() throws NumberFormatException, IllegalArgumentException {
doSomething();
}

Ошибка 2: перехват обобщенных исключений

Серьезность этой ошибки зависит от того, какой программный компонент вы реализуете, и где вы обнаруживаете исключение. Возможно, было бы хорошо поймать java.lang.Exception в основном методе вашего приложения Java SE. Но вы должны предпочесть поймать определенные исключения, если вы реализуете библиотеку или работаете над более глубокими слоями вашего приложения.

Это дает несколько преимуществ. Такой подход позволяет обрабатывать каждый класс исключений по-разному и не позволяет вам перехватывать исключения, которых вы не ожидали.

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

try {
doSomething();
} catch (NumberFormatException e) {
// handle the NumberFormatException
log.error(e);
} catch (IllegalArgumentException e) {
// handle the IllegalArgumentException
log.error(e);
}

Ошибка 3: Логирование и проброс исключений

Это одна из самых популярных ошибок при обработке исключений Java. Может показаться логичным регистрировать исключение там, где оно было брошено, а затем пробросить его вызывающему объекту, который может реализовать конкретную обработку для конкретного случая использования. Но вы не должны делать это по трем причинам:

1. У вас недостаточно информации о прецеденте, который хочет реализовать вызывающий объект вашего метода. Исключение может быть частью ожидаемого поведения и обрабатываться клиентом. В этом случае нет необходимости регистрировать его. Это добавит ложное сообщение об ошибке в файл журнала, который должен быть отфильтрован вашей операционной группой.

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

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

Регистрируйте исключение там, где вы его обрабатываете

Таким образом, лучше всего регистрировать исключение тогда, когда вы его обрабатываете. Как в следующем фрагменте кода. Метод doSomething генерирует исключение. Метод doMore просто указывает его, потому что у разработчика недостаточно информации для его обработки. Затем он обрабатывается в методе doEvenMore, который также записывает сообщение журнала.

public void doEvenMore() {
try {
doMore();
} catch (NumberFormatException e) {
// handle the NumberFormatException
} catch (IllegalArgumentException e) {
// handle the IllegalArgumentException
}
}
public void doMore() throws NumberFormatException, IllegalArgumentException {
doSomething();
}
public void doSomething() throws NumberFormatException, IllegalArgumentException {
// do something
}

Ошибка 4: использование исключений для управления потоком

Использование исключений для управления потоком вашего приложения считается анти-шаблоном по двум основным причинам:

Они в основном работают как оператор Go To, потому что они отменяют выполнение блока кода и переходят к первому блоку catch, который обрабатывает исключение. Это делает код очень трудным для чтения.

Они не так эффективны, как общие структуры управления Java. Как видно из названия, вы должны использовать их только для исключительных событий, а JVM не оптимизирует их так же, как и другой код.Таким образом, лучше использовать правильные условия, чтобы разбить свои циклы или инструкции if-else, чтобы решить, какие блоки кода должны быть выполнены.

Ошибка 5: удалить причину возникновения исключения

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

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

try {
doSomething();
} catch (NumberFormatException e) {
throw new MyBusinessException(e, ErrorCode.CONFIGURATION_ERROR);
} catch (IllegalArgumentException e) {
throw new MyBusinessException(e, ErrorCode.UNEXPECTED);
}

Ошибка 6: Обобщение исключений

Когда вы обобщаете исключение, вы ловите конкретный, например, NumberFormatException, и вместо этого генерируете неспецифическое java.lang.Exception. Это похоже, но даже хуже, чем первая ошибка, которую я описал в этой статье. Он не только скрывает информацию о конкретном случае ошибки на вашем API, но также затрудняет доступ.

public void doNotGeneralizeException() throws Exception {
try {
doSomething();
} catch (NumberFormatException e) {
throw new Exception(e);
} catch (IllegalArgumentException e) {
throw new Exception(e);
}
}

Как вы можете видеть в следующем фрагменте кода, даже если вы знаете, какие исключения может вызвать метод, вы не можете просто их поймать. Вам нужно поймать общий класс Exception и затем проверить тип его причины. Этот код не только громоздкий для реализации, но его также трудно читать. Становится еще хуже, если вы сочетаете этот подход с ошибкой 5. Это удаляет всю информацию об исключительном событии.

try {
doNotGeneralizeException();
} catch (Exception e) {
if (e.getCause() instanceof NumberFormatException) {
log.error("NumberFormatException: " + e);
} else if (e.getCause() instanceof IllegalArgumentException) {
log.error("IllegalArgumentException: " + e);
} else {
log.error("Unexpected exception: " + e);
}
}

Итак, какой подход лучший?

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

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

try {
doSomething();
} catch (NumberFormatException e) {
throw new MyBusinessException(e, ErrorCode.CONFIGURATION_ERROR);
} catch (IllegalArgumentException e) {
throw new MyBusinessException(e, ErrorCode.UNEXPECTED);
}

Ошибка 7: добавление ненужных преобразований исключений

Как я уже объяснял ранее, может быть полезно обернуть исключения в пользовательские, если вы установите исходное исключение в качестве причины. Но некоторые архитекторы переусердствуют и вводят специальный класс исключений для каждого архитектурного уровня. Таким образом, они улавливают исключение в уровне персистентности и переносят его в MyPersistenceException. Бизнес-уровень ловит и обертывает его в MyBusinessException, и это продолжается до тех пор, пока оно не достигнет уровня API или не будет обработано.

public void persistCustomer(Customer c) throws MyPersistenceException {
// persist a Customer
}
public void manageCustomer(Customer c) throws MyBusinessException {
// manage a Customer
try {
persistCustomer(c);
} catch (MyPersistenceException e) {
throw new MyBusinessException(e, e.getCode()); 
}
}
public void createCustomer(Customer c) throws MyApiException {
// create a Customer
try {
manageCustomer(c);
} catch (MyBusinessException e) {
throw new MyApiException(e, e.getCode()); 
}
}

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

Обязательно добавьте информацию

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

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

public void persistCustomer(Customer c) {
// persist a Customer
}
public void manageCustomer(Customer c) throws MyBusinessException {
// manage a Customer
throw new MyBusinessException(e, e.getCode()); 
}
public void createCustomer(Customer c) throws MyBusinessException {
// create a Customer
manageCustomer(c);
}

Исключения

  • Исключения
    • Введение
    • Иерархия исключений
      • Проверяемые и непроверяемые
      • Иерархия
        • Классификация
        • Error и Exception
    • Работа с исключениями
      • Обработка исключений
        • Правила try/catch/finally
        • Расположение catch блоков
        • Транзакционность
      • Делегирование
      • Методы и практики работы с исключительными ситуацими
        • Собственные исключения
        • Реагирование через re-throw
        • Не забывайте указывать причину возникновения исключения
        • Сохранение исключения
        • Логирование
        • Чего нельзя делать при обработке исключений
      • Try-with-resources или try-с-ресурсами
      • Общие советы
        • Избегайте генерации исключений, если их можно избежать простой проверкой
        • Предпочитайте Optional, если отсутствие значения — не исключительная ситуация
        • Заранее обдумывайте контракты методов
        • Предпочитайте исключения кодам ошибок и boolean флагам-признакам успеха
    • Исключения и статические блоки
    • Многопоточность и исключения
    • Проверяемые исключения и их необходимость
    • Заключение
    • Полезные ссылки

Введение

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

(c) Морис Уилкс.

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

    public List<String> readAll(String path) {
        BufferedReader br = new BufferedReader(new FileReader(path));
        String line;
        List<String> lines = new ArrayList<>();
        while ((line = br.readLine()) != null) {
            lines.add(line);
        }
        
        return lines;
    }

И это был бы вполне рабочий вариант, если бы не одно но: мы живём не в идеальном мире. Код, приведённый выше, рассчитан на то, что всё работает идеально: путь до файла указан верный, файл можно прочитать, во время чтения с файлом ничего не происходит, место хранения файла работает без ошибок и еще огромное количество предположений.

Однако, как показывает практика, мир не идеален, а нас повсюду преследуют ошибки и проблемы. Кто-то может указать путь до несуществующего файла, во время чтения может произойти ошибка, например, файл повреждён или удален в процессе чтения и т.д.

Игнорирование подобных ситуаций недопустимо, так как это ведет к нестабильно и непредсказуемо работающему коду.
Значит, на такие ситуации надо реагировать.

Самая простая реакция — это возвращать boolean — признак успеха или некоторый код ошибки, например, какое-то число.
Пусть, 0 — это код удачного завершения приложения, 1 — это аварийное завершение и т.д.
Мы получаем код возврата и уже на него реагируем.

Подобный ход имеет право на жизнь, однако, он крайне неудобен в повседневной разработке с её тысячами возможных ошибок и проблемных ситуаций.

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

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

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

Lots of newbie’s coming in from the C world complain about exceptions and the fact that they have to put exception handling all over the place—they want to just write their code. But that’s stupid: most C code never checks return codes and so it tends to be very fragile. If you want to build something really robust, you need to pay attention to things that can go wrong, and most folks don’t in the C world because it’s just too damn hard.
One of the design principles behind Java is that I don’t care much about how long it takes to slap together something that kind of works. The real measure is how long it takes to write something solid.

In Java you can ignore exceptions, but you have to willfully do it. You can’t accidentally say, «I don’t care.» You have to explicitly say, «I don’t care.»

(c) James Gosling.

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

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

В нашем примере с чтением содержимого файла, источником такого сообщения может являться BufferedReader или FileReader. Сообщению необходим получатель/обработчик, чтобы перехватить его и что-то сделать, как-то отреагировать.

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

Что значит «ломает поток выполнения программы»?

Представьте, что по дороге едет грузовик. Движение машины и есть поток выполнения программы. Вдруг водитель видит, что впереди разрушенный мост — исключение, ошибка. Теперь он либо поедет по объездной дороге, т.е перехватит и отреагирует на исключение, либо остановится и поездка будет завершена.

Объездная

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

Исключение также может хранить информацию о возникшей проблеме: причину, описание-комментарий и т.д.
Исходя из описания можно сказать, что исключение — это объект некоторого, специально для этого предназначенного, класса. Так как проблемы и ошибки бывают разного рода, их можно классифицировать и логически разделить, значит и классы исключений можно выстроить в некоторую иерархию.

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

Иерархия исключений

Ниже приведена иерархия исключений:

Exception Hierarchy

Картинка большая, чтобы лучше запоминалась.

Для начала разберем загадочные подписи checked и unchecked на рисунке.

Проверяемые и непроверяемые

Все исключения в Java делятся на два типа: проверяемые (checked) и непроверяемые исключения (unchecked).

Как видно на рисунке, java.lang.Throwable и java.lang.Exception относятся к проверяемым исключениям, в то время как java.lang.RuntimeException и java.lang.Error — это непроверяемые исключения.

Принадлежность к тому или иному типу каждое исключение наследует от родителя.
Это значит, что наследники java.lang.RuntimeException будут unchecked исключениями, а наследники java.lang.Exceptionchecked.

Что это за разделение?

В первую очередь напомним, что Java — это компилируемый язык, а значит, помимо runtime(время выполнения кода), существует ещё и compile-time(то, что происходит во время компиляции).

Так вот проверяемые исключения — это исключения, на которые разработчик обязан отреагировать, т.е написать обработчики, и наличие этих обработчиков будет проверено на этапе компиляции. Ваш код не будет скомпилирован, если какое-то проверяемое исключение не обработано, компилятор этого не допустит.

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

В чём же смысл этого разделения на проверяемые и непроверяемые исключения?

Я думаю так: проверяемые исключения в Java — это ситуации, которые разработчик никак не может предотвратить и исключение является одним из вариантов нормальной работы кода.

Например, при чтении файла требуется обрабатывать java.io.FileNotFoundException и java.io.IOException, которые является потомками java.io.Exception.

Потому, что отсутствие файла или ошибка работы с вводом/выводом — это вполне допустимая ситуация при чтении.

С другой стороны, java.lang.RuntimeException — это скорее ошибки разработчика.
Например, java.lang.NullPointerException — это ошибка обращения по null ссылке, данную ситуацию можно предотвратить: проверить ссылку на null перед вызовом.

Представьте, что вы едете по дороге, так вот предупредительные знаки — это проверяемые исключения. Например, знак «Осторожно, дети!» говорит о том, что рядом школа и дорогу может перебежать ребенок. Вы обязаны отреагировать на это, не обязательно ребенок перебежит вам дорогу, но вы не можете это проконтролировать, но в данном месте — это нормальная ситуация, ведь рядом школа.

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

Разделение на проверяемые и непроверяемые исключения существует только в Java, в других языках программирования, таких как Scala, Groovy, Kotlin или Python, все исключения непроверяемые.

Это довольно холиварная тема и свои мысли по ней я изложу в конце статьи.

Теперь рассмотрим непосредственно иерархию исключений.

Иерархия

Итак, корнем иерархии является java.lang.Throwable, у которого два наследника: java.lang.Exception и java.lang.Error.
В свою очередь java.lang.Exception является родительским классом для java.lang.RuntimeException.

Занятно, что класс java.lang.Throwable назван так, как обычно называют интерфейсы, что иногда вводит в заблуждение новичков. Однако помните, что это класс! Запомнить это довольно просто, достаточно держать в уме то, что исключения могут содержать состояние (например, информация о возникшей проблеме).

Так как в Java все классы являются наследниками java.lang.Object, то и исключения (будучи тоже классами) наследуют все стандартные методы, такие как equals, hashCode, toString и т.д.

Раз мы работаем с классами, то можно с помощью наследования создавать свои собственные иерархии исключений, добавляя в них какое-то специфическое поведение и состояние.

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

Классификация

Каждый тип исключения отвечает за свою область ошибок.

  1. java.lang.Exception

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

    Это проверяемые исключения, мы обязаны на такие исключения реагировать, это будет проверено на этапе компиляции.

    Пример: java.io.IOException, java.io.FileNotFoundException.

  2. java.lang.RuntimeException

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

    Это непроверяемые исключения, реагировать на них или нет решает разработчик.

    Пример: java.lang.NullPointerException.

  3. java.lang.Error

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

    Это непроверяемые исключения, реагировать на них или нет решает разработчик.

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

Теперь перейдем к вопросу: в чем же разница между java.lang.Error и java.lang.Exception?

Error и Exception

Все просто. Исключения java.lang.Error — это более серьезная ситуация, нежели java.lang.Exception.
Это серьезные проблемы в работе приложения, которые тяжело исправить, либо вообще неясно, можно ли это сделать.

Это не просто исключительная ситуация — это ситуация, в которой работоспособность всего приложения под угрозой! Например, исключение java.lang.OutOfMemoryError, сигнализирующее о том, что кончается память или java.lang.StackOverflowError – переполнение стека вызовов, которое можно встретить при бесконечной рекурсии.

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

Т.е разница — в логическом разделении.

Поэтому, java.lang.Error и его наследники используются только для критических ситуаций.

Работа с исключениями

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

Корнем иерархии является класс java.lang.Throwable, т.е. что-то «бросаемое».
А раз исключения бросаются, то для обработки мы будем ловить их!

В Java исключения ловят и обрабатывают с помощью конструкции try/catch/finally.

При заключении кода в один или несколько блоков try указывается потенциальная возможность выбрасывания исключения в этом месте, все операторы, которые могут сгенерировать исключение, помещаются в этом блоке.

В блоках catch перечисляются исключения, на которые решено реагировать. Тут определяются блоки кода, предназначенные для решения возникших проблем. Это и есть объявление тех самых получателей/обработчиков исключений.

Пример:

public class ExceptionHandling {
    public static void main(String[] args) {
        try {
             // код
        } catch(FileNotFoundException fnf) {
            // обработчик на FileNotFoundException
        }
    }
}

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

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

Точно также и в Java, ставя фильтр на java.lang.RuntimeException вы ловите не только java.lang.RuntimeException, но и всех его наследников! Ведь эти потомки — это тоже runtime ошибки!

В блоке finally определяется код, который будет всегда выполнен, независимо от результата выполнения блоков try/catch. Этот блок будет выполняться независимо от того, выполнился или нет блок try до конца, было ли сгенерировано исключение или нет, и было ли оно обработано в блоке catch или нет.

Пример:

public class ExceptionHandling {
    public static void main(String[] args) {
        try {
             // some code
        } catch(FileNotFoundException fnf) {
            // обработчик 1
        } catch(RuntimeException re) {
            // обработчик 2
        } finally {
            System.out.println("Hello from finally block.");
        }
    }
}

В примере выше объявлен try блок с кодом, который потенциально может сгенерировать исключения, после try блока описаны два обработчика исключений, на случай генерации FileNotFoundException и на случай генерации любого RuntimeException.
Объект исключения доступен по ссылке exception.

Правила try/catch/finally

  1. Блок try находится перед блоком catch или finally. При этом должен присутствовать хотя бы один из этих блоков.

  2. Между try, catch и finally не может быть никаких операторов.

  3. Один блок try может иметь несколько catch блоков. В таком случае будет выполняться первый подходящий блок.

    Поэтому сначала должны идти более специальные блоки обработки исключений, а потом уже более общие.

  4. Блок finally будет выполнен всегда, кроме случая, когда JVM преждевременно завершит работу или будет сгенерировано исключение непосредственно в самом finally блоке.

  5. Допускается использование вложенных конструкций try/catch/finally.

    public class ExceptionHandling {
        public static void main(String[] args) {
            try {
                 try {
                    // some code
                } catch(FileNotFoundException fnf) {
                    // обработчик 1
                }
            } catch(RuntimeException re) {
                // обработчик 2
            } finally {
                System.out.println("Hello from finally block.");
            }
        }
    }

Вопрос:

Каков результат выполнения примера выше, если в блоке try не будет сгенерировано ни одного исключения?

Ответ:

Будет выведено на экран: «Hello from finally block.».

Так как блок finally выполняется всегда.


Вопрос:

Теперь немного видоизменим код, каков результат выполнения будет теперь?

public class ExceptionHandling {
  public static void main(String[] args) {
    try {
         return;
    } finally {
         System.out.println("Hello from finally block");
    }
  }
}

Ответ:

На экран будет выведено: Hello from finally block.


Вопрос:

Плохим тоном считается прямое наследование от java.lang.Throwable.
Это строго не рекомендуется делать, почему?

Ответ:

Наследование от наиболее общего класса, а в данном случае от корневого класса иерархии, усложняет обработку ваших исключений. Проблему надо стараться локализовать, а не делать ее описание/объявление максимально общим. Согласитесь, что java.lang.IllegalArgumentException говорит гораздо больше, чем java.lang.RuntimeException. А значит и реакция на первое исключение будет более точная, чем на второе.


Далее приводится несколько примеров перехвата исключений разных типов:

Обработка java.lang.RuntimeException:

try {
    String numberAsString = "one";
    Double res = Double.valueOf(numberAsString);
} catch (RuntimeException re) {
    System.err.println("Error while convert string to double!");
}

Результатом будет печать на экран: Error while convert string to double!.

Обработка java.lang.Error:

try {
    throw new Error();
} catch (RuntimeException re) {
    System.out.println("RuntimeException");
} catch (Error error) {
    System.out.println("ERROR");
}

Результатом будет печать на экран: ERROR.

Расположение catch блоков

Как уже было сказано, один блок try может иметь несколько catch блоков. В таком случае будет выполняться первый подходящий блок.

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

Рассмотрим ситуацию, когда некоторый используемый нами метод может выбросить два разных исключения:

void method() throws Exception {
    if (new Random((System.currentTimeMillis())).nextBoolean()) {
        throw new Exception();
    } else {
       throw new IOException();
    }
}

Конструкция new Random((System.currentTimeMillis())).nextBoolean() генерирует нам случайное значение false или true.

Для обработки исключений этого метода написан следующий код:

try {
  method();
} catch (Exception e) {
  // Обработчик 1
} catch (IOException e) {
  // Обработчик 2
}

Все ли хорошо с приведенным выше кодом?
Нет, код выше неверен, так как обработчик java.io.IOException в данном случае недостижим. Все дело в том, что первый обработчик, ответсвенный за Exception, перехватит все исключения, а значит не может быть ситуации, когда мы сможем попасть во второй обработчик.

Снова вспомним пример с мукой, приведенный в начале.

Так вот песчинка, которую мы ищем, это и есть наше исключение, а каждый фильтр это catch блок.

Если первым установлен фильтр ловить все, что является Exception и его потомков, то до фильтра ловить все, что является IOException и его потомков ничего не дойдет, так как верхний фильтр уже перехватит все песчинки.

Отсюда следует правило:

Сначала должны идти более специальные блоки обработки исключений, а потом уже более общие.

А что если на два разных исключения предусмотрена одна и та же реакция? Написание двух одинаковых catch блоков не приветствуется, ведь дублирование кода — это зло.

Поэтому допускается объединить два catch блока с помощью |:

try {
    method2();
} catch (IllegalArgumentException | IndexOutOfBoundsException e) {
    // Обработчик
}

Вопрос:

Есть ли способ перехватить все возможные исключения?

Ответ:

Есть! Если взглянуть еще раз на иерархию, то можно отметить, что java.lang.Throwable является родительским классом для всех исключений, а значит, чтобы поймать все, необходимо написать что-то в виде:

try {
  method();
} catch (Throwable t) {
  // Обработчик
}

Однако, делать так не рекомендуется, что наталкивает на следующий вопрос.


Вопрос:

Почему перехватывать java.lang.Throwable — плохо?

Ответ:

Дело в том, что написав:

try {
  method();
} catch (Throwable t) {
  // catch all
}

Будут перехвачены абсолютно все исключения: и java.lang.Exception, и java.lang.RuntimeException, и java.lang.Error, и все их потомки.

И как реагировать на все? При этом надо учесть, что обычно на java.lang.Error исключений вообще не ясно как реагировать. А значит, мы можем неверно отреагировать на исключение и вообще потерять данные. А ловить то, что не можешь и не собирался обрабатывать — плохо.

Поэтому перехватывать все исключения — плохая практика.


Вопрос-Тест:

Что будет выведено на экран при запуске данного куска кода?

public static void main(String[] args) {
    try {
        try {
            throw new Exception("0");
        } finally {
            if (true) {
                throw new IOException("1");
            }

            System.err.println("2");
        }
    } catch (IOException ex) {
        System.err.println(ex.getMessage());
    } catch (Exception ex) {
        System.err.println("3");
        System.err.println(ex.getMessage());
    }
}

Ответ:

При выполнении данного кода выведется «1».
Давайте разберем почему.

Мы кидаем исключение во вложенном try блоке: throw new Exception("0");.

После этого поток программы ломается и мы попадаем в finally блок:

if (true) {
    throw new IOException("1");
}

System.err.println("2");

Здесь мы гарантированно зайдем в if и кинем уже новое исключение: throw new IOException("1");.
При этом вся информация о первом исключении будет потеряна! Ведь мы никак не отреагировали на него, а в finally блоке и вовсе ‘перезатерли’ новым исключением.

На try, оборачивающий наш код, настроено два фильтра: первый на IOException, второй на Exception.

Так как порядок расположения задан так, что мы прежде всего смотрим на IOException, то и сработает этот фильтр, который выполнит следующий код:

System.err.println(ex.getMessage());

Именно поэтому выведется 1.


Транзакционность

Важным моментом, который нельзя пропустить, является то, что try блок не транзакционный.

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

Что это значит?

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

По сути именно поэтому и существует finally блок, так как туда, как уже было сказано выше, мы зайдем в любом случае, то там и освобождают выделенные ресурсы.


Вопрос:

Работа с объектами из try блока в других блоках невозможна:

public class ExceptionExample {
    public static void main(String[] args) {
        try {
            String line = "hello";
        } catch (Exception e) {
            System.err.println(e);
        }

        // Compile error
        System.out.println(line); // Cannot resolve symbol `line`
    }
}

Почему?

Ответ:

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

Ведь могло быть сгенерировано исключение. Тогда после места, где было сгенерировано исключение, оставшиеся действия не будут выполнены, а значит возможна ситуация, когда объект не будет создан. Следовательно и работать с ним нельзя.


Вернемся к примеру с грузовиком, чтобы объяснить все вышесказанное.

Объездная

Объездная здесь — это catch блок, реакция на исключительную ситуацию. Если добавить еще несколько объездных дорог, несколько catch блоков, то водитель выберет наиболее подходящий путь, наиболее подходящий и удобный catch блок, что объясняет важность расположения этих блоков.

Транзакционность на этом примере объясняется тем, что если до этого водитель где-то оплатил проезд по мосту, то деньги ему автоматически не вернутся, необходимо будет написать в поддержку или куда-то пожаловаться на управляющую компанию.

Делегирование

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

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

Пример:

// Код написан только для ознакомительной цели, не стоит с него брать пример!
String readLine(String path) throws IOException {
    BufferedReader br = new BufferedReader(...);
    String line = br.readLine();

    return line;
}

Таким образом обеспечивается передача объявленного исключения в место вызова метода. И то, как на него реагировать уже становится заботой вызывающего этот метод.
Поэтому реагировать и писать обработчики на те исключения, которые мы делегировали, внутри метода уже не надо.

Механизм throws введен для проброса проверяемых исключений.

Разумеется, с помощью throws можно описывать делегирование как проверяемых, так и непроверяемых исключений.
Однако перечислять непроверяемые не стоит, такие исключения не контролируются в compile time.

Перечисление непроверяемых исключений бессмысленно, так как это примерно то же самое, что перечислять все, что может с вами случиться на улице.

Теперь пришла пора рассмотреть методы обработки исключительных ситуаций.

Методы и практики работы с исключительными ситуацими

Главное и основное правило при работе с исключениями звучит так:

На исключения надо либо реагировать, либо делегировать, но ни в коем случае не игнорировать.

Определить когда надо реагировать, а когда делегировать проще простого. Задайте вопрос: «Знаю ли я как реагировать на это исключение?».

Если ответ «да, знаю», то реагируйте, пишите обработчик и код, отвечающий за эту реакцию, если не знаете что делать с исключением, то делегируйте вызывающему коду.

Собственные исключения

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

Например, пусть есть некоторый справочник:

class Catalog {
    Person findPerson(String name);
}

В данном случае нам надо обработать ситуации, когда name является null, когда в каталоге нет пользователя с таким именем.

Если генерировать на все ситуации java.lang.Exception, то обработка ошибок будет крайне неудобной.
Более того, хотелось бы явно выделить ошибку, связанную с тем, что пользователя такого не существует.
Очевидно, что стандартное исключение для этого случая не существует, а значит вполне логично создать свое.

class PersonNotFoundException extends RuntimeException {
    private String name;

    // some code
}

Обратите внимание, что имя Person, по которому в каталоге не смогли его найти, выделено в свойство класса name.

Теперь при использовании этого метода проще реагировать на различные ситуации, такие как null вместо имени, а проблему с отсутствием Person в каталоге можно отдельно вынести в свой catch блок.

Реагирование через re-throw

Часто бывает необходимо перехватить исключение, сделать запись о том, что случилось (в файл лога, например) и делегировать его вызывающему коду.
Как уже было сказано выше, в рамках конструкции try/catch/finally можно сгенерировать другое исключение.

Такой подход называется re-throw.

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

Как это выглядит на практике:

try {
    Reader readerConf = ....
    readerConf.readConfig();
} catch(IOException ex) {
    System.err.println("Log exception: " + ex);
    throw new ConfigException(ex);
}

Во время чтения конфигурационного файла произошло исключение java.io.IOException, в catch блоке оно было перехвачено, сделана запись в консоль о проблеме, после чего было создано новое, более конкретное, исключение ConfigException, с указанием причины (перехваченное исключение, ссылка на которое ex) и оно было проброшено дальше.

По итогу, из метода с приведенным кодом, в случае ошибки чтения конфигурации, будет выброшено ConfigException.

Для чего мы здесь так поступили?

Это полезно для более гибкой обработки исключений.
В примере выше чтение конфигурации генерирует слишком общее исключение, так как java.io.IOException это довольно общее исключение, но проблема в примере выше понятна: работа с этим конфигурационным файлом невозможна.

Значит и сообщить лучше именно как о том, что это не абстрактный java.io.IOException, а именно ConfigException. При этом, так как перехваченное исключение было передано новому в конструкторе, т.е. указалась причина возникновения (cause) ConfigException, то при выводе на консоль или обработке в вызывающем коде будет понятно почему ConfigException был создан.

Также, можно было добавить еще и текстовое описание к сгенерированному ConfigException, более подробно описывающее произошедшую ситуацию.

Еще одной важной областью применения re-throw бывает преобразование проверяемых исключений в непроверяемые.
В Java 8 даже добавили исключение java.io.UncheckedIOException, которое предназначено как раз для того, чтобы сделать java.io.IOException непроверяемым, обернуть в unchecked обертку.

Пример:

try {
    Reader readerConf = ....
    readerConf.readConfig();
} catch(IOException ex) {
    System.err.println("Log exception: " + ex);
    throw new UncheckedIOException(ex);
}

Не забывайте указывать причину возникновения исключения

В предыдущем пункте мы создали собственное исключение, которому указали причину: перехваченное исключение, java.io.IOException.

Чтобы понять как это работает, давайте рассмотрим наиболее важные поля класса java.lang.Throwable:

public class Throwable implements Serializable {

    /**
     * Specific details about the Throwable.  For example, for
     * {@code FileNotFoundException}, this contains the name of
     * the file that could not be found.
     *
     * @serial
     */
    private String detailMessage;

    // ...


    /**
     * The throwable that caused this throwable to get thrown, or null if this
     * throwable was not caused by another throwable, or if the causative
     * throwable is unknown.  If this field is equal to this throwable itself,
     * it indicates that the cause of this throwable has not yet been
     * initialized.
     *
     * @serial
     * @since 1.4
     */
    private Throwable cause = this;

    // ...
}

Все исключения, будь то java.lang.RuntimeException, либо java.lang.Exception имеют необходимые конструкторы для инициализации этих полей.

При создании собственного исключения не пренебрегайте этими конструкторами!

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

Представьте, что код, использующий ваш метод также перехватил ConfigException, пробросив какое-то своё исключение, а это исключение снова кто-то перехватил и пробросил свое. Получается, что истинная причина будет просто потеряна! Однако, если каждый будет указывать cause, истинного виновника возникновения исключения, то вы всегда сможете обнаружить по этому стеку виновника.

Для получения причины возникновения исключения существует метод getCause.

public class ExceptionExample {
    public Config readConfig() throws ConfigException { // (1)
      try {
        Reader readerConf = ....;
        readerConf.readConfig();
      } catch (IOException ex) {
          System.err.println("Log exception: " + ex);
          throw new ConfigException(ex); // (2)
      }
    }

    public void run() {
        try {
            Config config = readConfig(); // (3)
        } catch (ConfigException e) {
            Throwable t = e.getCause(); // (4)
        }
    }
}

В коде выше:

  1. В строке (1) объявлен метод readConfig, который может выбросить ConfigException.
  2. В строке (2) создаётся исключение ConfigException, в конструктор которого передается IOException — причина возникновения.
  3. readConfig вызывается в (3) строке кода.
  4. А в (4) вызван метод getCause который и вернёт причину возникновения ConfigExceptionIOException.

Сохранение исключения

Исключения необязательно генерировать, пробрасывать и так далее.
Выше уже упоминалось, что исключение — это Java-объект. А значит, его вполне можно присвоить переменной или свойству класса, передать по ссылке в метод и т.д.

class Reader {
    // A holder of the last IOException encountered
    private IOException lastException;

    // some code
    
    public void read() {
        try {
            Reader readerConf = ....
            readerConf.readConfig();
        } catch(IOException ex) {
            System.err.println("Log exception: " + ex);
            lastException = ex;
        }
    }
}

Генерация исключения это довольно дорогостоящая операция. Кроме того, исключения ломают поток выполнения программы. Чтобы не ломать поток выполнения, но при этом иметь возможность в дальнейшем отреагировать на исключительную ситуацию можно присвоить ее свойству класса или переменой.

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

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

Например, идет запись в базу данных тысячу строк построчно.
Из них 100 записей происходит с ошибкой.
Эти исключения складываются в список, а после этот список передается специальному методу, который по каждой ситуации из списка как-то отреагирует.
Т.е пока делаете операцию, копите ошибки, а потом уже реагируете.

Это похоже на то, как опрашивают 1000 человек, а негативные отзывы/голоса записывают, после чего реагируют на них. Согласитесь, было бы глупо после каждого негативного отзыва осуществлять реакцию, а потом снова возвращаться к толпе и продолжать опрос.

class Example {
    private List<Exception> exceptions;

    // some code
    
    public void parse(String s) {
        try {
            // do smth
        } catch(Exception ex) {
            exceptions.add(ex);
        }
    }

    private void handleExceptions()  {
        for(Exception e : exceptions) {
            System.err.println("Log exception: " + e);
        }
    }
}

Логирование

Когда логировать исключение?

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

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

Поэтому не стоит преждевременно логировать исключение, например:

/**
 * Parse date from string to java.util.Date.
 * @param date as string 
 * @return Date object.
 */
public static Date from(String date) {
    try {
        DateFormat format = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH);
        return format.parse(date);
    }  catch (ParseException e) {
        logger.error("Can't parse ")
        throw e;
    }
}

Здесь ParseException является частью ожидаемой работы, в ситуациях, когда строка содержит невалидные данные.
Раз происходит делегирование исключения выше (с помощью throw), то и там, где его будут обрабатывать и лучше всего логировать, а эта запись в лог будет избыточной. Хотя бы потому, что в месте обработки исключения его тоже залогируют!

Подробнее о логировании.

Чего нельзя делать при обработке исключений

  1. Старайтесь не игнорировать исключения.

    В частности, никогда не пишите подобный код:

        try {
            Reader readerConf = ....
            readerConf.readConfig();
        } catch(IOException e) {
            e.printStackTrace();
        }
  2. Не следует писать ‘универсальные’ блоки обработки исключений.

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

    Также программный код может измениться, а ‘универсальный’ обработчик исключений будет продолжать обрабатывать новые типы исключений одинаково.

    Поэтому таких ситуаций лучше не допускать.

  3. Старайтесь не преобразовывать более конкретные исключения в более общие.

    В частности, например, не следует java.io.IOException преобразовывать в java.lang.Exception или в java.lang.Throwable.

    Чем с более конкретными исключениями идет работа, тем проще реагировать и принимать решения об их обработке.

  4. Старайтесь не злоупотреблять исключениями.

    Если исключение можно не допустить, например, дополнительной проверкой, то лучше так и сделать.

    Например, можно обезопасить себя от java.lang.NullPointerException простой проверкой:

      if(ref != null) {
          // some code
      }

Try-with-resources или try-с-ресурсами

Как уже говорилось выше про finally блок, код в нем выполняется в любом случае, что делает его отличным кандидатом на место по освобождению ресурсов, учитывая нетранзакционность блока try.

Чаще всего за закрытие ресурса будет отвечать код, наподобие этого:

try {
    // code
} finally {
    resource.close();
}

Освобождение ресурса (например, освобождение файлового дескриптора) — это поведение.

А за поведение в Java отвечают интерфейсы.

Это наталкивает на мысль, что нужен некоторый общий интерфейс, который бы реализовывали все классы, для которых необходимо выполнить какой-то код по освобождению ресурсов, т.е выполнить ‘закрытие’ в finally блоке и еще удобнее, если бы этот однообразный finally блок не нужно было писать каждый раз.

Поэтому, начиная с Java 7, была введена конструкция try-with-resources или TWR.

Для этого объявили специальный интерфейс java.lang.AutoCloseable, у которого один метод:

void close() throws Exception;

Все классы, которые будут использоваться так, как было описано выше, должны реализовать или java.lang.Closable, или java.lang.AutoCloseable.

В качестве примера, напишем код чтения содержимого файла и представим две реализации этой задачи: используя и не используя try-with-resources.

Без использования try-with-resources (пример ниже плох и служит только для демонстрации объема необходимого кода):

BufferedReader br = null;
try {
    br = new BufferedReader(new FileReader(path));
    // read from file
} catch (IOException e) {
    // catch and do smth
} finally {
    try {
        if (br != null) {
            br.close();
        }
    } catch (IOException ex) {
        // catch and do smth
    }
}

А теперь то же самое, но в Java 7+:

try (FileReader fr = new FileReader(path);
    BufferedReader br = new BufferedReader(fr)) {
         // read from file
} catch (IOException e) {
         // catch and do smth
}

По возможности пользуйтесь только try-with-resources.

Помните, что без реализации java.lang.Closable или java.lang.AutoCloseable ваш класс не будет работать с try-with-resources так, как показано выше.


Вопрос:

Получается, что используя TWR мы не пишем код для закрытия ресурсов, но при их закрытии может же тоже быть исключение! Что произойдет?

Ответ:

Точно так же, как и без TWR, исключение выбросится так, будто оно было в finally-блоке.

Помните, что TWR, грубо говоря, просто добавляет вам блок кода вида:

finally {
    resource.close();
}

Вопрос:

Является ли безопасной конструкция следующего вида?

try (BufferedWriter bufferedWriter
        = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a")))) {
}

Ответ:

Не совсем, если конструктор OutputStreamWriter или BufferedWriter выбросит исключение, то FileOutputStream закрыт не будет.

Пример, демонстрирующий это:

public class Main {
    public static void main(String[] args) throws Exception {
        try (ThrowingAutoCloseable throwingAutoCloseable
                     = new ThrowingAutoCloseable(new PrintingAutoCloseable())) { // (1)
        }
    }

    private static class ThrowingAutoCloseable implements AutoCloseable { // (2)
        private final AutoCloseable other;

        public ThrowingAutoCloseable(AutoCloseable other) {
            this.other = other;
            throw new IllegalStateException("I always throw"); // (3)
        }

        @Override
        public void close() throws Exception {
            try {
                other.close(); // (4)
            } finally {
                System.out.println("ThrowingAutoCloseable is closed");
            }
        }
    }

    private static class PrintingAutoCloseable implements AutoCloseable { // (5)
        public PrintingAutoCloseable() {
            System.out.println("PrintingAutoCloseable created"); // (6)
        }

        @Override
        public void close() {
            System.out.println("PrintingAutoCloseable is closed"); // (7)
        }
    }
}
  1. В строке (1) происходит заворачивание одного ресурса в другой, аналогично new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a"))).
  2. ThrowingAutoCloseable (2) — такой AutoCloseable, который всегда бросает исключение (3), в (4) производится попытка закрыть полученный в конструкторе AutoCloseable.
  3. PrintingAutoCloseable (5) — AutoCloseable, который печатает сообщения о своём создании (6) и закрытии (7).

В результате выполнения этой программы вывод будет примерно следующим:

PrintingAutoCloseable created
Exception in thread "main" java.lang.IllegalStateException: I always throw
    at ru.misc.Main$ThrowingAutoCloseable.<init>(Main.java:19)
    at ru.misc.Main.main(Main.java:9)

Как видно, PrintingAutoCloseable закрыт не был!


Вопрос:

В каком порядке закрываются ресурсы, объявленные в try-with-resources?

Ответ:

В обратном.

Пример:

public class Main {
    public static void main(String[] args) throws Exception {
        try (PrintingAutoCloseable printingAutoCloseable1 = new PrintingAutoCloseable("1");
             PrintingAutoCloseable printingAutoCloseable2 = new PrintingAutoCloseable("2");
             PrintingAutoCloseable printingAutoCloseable3 = new PrintingAutoCloseable("3")) {
        }
    }

    private static class PrintingAutoCloseable implements AutoCloseable {
        private final String id;

        public PrintingAutoCloseable(String id) {
            this.id = id;
        }

        @Override
        public void close() {
            System.out.println("Closed " + id);
        }
    }
}

Вывод:

Closed 3
Closed 2
Closed 1

Общие советы

Избегайте генерации исключений, если их можно избежать простой проверкой

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

Помните, что если исключение можно не допустить, то лучше так и сделать.

Отсюда следует первый совет: не брезгуйте дополнительными проверками.

  1. Не ловите IllegalArgumentException, NullPointerException, ArrayIndexOutOfBoundsException и подобные.
    Потому что эти ошибки — это явная отсылка к тому, что где-то недостает проверки.
    Обращение по индексу за пределами массива, NullPointerException, все эти исключения — это ошибка разработчика.
  2. Вводите дополнительные проверки на данные, дабы избежать возникновения непроверяемых исключения

Например, запретите вводить в поле возраста не числовые значения, проверяйте ссылки на null перед обращением и т.д.

Предпочитайте Optional, если отсутствие значения — не исключительная ситуация

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

class Catalog {
    Person findPerson(String name);
}

Но и в этом случае генерации исключения можно избежать, если воспользоваться java.util.Optional:

Optional<Person> findPerson(String name);

Класс java.util.Optional был добавлен в Java 8 и предназначен как раз для подобных ситуаций, когда возвращаемого значения может не быть. В зависимости от задачи и контекста можно как генерировать исключение, как это сделано в примере с PersonNotFoundException, так и изменить сигнатуру метода, воспользовавшись java.util.Optional.

Отсюда следует второй совет: думайте над API ваших классов, исключений можно избежать воспользовавшись другим подходом.

Заранее обдумывайте контракты методов

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

class Person {
    void hello() throws RuntimeException {
        // some code
    }
}

// Compile Error
class PPerson extends Person {
    @Override
    void hello() throws Exception {
        // some code
    }
}

Если было явно указано, что метод может сгенерировать java.lang.RuntimeException, то нельзя объявить более общее бросаемое исключение при переопределении. Но можно указать потомка:

// IllegalArgumentException - потомок RuntimeException!
class PPerson extends Person {
    @Override
    void hello() throws IllegalArgumentException {
        // some code
    }
}

Что, в целом логично.

Если объявляется, что метод может сгенерировать java.lang.RuntimeException, а он выбрасывает java.io.IOException, то это было бы как минимум странно.

Это объясняется и с помощью полимофризма. Пусть есть интерфейс, в котором объявлен метод, генерирующий исключение. Если полиморфно работать с объектом через общий интерфейс, то разработчик обязан обработать исключение, объявленное в интерфейсе, а если одна из реализаций интерфейса генерирует более общее исключение, то это нарушает полиморфизм. Поэтому такой код даже не скомпилируется.

При этом при переопределении можно вообще не объявлять бросаемые исключения, таким образом сообщив, что все проблемы будут решены в методе:

class PPerson extends Person {
    @Override
    void hello() {
        // some code
    }
}

Отсюда следует третий совет: необходимо думать о тех исключениях, которые делегирует метод, если класс может участвовать в наследовании.

Предпочитайте исключения кодам ошибок и boolean флагам-признакам успеха

  1. Исключения более информативны: они позволяют передать сообщение с описанием ошибки
  2. Исключение практически невозможно проигнорировать
  3. Исключение может быть обработано кодом, находящимся выше по стеку, а boolean-флаг или код ошибки необходимо обрабатывать здесь и сейчас

Исключения и статические блоки

Еще интересно поговорить про то, что происходит, если исключение возникает в статическом блоке.

Так вот, такие исключения оборачиваются в java.lang.ExceptionInInitializerError:

public class ExceptionHandling {
    static {
        throwRuntimeException();
    }

    private static void throwRuntimeException()  {
        throw new NullPointerException();
    }

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

Результатом будет падение со следующим стектрейсом:

java.lang.ExceptionInInitializerError Caused by: java.lang.NullPointerException at exception.test.ExceptionHandling.throwRuntimeException(ExceptionHandling.java:13) at exception.test.ExceptionHandling. (ExceptionHandling.java:8)

Многопоточность и исключения

Код в Java потоке выполняется в методе со следующей сигнатурой:

Что делает невозможным пробрасывание проверяемых исключений, т.е разработчик должен обрабатывать все проверяемые исключения внутри метода run.

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

Например:

public class ExceptionHandling4 {
  public static void main(String[] args) throws InterruptedException {
    Thread t = new Thread() {
        @Override
        public void run() {
                throw new RuntimeException("Testing unhandled exception processing.");
         }
    };
    t.start();
  }
}

Результатом выполнения этого кода будет то, что возникшее исключение прервет поток исполнения (interrupt thread):

Exception in threadThread-0java.lang.RuntimeException: Testing unhandled exception processing. at exception.test. ExceptionHandling4$1.run(ExceptionHandling4.java:27)

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

В таких ситуациях рекомендуется использовать Thread.UncaughtExceptionHandler.

t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
          public void uncaughtException(Thread t, Throwable e)   {
             System.out.println("Handled uncaught exception in thread :" + t + " Exception : " + e);
         }
  });

И вывод уже будет:

Handled uncaught exception in thread :Thread[Thread-0,5,main] Exception : java.lang.RuntimeException: Testing unhandled exception processing.

Необработанное исключение RuntimeException("Testing unhandled exception processing."), убившее поток, было перехвачено специальным зарегистрированным обработчиком.

Проверяемые исключения и их необходимость

В большинстве языков программирования, таких как C#, Scala, Groovy, Python и т.д., нет такого разделения, как в Java, на проверяемые и непроверяемые исключения.
Почему оно введено в Java было разобрано выше, а вот почему проверяемые исключения недолюбливают разработчики?

Основных причин две, это причины с: версионированием и масштабируемостью.

Представим, что вы, как разработчик библиотеки, объявили некоторый условный метод foo, бросающий исключения A, B и C:

void foo() throws A, B, C;

В следующей версии библиотеки в метод foo добавили функциональности и теперь он бросает еще новое исключение D:

void foo() throws A, B, C, D;

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

И с одной стороны, это правильно, так как в новой версии добавляется еще одно исключение и те, кто использует библиотеку должны отреагировать на все новые исключения. С другой стороны, чаще всего такие исключения будут также проброшены дальше. Все дело в том, что случаев, когда можно обработать специфический тип исключения, например тот же D или A в примере выше, и сделать в обработчике что-то интеллектуальное, можно пересчитать по пальцам одной руки.

Проблема с масштабируемостью начинается тогда, когда происходит вызов не одного, а нескольких API, каждый из которых также несет с собой проверяемые исключения. Представьте, что помимо foo, бросающего A, B, C и D, в методе hello вызывается еще и bar, который также бросает E и T исключения. Как сказано выше, как реагировать чаще всего непонятно, поэтому эти исключения делегируются вызывающему коду, из-за чего объявление метода hello выглядит совсем уж угрожающе:

void hello() throws A, B, C, D, E, T {
    try {
        foo();
        bar();
    } finally {
        // clear resources if needed
    }
}

Все это настолько раздражающе, что чаще всего разработчики просто объявляют наиболее общее исключение в throws:

void hello() throws Exception {
    try {
        foo();
        bar();
    } finally {
        // clear resources if needed
    }
}

А в таком случае это все равно, что сказать «метод может выбросить исключение» — это настолько общие и абстрактные слова, что смысла в throws Exception практически нет.

Также есть еще одна проблема с проверяемыми исключениями. Это то, что с проверяемыми исключениями крайне неудобно работать в lambda-ах и stream-ах:

// compilation error
    Lists.newArrayList("a", "asg").stream().map(e -> {throw new Exception();});

Так как с Java 8 использование lambda и stream-ов распространенная практика, то накладываемые ограничения вызовут дополнительные трудности при использовании проверяемых исключений.

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

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

В своей работе я стараюсь чаще использовать непроверяемые исключения, а проверяемые оборачивать в unchecked аналоги, как, например, java.io.IOException и java.io.UncheckedIOException.

Заключение

Иерархия исключений в Java.

Exception Hierarchy

Исключения делятся на два типа: непроверяемые(unchecked) и проверяемые(checked). Проверяемые исключения — это исключения, которые проверяются на этапе компиляции, мы обязаны на них отреагировать.

Проверяемые исключения в Java используются тогда, когда разработчик никак не может предотвратить их возникновение. Причину возникновения java.lang.RuntimeException можно проверить и устранить заранее, например, проверить ссылку на null перед вызовом метода, на объекте по ссылке. А вот с причинами проверяемых исключений так сделать не получится, так как ошибка при чтении файла может возникнуть непосредственно в момент чтения, потому что другая программа его удалила. Соответственно, при чтении файла требуется обрабатывать java.io.IOException, который является потомком java.lang.Exception.

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

Обработка исключений происходит с помощью конструкции try/catch/finally. Один блок try может иметь несколько catch блоков. В таком случае будет выполняться первый подходящий блок.

Помните, что try блок не транзакционен, все ресурсы, занятые в try ДО исключения остаются в памяти. Их надо освобождать и очищать вручную.
Если вы используете Java версии 7 и выше, то отдавайте предпочтение конструкции try-with-resources.

Основное правило:

На исключения можно реагировать, их обработку можно делегировать, но ни в коем случае нельзя их игнорировать.

Определить когда надо реагировать, а когда делегировать проще простого. Задайте вопрос: «Знаю ли я как реагировать на это исключение?».
Если ответ «да, знаю», то реагируйте, пишите обработчик и код, отвечающий за эту реакцию, если не знаете что делать с исключением, то делегируйте вызывающему коду.

Помните, что перехват java.lang.Error стоит делать только если вы точно знаете, что делаете. Восстановление после таких ошибок не всегда возможно и почти всегда нетривиально.
Не забывайте, что большинство ошибок java.lang.RuntimeException и его потомков можно избежать.

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

Представьте себе, что существуют пять причин, по которым может быть выброшено исключение, и во всех пяти случаях бросается java.lang.Exception. Вы же спятите разбираться, чем именно это исключение вызвано.

(c) Евгений Матюшкин.

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

Постарайтесь не создавать ‘универсальных’ обработчиков, так как это чревато трудноуловимыми ошибками.

Если исключение можно не генерировать, то лучше так и сделать. Не пренебрегайте проверками.

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

Помните:

In Java you can ignore exceptions, but you have to willfully do it. You can’t accidentally say, «I don’t care.» You have to explicitly say, «I don’t care.»

(c) James Gosling.

Для закрепления материала рекомендую ознакомиться с ссылками ниже и этим материалом.

Полезные ссылки

  1. Книга С. Стелтинг ‘Java без сбоев: обработка исключений, тестирование, отладка’
  2. Oracle Java Tutorials
  3. Лекция Технострим Исключения
  4. Лекция OTUS Исключения в Java
  5. Лекция Ивана Пономарёва по исключениям
  6. Заметка Евгения Матюшкина про Исключения
  7. Failure and Exceptions by James Gosling
  8. The Trouble with Checked Exceptions by Bill Venners with Bruce Eckel
  9. Никто не умеет обрабатывать ошибки
  10. Исключения и обобщенные типы в Java
  11. Вопросы для закрепления

Errors in Java occur when a programmer violates the rules of Java programming language.

It might be due to programmer’s typing mistakes while developing a program. It may produce incorrect output or may terminate the execution of the program abnormally.

For example, if you use the right parenthesis in a Java program where a right brace is needed, you have made a syntax error. You have violated the rules of Java language.

Therefore, it is important to detect and fix properly all errors occurring in a program so that the program will not terminate during execution.

Types of Errors in Java Programming


When we write a program for the first time, it usually contains errors. These errors are mainly divided into three types:

1. Compile-time errors (Syntax errors)
2. Runtime errors
3. Logical errors

Types of errors in Java programming


Compile-time errors occur when syntactical problems occur in a java program due to incorrect use of Java syntax.

These syntactical problems may be missing semicolons, missing brackets, misspelled keywords, use of undeclared variables, class not found, missing double-quote in Strings, and so on.

These problems occurring in a program are called syntax errors in Java.

Since all syntax errors are detected by Java compiler, therefore, these errors are also known as compile time errors in Java.

When Java compiler finds syntax errors in a program, it prevents the code from compile successfully and will not create a .class file until errors are not corrected. An error message will be displayed on the console screen.

These errors must be removed by debugging before successfully compile and run the program. Let’s take an example program where we will get a syntax error.

Program source code 1:

public class CompileTimeErrorEx 
{
public static void main(String[] args) 
{
  System.out.println("a") // Syntax error. Semicolon missing.
 }
}
Compile time error in Java code:
      Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
      Syntax error, insert ";" to complete BlockStatements

When you will try to compile the above program, Java compiler will tell you where errors are in the program. Then you can go to the appropriate line, correct error, and recompile the program.

Let’s create a program where we will try to call the undeclared variable. In this case, we will get unresolved compilation problem.

Program source code 2:

public class MisspelledVar 
{	
public static void main(String[] args) 
{
int x = 20, y = 30;

// Declare variable sum.
   int sum = x + y; 

// Call variable Sum with Capital S.
   System.out.println("Sum of two numbers: " + Sum); // Calling of undeclared variable.
 }
}
Compile time error in Java code:
       Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	Sum cannot be resolved to a variable

Program source code 3: Missing parenthesis in for statement.

public class MissingBracket 
{	
public static void main(String[] args) 
{ 
 int i; 
 int sum = 0;

// Missing bracket in for statement.
 for (i = 1; i <= 5; i++ // insert " ) Statement" to complete For Statement.
 {
   sum = sum + i;	
 }
System.out.println("Sum of 1 to 5 n");
System.out.println(sum); 
  }
}
Compile time error in Java code:
      Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
      Syntax error, insert ") Statement" to complete ForStatement

Program source code 4: Missing double quote in String literal.

public class MissingDoubleQuote
{	
public static void main(String[] args) 
{ 
 String str = "Scientech; // Missing double quote in String literal.
 System.out.println(str);
  }
}
Compile time error in Java code:
       Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	String literal is not properly closed by a double-quote

We may also face another error related to the directory path. An error such as

javac : command not found

means that you have not set the path correctly.

Runtime Errors in Java


Runtime errors occur when a program is successfully compiled creating the .class file but does not run properly. It is detected at run time (i.e. during the execution of the program).

Java compiler has no technique to detect runtime errors during compilation because a compiler does not have all of the runtime information available to it. JVM is responsible to detect runtime errors while the program is running.

Such a program that contains runtime errors, may produce wrong results due to wrong logic or terminate the program. These runtime errors are usually known as exceptions.

For example, if a user inputs a value of string type in a program but the computer is expecting an integer value, a runtime error will be generated.

The most common runtime errors are as follows:

1. Dividing an integer by zero.
2. Accessing an element that is out of range of the array.
3. Trying to store a value into an array that is not compatible type.
4. Passing an argument that is not in a valid range or valid value for a method.
5. Striving to use a negative size for an array.
6. Attempting to convert an invalid string into a number.
7. and many more.

When such errors are encountered in a program, Java generates an error message and terminates the program abnormally. To handle these kinds of errors during the runtime, we use exception handling technique in java program.

Let’s take different kinds of example programs to understand better. In this program, we will divide an integer number by zero. Java compiler cannot detect it.

Program source code 5:

public class DivisionByZeroError
{	
public static void main(String[] args) 
{ 
 int a = 20, b = 5, c = 5;
 int z = a/(b-c); // Division by zero.
 
 System.out.println("Result: " +z);
  }
}
Output:
       Exception in thread "main" java.lang.ArithmeticException: / by zero
	at errorsProgram.DivisionByZeroError.main(DivisionByZeroError.java:8)

The above program is syntactically correct. There is no syntax error and therefore, does not cause any problem during compilation. While executing, runtime error occurred that is not detected by compiler.

The error is detected by JVM only in runtime. Default exception handler displays an error message and terminates the program abnormally without executing further statements in the program.

Let’s take an example program where we will try to retrieve a value from an array using an index that is out of range of the array.

Program source code 6: 

public class AccessingValueOutOfRangeError
{	
public static void main(String[ ] args) 
{ 
 int arr[ ] = {1, 2, 3, 4, 5}; // Here, array size is 5.
 System.out.println("Value at 5th position: "+arr[5]);
 }
}
Output:
       Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
	at errorsProgram.AccessingValueOutOfRangeError.main(AccessingValueOutOfRangeError.java:9)

Logical Errors in Java Program


Logical errors in Java are the most critical errors in a program and they are difficult to detect. These errors occur when the programmer uses incorrect logic or wrong formula in the coding.

The program will be compiled and executed successfully but does not return the expected output.

Logical errors are not detected either by Java compiler or JVM (Java runtime system). The programmer is entirely responsible for them. They can be detected by application testers when they compare the actual result with its expected result.

For example, a programmer wants to print even numbers from an array but he uses division (/) operator instead of modulus (%) operator to get the remainder of each number. Due to which he got the wrong results.

Let’s see the following source code related to this problem.

Program source code 7:

public class LogicalErrorEx
{	
public static void main(String[] args) 
{ 
 int a[]={1, 2 , 5, 6, 3, 10, 12, 13, 14};  
 
System.out.println("Even Numbers:");  
for(int i = 0; i <a.length; i++)
{  
if(a[i] / 2 == 0) // Using wrong operator.
{  
  System.out.println(a[i]);  
 }  
}  
 }
}
Output:
       Even Numbers:
       1

As you can see the program is successfully compiled and executed but the programmer got the wrong output due to logical errors in the program.


Seldom does a program run successfully at its first attempt. A software engineer in a company also commits several errors while designing the project or developing code.

These errors in a program are also called bugs and the process of fixing these bugs is called debugging.

All modern integrated development environments (IDEs) such as Eclipse, NetBeans, JBuilder, etc provide a tool known as debugger that helps to run the program step by step to detect bugs.


If you need professional help with Java homework assignments online, please address experts from AssignmentCore to get your Java projects done with no errors.

In this tutorial, we have familiarized different types of errors in java that may possibly occur in a program.
Thanks for reading!!!
Next ⇒ Exception handling Interview Programs for Practice

⇐ Prev Next ⇒

Exception  in the unwanted unexpected event that disturbs the normal flow of the program is called an exception.

Example

SleepingException 

TyrePunchuredException 

FileNotFoundException …etc.

It is highly recommended to handle exceptions. The main objective of exception handling is graceful (normal) termination of the program.

What is the meaning of exception handling?

Exception handling doesn’t mean repairing an exception. We have to define alternative ways to continue the rest of the program normally this way of «defining alternative is nothing but exception handling».

Example

Suppose our programming requirement is to read data from remote file locating at London at runtime if London file is not available our program should not be terminated abnormally.

We have to provide a local file to continue the rest of the program normally. This way of defining alternative is nothing but exception handling.

Example:

Try { read data from london file } catch(FileNotFoundException e) { use local file and continue rest of the program normally } } . . .

Runtime stack mechanism

For every thread, JVM will create a separate stack all method calls performed by the thread will be stored in that stack. 

Each entry in the stack is called «one activation record» (or) «stack frame». 

 After completing every method call JVM removes the corresponding entry from the stack.

After completing all method calls JVM destroys the empty stack and terminates the program normally.

Example:

class Test { public static void main(String[] args){ doStuff(); } public static void doStuff(){ doMoreStuff(); } public static void doMoreStuff(){ System.out.println("Hello"); }} Output: Hello

1) If an exception raised inside any method then the method is responsible to create an Exception object with the following information. 

2) Name of the exception. 

3) Description of the exception.

 4) Location of the exception. (StackTrace)
After creating that Exception object the method handovers that object to the JVM.
JVM checks whether the method contains any exception handling code or not. 

5) If the method won’t contain any handling code then JVM terminates that method abnormally and removes corresponding entry form the stack.

6)  JVM identifies the caller method and checks whether the caller method contains any handling code or not. If the caller method also does not contain handling code then JVM terminates that caller also abnormally and the removes corresponding entry from the stack. 

7) This process will be continued until the main() method and if the main() method also doesn’t contain any exception handling code then JVM terminates main() method and removes the corresponding entry from the stack.

  8)  Then JVM handovers the responsibility of exception handling to the default exception handler. 

9) The default exception handler just prints exception information to the console in the following formats and terminates the program abnormally.
Name of exception: description
Location of exception (stack trace)

Example:

class Test { public static void main(String[] args){ doStuff(); } public static void doStuff(){ doMoreStuff(); } public static void doMoreStuff(){ System.out.println(10/0); }} Output: Runtime error Exception in thread "main" java.lang.ArithmeticException: / by zero at Test.doMoreStuff(Test.java:10) at Test.doStuff(Test.java:7) at Test.main(Test.java:4)

Diagram

Exception hierarchy

Throwable acts as a root for exception hierarchy. The throwable class contains the following two child classes.

Exception:
Most of the cases exceptions are caused by our program and these are recoverable.
Ex: If FileNotFoundException occurs we can use a local file and we can continue the rest of the program execution normally. 

Error:
Most of the cases errors are not caused by our program these are due to lack of system resources and these are non-recoverable.
Ex: If OutOfMemoryError occurs being a programmer we can’t do anything the program will be terminated abnormally.
System Admin or Server Admin is responsible to raise/increase heap memory.

Checked Vs Unchecked Exceptions

There are 2 types of exception:

  • Checked

    : The exceptions which are checked by the compiler for smooth execution of the program at runtime are called checked exceptions.

  • 1)HallTicketMissingException
  • 2)PenNotWorkingException
  • 3)FileNotFoundException
  • Un Checked: The exceptions which are not checked by the compiler are called unchecked exceptions.

  • 1)BombBlaustException
  • 2)ArithmeticException
  • 3)NullPointerException.

Note: RuntimeException and its child classes, Error, and its child classes are unchecked and all the remaining are considered as checked exceptions.
Note: Whether exception is checked or unchecked compulsory it should occur at runtime only there is no chance of occurring any exception at compile time.

Partially checked Vs fully checked :

A checked exception is said to be fully checked if and only if all its child classes are also checked.
Example: 

1) IOException 

2) InterruptedException

A checked exception is said to be partially checked if and only if some of its child classes are unchecked.

Example:
Exception The only partially checked exceptions available in java are : 

1) Throwable.

 2) Exception.

Which of the following are checked?


  • RuntimeException——unchecked

  • Error——unchecked

  • IOException——fully checked

  • Exception——partially checked

  • InterruptedException——fully checked

  • Throwable——partially checked

  • ArithmeticException —— unchecked Checked

  • NullPointerException —— unchecked

  • FileNotFoundException —— fully checked

Diagram:

Customized exception handling by try-catch

1) It is highly recommended to handle exceptions. 

2) In our program the code which may cause an exception is called risky code, we have to place risky code inside try block and the corresponding handling code inside the catch block.

Example:

Try
{
risky code
}
catch(Exception e)
{
handling code
}

Without try-catch

Example:
class Test { public static void main(String[] args){ System.out.println("statement1"); System.out.println(10/0); System.out.println("statement3"); } } output: statement1 RE:AE:/by zero at Test.main() Abnormal termination



With try-catch

Example:

class Test { public static void main(String[] args){ System.out.println("statement1"); try{ System.out.println(10/0); } catch(ArithmeticException e){ System.out.println(10/2); } System.out.println("statement3"); }} Output: statement1 5 statement3 Normal termination.

Control flow in try-catch

try{
statement1;
statement2;
statement3;
}
catch(X e) {
statement4;
}
statement5;

Output: statement1 5 statement3 Normal termination.  
.
.
.
  • Case 1:   There is no exception.
    1, 2, 3, 5 normal terminations.
  • Case 2:  if an exception raised at statement 2 and corresponding catch block matched 1, 4, 5 normal terminations.

  • Case 3:  if an exception raised at statement 2 but the corresponding catch block not matched, 1 followed by abnormal termination.

  • Case 4: if an exception raised at statement 4 or statement 5 then it’s always abnormal termination of the program.

Note:
1) Within the try block if anywhere an exception raised then the rest of the try block won’t be executed even though we handled that exception. Hence we have to place/take only risk code inside try and length of the try block should be as less as possible.
2) If any statement raises an exception and it is not part of any try block then it is always abnormal termination of the program.
3) There may be a chance of raising an exception inside catch and finally blocks also in addition to try block.

Various methods to print exception information:

The Throwable class defines the following methods to print exception information to the console.
printStackTrace()


This method prints exception information in the following format.
Name of the exception: description of the exception
Stack trace


toString():


This method prints exception information in the following format.
Name of the exception: description of the exception


getMessage():

This method returns only a description of the exception.
Description.



Example:
Note: Default exception handler internally uses the printStackTrace() method to print exception information to the console.

Try with multiple catch blocks

The way of handling an exception is varied from exception to exception hence for every exception raise a separate catch block is required .i.e try with multiple catch blocks is possible and recommended to use.

Example:
This approach is not recommended
because for any type of Exception
we are using the same catch block.

try

{ . . . . } catch(Exception e) { default handler }

This approach is highly recommended
because for any exception raise
we are defining a separate catch block.

try

{ . . . . catch(FileNotFoundException e) { use local file } catch(ArithmeticException e) { perform these Arithmetic operations } catch(SQLException e) { don't use oracle db, use mysql db } catch(Exception e) { default handler }

If try with multiple catch blocks presents then the order of catch blocks is very important it should be from child to parent by mistake if we are taking from parent to child then we will get Compile time error saying «exception xxx has already been caught».

class Test

{ public static void main(String[] args) { try { System.out.println(10/0); } catch(Exception e) { e.printStackTrace(); } catch(ArithmeticException e) { e.printStackTrace(); }}} Output: Compile time error. Test.java:13: exception java.lang.ArithmeticException has already been caught catch(ArithmeticException e)

class Test

{ public static void main(String[] args) { try { System.out.println(10/0); } catch(ArithmeticException e) { e.printStackTrace(); } catch(Exception e) { e.printStackTrace(); }}} Output: Compile successfully.

Finally block

  • It is never recommended to take clean up code inside try block because there is no guarantee for the execution of every statement inside a try.
  • It is never recommended to place clean up code inside the catch block because if there is no exception then catch block won’t be executed.

  • We require someplace to maintain clean up code which should be executed always irrespective of whether exception raised or not raised and whether handled or not handled such type of place is nothing but finally block.

  • Hence the main objective of finally block is to maintain cleanup code.

Example:

Try { risky code } catch(x e) { handling code } finally { cleanup code }

The specialty of finally block is it will be executed always irrespective of whether the exception raised or not raised and whether handled or not handled.

Example 1:

class Test
{
public static void main(String[] args)
{
try
{
System.out.println("try block executed");
}
catch(ArithmeticException e)
{
System.out.println("catch block executed");
}
finally
{
System.out.println("finally block executed");
}}}
Output:
Try block executed
Finally block executed

Example 2:
class Test
{
public static void main(String[] args)
{
try
{
System.out.println("try block executed");
System.out.println(10/0);
}
catch(ArithmeticException e)
{
System.out.println("catch block executed");
}
finally
{
System.out.println("finally block executed");
}}}
Output:
Try block executed
Catch block executed
Finally block executed
 

Example 3:

class Test { public static void main(String[] args) { try { System.out.println("try block executed"); System.out.println(10/0); } catch(NullPointerException e) { System.out.println("catch block executed"); } finally { System.out.println("finally block executed"); }}} Output: Try block executed Finally block executed Exception in thread "main" java.lang.ArithmeticException: / by zero at Test.main(Test.java:8)

Return Vs Finally

Even though return present in try or catch blocks first finally will be executed and after that only return statement will be considered that is finally block dominates return statement.

Example:

class Test { public static void main(String[] args) { try { System.out.println("try block executed"); return; } catch(ArithmeticException e) { System.out.println("catch block executed"); } finally { System.out.println("finally block executed"); }}} Output: Try block executed Finally block executed

If the return statement presents try-catch and finally blocks then finally block return statement will be considered.

class Test
{
public static void main(String[] args)
{
System.out.println(methodOne());
}
public static int methodOne(){
try
{
System.out.println(10/0);
return 777;
}
catch(ArithmeticException e)
{
return 888;
}
finally{
return 999;
}}}
Output:
999
 

There is only one situation where the finally block won’t be executed is whenever we are using System.exit(0) method.
Then JVM itself will be shut down, in this case finally block won’t be executed.
i.e., System.exit(0); dominates finally block.

try

Example: class Test { public static void main(String[] args) { try { System.out.println("try"); System.exit(0); } catch(ArithmeticException e) { System.out.println("catch block executed"); } finally { System.out.println("finally block executed"); }}} Output: Try

Note :
System.exit(0); instead of zero, we can take any integer value
zero means normal termination, non-zero means abnormal termination
this status code internally used by JVM, whether it is zero or non-zero there is no change in the result and effect is same

Difference between final, finally, and finalize


Final

  • The Final is the modifier applicable for class, methods, and variables.
  • If a class declared as the final then child class creation is not possible.
  • If a method declared as the final then overriding of that method is not possible.
  • If a variable declared as the final then reassignment is not possible.

Finally

It is the block always associated with try-catch to maintain clean up code which should be executed always irrespective of whether exception raised or not raised and whether handled or not handled.


Finalize

It is a method which should be called by garbage collector always just before destroying an object to perform cleanup activities.

Note:
To maintain clean up code faunally block is recommended over the finalize() method because we can’t expect the exact behavior of GC.

Control flow in try-catch-finally

class Test
{
public static void main(String[] args){
try{
System.out.println("statement1");
System.out.println("statement2");
System.out.println("statement3");
}
catch(Exception e){
System.out.println("statement4");
}
finally
{
System.out.println("statement5");
}
System.out.println("statement6");
}
}
 
  • Case 1: If there is no exception. 1, 2, 3, 5, 6 normal termination.
  • Case 2: if an exception raised at statement 2 and corresponding catch block matched. 1,4,5,6 normal terminations.
  • Case 3: if an exception raised at statement 2 and the corresponding catch block is not matched. 1,5 abnormal termination.
  • Case 4: if an exception raised at statement 4 then it’s always abnormal termination but before the finally block will be executed.
  • Case 5: if an exception raised at statement 5 or statement 6 its always abnormal termination.


Control flow in nested try-catch-finally

class Test
{
public static void main(String[] args){
try{
System.out.println("statement1");
System.out.println("statement2");
System.out.println("statement3");
 try{
        System.out.println("statement4");
        System.out.println("statement5");
        System.out.println("statement6");
      }
      catch(ArithmeticException  e){
      System.out.println("statement7");
      }
     finally
     {
     System.out.println("statement8");
     }
     System.out.println("statement9");
    }
catch(Exception e)
{
System.out.println("statement10");
}
finally
{
System.out.println("statement11");
}
System.out.println("statement12");
}
}
 

  • Case 1: if there is no exception. 1, 2, 3, 4, 5, 6, 8, 9, 11, 12 normal termination.
  • Case 2: if an exception raised at statement 2 and corresponding catch block matched 1,10,11,12 normal terminations.
  • Case 3: if an exception raised at statement 2 and the corresponding catch block is not matched 1, 11 abnormal termination.
  • Case 4: if an exception raised at statement 5 and corresponding inner catch has matched 1, 2, 3, 4, 7, 8, 9, 11, 12 normal terminations.
  • Case 5: if an exception raised at statement 5 and inner catch has not matched but the outer catch block has matched. 1, 2, 3, 4, 8, 10, 11, 12 normal termination.
  • Case 6: if an exception raised at statement 5 and both inner and outer catch blocks are not matched. 1, 2, 3, 4, 8, 11 abnormal termination.
  • Case 7: if an exception raised at statement 7 and the corresponding catch block matched 1, 2, 3, 4, 5, 6, 8, 10, 11, 12 normal terminations.
  • Case 8: if an exception raised at statement 7 and the corresponding catch block not matched 1, 2, 3, 4, 5, 6, 8, 11 abnormal terminations.
  • Case 9: if an exception raised at statement 8 and the corresponding catch block has matched 1, 2, 3, 4, 5, 6, 7, 10, 11,12 normal termination.
  • Case 10: if an exception raised at statement 8 and the corresponding catch block not matched 1, 2, 3, 4, 5, 6, 7, 11 abnormal terminations.
  • Case 11: if an exception raised at statement 9 and corresponding catch block matched 1, 2, 3, 4, 5, 6, 7, 8,10,11,12 normal termination.
  • Case 12: if an exception raised at statement 9 and corresponding catch block not matched 1, 2, 3, 4, 5, 6, 7, 8, 11 abnormal terminations.
  • Case 13: if an exception raised at statement 10 is always abnormal termination but before that finally block 11 will be executed.
  • Case 14: if an exception raised at statement 11 or 12 is always abnormal termination.

Note: if we are not entering into the try block then the finally block won’t be executed. Once we entered into the try block without executing finally block we can’t come out.

We can take try-catch inside try i.e., nested try-catch is possible
The most specific exceptions can be handled by using inner try-catch and generalized exceptions can be handle by using outer try-catch.

class Test
{
public static void main(String[] args){
try{
System.out.println(10/0);
}
catch(ArithmeticException e)
{
System.out.println(10/0);
}
finally{
String s=null;
System.out.println(s.length());
}}}

output :
RE:NullPointerException

Note: Default exception handler can handle only one exception at a time and that is the most recently raised exception.


Various possible combinations of try-catch-finally

1) Whenever we are writing try block compulsory we should write either catch or finally.
i.e., try without a catch or finally is invalid. 

2) Whenever we are writing catch block compulsory we should write a try.
i.e., catch without try is invalid. 

3) Whenever we are writing finally block compulsory we should write a try.
i.e., finally without try is invalid. 

4) In try-catch-finally order is important. 

5) Within the try-catch-finally blocks, we can take try-catch-finally.
i.e., nesting of try-catch-finally is possible.
6) For try-catch-finally blocks curly braces are mandatory.

class Test1 {

public static void main(String[] args){ try {} catch(ArithmeticException e) {} }} Output: Compile and running successfully.

class Test2 {

public static void main(String[] args){ try {} catch(ArithmeticException e) {} catch(NullPointerException e) {} } } Output: Compile and running successfully.

class Test3 {

public static void main(String[] args){ try {} catch(ArithmeticException e) {} catch(ArithmeticException e) {} } } Output: Compile time error. Test1.java:7: exception java.lang.ArithmeticException has already been caught catch(ArithmeticException e)

class Test4 {

public static void main(String[] args){ try {} } } Output: Compile time error Test1.java:3: 'try' without 'catch' or 'finally' try

class Test5 {

public static void main(String[] args){ catch(Exception e) {} } } Output: Compile time error. Test1.java:3: 'catch' without 'try' catch(Exception e)

class Test6 {

public static void main(String[] args){ try {} System.out.println("hello"); catch(Exception e) {} } } Output: Compile time error. Test1.java:3: 'try' without 'catch' or 'finally' Try

class Test7 {

public static void main(String[] args){ try {} catch(Exception e) {} finally {} } } Output: Compile and running successfully.

class Test8 {

public static void main(String[] args){ try {} finally {} } } Output: Compile and running successfully.

class Test9 {

public static void main(String[] args){ try {} finally {} finally {} } } Output: Compile time error. Test1.java:7: 'finally' without 'try' Finally

class Test10 {

public static void main(String[] args){ try {} catch(Exception e) {} System.out.println("hello"); finally {} } } Output: Compile time error. Test1.java:8: 'finally' without 'try' Finally

class Test11 {

public static void main(String[] args){ try {} finally {} catch(Exception e) {} } } Output: Compile time error. Test1.java:7: 'catch' without 'try' catch(Exception e)

class Test12 {

public static void main(String[] args){ finally {} } } Output: Test1.java:3: 'finally' without 'try' Finally

class Test13 {

public static void main(String[] args){ try { try{} catch(Exception e){} } catch(Exception e) {} } } Output: Compile and running successfully.

class Test14 {

public static void main(String[] args){ try { } catch(Exception e) { try{} finally{} } } } Output: Compile and running successfully.

class Test15 {

public static void main(String[] args){ try { } catch(Exception e) { try{} catch(Exception e){} } finally{ finally{} } } } Output: Compile time error. Test1.java:11: 'finally' without 'try' finally{}

class Test16 {

public static void main(String[] args){ finally{} try{ } catch(Exception e){} } } Output: Compile time error. Test1.java:3: 'finally' without 'try' finally{}

class Test17 {

public static void main(String[] args){ try{ } catch(Exception e){} finally { try{} catch(Exception e){} finally{} } } } Output: Compile and running successfully.


Throw statement

Sometimes we can create an Exception object explicitly and we can hand over to the JVM manually by using the throw keyword.

The result of the following 2 programs is exactly the same.

class Test

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

In this case creation of ArithmeticException object and handover to the JVM will be performed automatically by the main() method.

class Test

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

In this case, we are creating an exception objects explicitly and handover to the JVM manually.

Note: In general we can use throw keyword for customized exceptions but not for predefined exceptions.

Case 1:
throw e;
If e refers null then we will get NullPointerException.

class Test1

{ static ArithmeticException e=new ArithmeticException(); public static void main(String[] args){ throw e; } } Output: Runtime exception: Exception in thread "main" java.lang.ArithmeticException . . .

class Test2

{ static ArithmeticException e; public static void main(String[] args){ throw e; } } Output: Exception in thread "main" java.lang.NullPointerException at Test3.main(Test3.java:5)

Case 2:
After throw statement we can’t take any statement directly otherwise we will get a compile-time error saying an unreachable statement.
Example:

class Test1

{ public static void main(String[] args){ System.out.println(10/0); System.out.println("hello"); } } Output: Runtime error: Exception in thread "main" java.lang.ArithmeticException: / by zero at Test3.main(Test3.java:4)

Case 3:
We can use throw keyword only for Throwable types otherwise we will get a compile-time error saying incomputable types.
Example:

class Test1

{ public static void main(String[] args){ throw new Test3(); } }Output: Compile time error. Test3.java:4: incompatible types found : Test3 required: java.lang.Throwable throw new Test3();

class Test2 extends RuntimeException

{ public static void main(String[] args){ throw new Test3(); } } Output: Runtime error: Exception in thread "main" Test3 at Test3.main(Test3.java:4)

Throws statement

In our program, if there is any chance of raising checked exception compulsory we should handle either by try-catch or by throws keyword otherwise the code won’t compile.

import java.io.*;

class Test3 { public static void main(String[] args){ PrinterWriter out=new PrintWriter("abc.txt"); out.println("hello"); } } CE : Unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown.

class Test3

{ public static void main(String[] args){ Thread.sleep(5000); } } Unreported exception java.lang.InterruptedException; must be caught or declared to be thrown.

We can handle this compile-time error by using the following 2 ways.
Example:

By using try-catch

class Test3

{ public static void main(String[] args){ try { Thread.sleep(5000); } catch(InterruptedException e){} } } Output: Compile and running successfully

By using throws keyword
We can use throws keyword to delicate the responsibility of exception handling to the caller method. Then the caller method is responsible to handle that exception.

class Test3

{ public static void main(String[] args)throws InterruptedException{ Thread.sleep(5000); } } Output: Compile and running successfully
    Note :

  • Hence the main objective of the «throws» keyword is to delicate the responsibility of exception handling to the caller method.

  • «throws» keyword required only checked exceptions. Usage of throws for unchecked exceptions there is no use.
  • «throws» keyword required only to convenes complier. The usage of throws keyword doesn’t prevent abnormal termination of the program.
  • Hence recommended to use try-catch over throws keyword.
class Test
{
public static void main(String[] args)throws InterruptedException{
doStuff();
}
public static void doStuff()throws InterruptedException{
doMoreStuff();
}
public static void doMoreStuff()throws InterruptedException{ 
Thread.sleep(5000);
}
}
Output:
Compile and running successfully.

In the above program if we are removing at least one throws keyword then the program won’t compile. 

Case 1:
we can use throws keyword only for Throwable types otherwise we will get a compile-time error saying incompatible types.

class Test3{

public static void main(String[] args) throws Test3 {} } Output: Compile time error Test3.java:2: incompatible types found : Test3 required: java.lang.Throwable public static void main(String[] args) throws Test3 . .

class Test3 extends RuntimeException{

public static void main(String[] args) throws Test3 {} } Output: Compile and running successfully.


Case 2: Example:

class Test3{

public static void main(String[] args){ throw new Exception(); } } Output: Compile time error. Test3.java:3: unreported exception java.lang.Exception; must be caught or declared to be thrown

class Test3{

public static void main(String[] args){ throw new Error(); } } Output: Runtime error Exception in thread "main" java.lang.Error at Test3.main(Test3.java:3)


Case 3:
In our program within the try block, if there is no chance of raising an exception then we can’t right catch block for that exception otherwise we will get a compile-time error saying exception XXX is never thrown in body of corresponding try statement. But this rule is applicable only for fully checked exceptions.

image7 image8


Case 4:
We can use throws keyword only for constructors and methods but not for classes.

execp9:img

Exception handling keywords summary

1) try: To maintain risky code.
2) catch: To maintain handling code.
3) finally: To maintain cleanup code.
4) throw: To handover our created exception object to the JVM manually.
5) throws: To delegate the responsibility of exception handling to the caller method.

Various possible compile-time errors in exception handling

1) Exception XXX has already been caught. 

2) Unreported exception XXX must be caught or declared to be thrown. 

3) Exception XXX is never thrown in body of corresponding try statement.

 4) Try without a catch or finally.

 5) Catch without a try. 

6) Finally without a try.
Incompatible types.
Found: test
Requried:java.lang.Throwable;
7) Unreachable statement.

Customized Exceptions (User-defined Exceptions)

Sometimes we can create our own exception to meet our programming requirements. Such types of exceptions are called customized exceptions (user-defined exceptions).

Example:
1) InSufficientFundsException
2) TooYoungException
3) TooOldException

class TooYoungException extends RuntimeException
{
TooYoungException(String s)
{
super(s);
}
}
class TooOldException extends RuntimeException
{
TooOldException(String s)
{
super(s);
}
}
class CustomizedExceptionDemo
{
public static void main(String[] args){
int age=Integer.parseInt(args[0]);
if(age>60)
{
throw new TooYoungException("please wait some more time.... u will get best match");
}
else if(age<18 1="" age="" already="" by="" chance="" crossed....no="" details="" e-mail="" else="" get="" getting="" married="" match="" new="" of="" output:="" r="" scjp="" soon="" system.out.println="" throw="" toooldexception="" u="" will="" you="">java CustomizedExceptionDemo 61
Exception in thread "main" TooYoungException:
please wait some more time.... u will get best match
at CustomizedExceptionDemo.main(CustomizedExceptionDemo.java:21)



2)E:scjp>java CustomizedExceptionDemo 27
You will get match details soon by e-mail

3)E:scjp>java CustomizedExceptionDemo 9
Exception in thread "main" TooOldException:
u r age already crossed....no chance of getting married
at CustomizedExceptionDemo.main(CustomizedExceptionDemo.java:25)
 

Note: It is highly recommended to maintain our customized exceptions as unchecked by extending RuntimeException.
We can catch any Throwable type including Errors also.

Example:

try {

} catch(){ } //Valid

Top-10 Exceptions

Exceptions are divided into two types.
They are: 

1) JVM Exceptions:

 2) Programmatic exceptions:

JVM Exceptions

The exceptions are raised automatically by the JVM whenever a particular event occurs. 

Example: 

 1) ArrayIndexOutOfBoundsException(AIOOBE) 

2) NullPointerException (NPE).

Programmatic Exceptions

The exceptions which are raised explicitly by the programmer (or) by the API developer are called programmatic exceptions.
Example: 1) IllegalArgumentException(IAE).

Top 10 Exceptions 

1) ArrayIndexOutOfBoundsException:
It is the child class of RuntimeException and hence it is unchecked. Raised automatically by the JVM whenever we are trying to access array element with out of range index. Example:

class Test{

public static void main(String[] args){ int[] x=new int[10]; System.out.println(x[0]);//valid System.out.println(x[100]);//ArrayIndexOutOfBoundsException System.out.println(x[-100]);//ArrayIndexOutOfBoundsException } }

2) NullPointerException: It is the child class of RuntimeException and hence it is unchecked. Raised automatically by the JVM, whenever we are trying to call any method on null.

class Test{
public static void main(String[] args){
String s=null;
System.out.println(s.length()); //R.E: NullPointerException
}
}

3) StackOverFlowError :
It is the child class of Error and hence it is unchecked. Whenever we are trying to invoke the recursive method call JVM will raise StackOverFloeError automatically.

class Test

{ public static void methodOne() { methodTwo(); } public static void methodTwo() { methodOne(); } public static void main(String[] args) { methodOne(); } } Output: Run time error: StackOverFloeError

4) NoClassDefFound:
It is the child class of Error and hence it is unchecked. JVM will raise this error automatically whenever it is unable to find the required .class file. Example: java Test If Test.class is not available. Then we will get a NoClassDefFound error.

5) ClassCastException:
It is the child class of RuntimeException and hence it is unchecked. Raised automatically by the JVM whenever we are trying to typecast parent object to child type.
Example:

6) ExceptionInInitializerError:
It is the child class of Error and it is unchecked. Raised automatically by the JVM, if any exception occurs while performing static variable initialization and static block execution.

class Test{
static int i=10/0;
}
Output:
Runtime exception:
 Exception in thread "main" java.lang.ExceptionInInitializerError
  .
  .
class Test{
static {
String s=null;
System.out.println(s.length());
}}
Output:
Runtime exception:
Exception in thread "main" java.lang.ExceptionInInitializerError

7) IllegalArgumentException:
It is the child class of RuntimeException and hence it is unchecked. Raised explicitly by the programmer (or) by the API developer to indicate that a method has been invoked with inappropriate argument.

class Test{ 
public static void main(String[] args){ 
Thread t=new Thread(); 
t.setPriority(10);//valid 
t.setPriority(100);//invalid 
}} 
Output: 
Runtime exception 
Exception in thread "main" java.lang.IllegalArgumentException.

8) NumberFormatException:
It is the child class of IllegalArgumentException and hence is unchecked. Raised explicitly by the programmer or by the API developer to indicate that we are attempting to convert string to the number. But the string is not properly formatted.

class Test{
public static void main(String[] args){
int i=Integer.parseInt("10");
int j=Integer.parseInt("ten");
}}
Output:
Runtime Exception
Exception in thread "main" java.lang.NumberFormatException: For input string: "ten"

9) IllegalStateException:
It is the child class of RuntimeException and hence it is unchecked. Raised explicitly by the programmer or by the API developer to indicate that a method has been invoked at an inappropriate time.

Example:
Once the session expires we can’t call any method on the session object otherwise we will get IllegalStateException

HttpSession session=req.getSession();

System.out.println(session.getId()); session.invalidate(); System.out.println(session.getId()); // IllgalstateException

10) AssertionError:
It is the child class of Error and hence it is unchecked. Raised explicitly by the programmer or by API developer to indicate that the Assert statement fails.

Example:
assert(false);

Exception/Error Raised automatically by JVM(JVM Exceptions)

1) AIOOBE
2) NPE(NullPointerException)
3) StackOverFlowError
4) NoClassDefFoundError
5) CCE(ClassCastException)
6) ExceptionInInitializerError

Exception/Error Raised explicitly either by the programmer or by API developer (Programmatic Exceptions).
1) IAE(IllegalArgumentException)
2) NumberFormatException
3) IllegalStateException
4) AssertionError

1.7 Version Enhancements 

As part of 1.7 version enhancements in Exception Handling the following 2 concepts introduced
try with resources
multi-catch block
try with resources
Until 1.5 version it is highly recommended to write finally block to close all resources which are open as part of the try block.

BufferedReader br=null;

try{ br=new BufferedReader(new FileReader("abc.txt")); //use br based on our requirements } catch(IOException e) { // handling code } finally { if(br != null) br.close(); }

problems in this approach 

1) Compulsory programmer is required to close all opened resources which increases the complexity of the programming 

2) Compulsory we should write finally block explicitly which increases the length of the code and reviews readability.
To overcome these problems Sun People introduced «try with resources» in 1.7 versions.

The main advantage of «try with resources» is

the resources which are opened as part of try block will be closed automatically
Once the control reaches the end of the try block either normally or abnormally and hence we are not required to close explicitly

due to the complexity of programming will be reduced, it is not required to write finally block explicitly and hence the length of the code will be reduced and readability will be improved.

try(BufferedReader br=new BufferedReader(new FileReader("abc.txt")))

{ use be based on our requirement, br will be closed automatically , Onec control reaches end of try either normally or abnormally and we are not required to close explicitly } catch(IOException e) { // handling code }

We can declare any no of resources but all these resources should be separated with ;(semicolon)

try(R1 ; R2 ; R3)

{ ------------- ------------- }

All resources should be auto closable resources, a resource is said to be auto closable if and only if the corresponding class implements the java.lang.AutoClosable interface either directly or indirectly.

All resource reference variables are implicitly final and hence we can’t perform reassignment within the try block.

try(BufferedReader br=new BufferedReader(new FileReader("abc.txt"))) ;

{ br=new BufferedReader(new FileReader("abc.txt")); } output : CE : Can't reassign a value to final variable br . .

Until 1.6 version try should be followed by either catch or finally but 1.7 version we can take only try with the resource without a catch or finally

try(R)

{ //valid } . .

The main advantage of «try with resources» finally block will become dummy because we are not required to close resources explicitly.

Multi catch block 

Even though Multiple Exceptions having same handling code we have to write a separate catch block for every exception, it increases the length of the code and reviews readability

try{

----------------- ----------------- } catch(ArithmeticException e) { e.printStackTrace(); } catch(NullPointerException e) { e.printStackTrace(); } catch(ClassCastException e) { System.out.println(e.getMessage()); } catch(IOException e) { System.out.println(e.getMessage()); }

To overcome this problem Sun People introduced the «Multi catch block» concept in 1.7 version.

The main advantage of the multi-catch block is we can write a single catch block, which can handle multiple different exceptions

try{

----------------- ----------------- } catch(ArithmeticException | NullPointerException e) { e.printStackTrace(); } catch(ClassCastException | IOException e) { System.out.println(e.getMessage()); }

In multi-catch block, there should not be any relation between Exception types(either child to parent Or parent to child Or same type, otherwise we will get Compile time error )

Example:

try{

----------------- ----------------- } catch(ArithmeticException | Exception e) { // compile time error e.printStackTrace();//invalid }

Exception Propagation 

Within a method if an exception raised and if that method doesn’t handle that exception then the Exception object will be propagated to the caller then the caller method is responsible to handle those exceptions. This process is called Exception Propagation.

Rethrowing an Exception 

To convert the one exception type to another exception type, we can use the rethrowing exception concept.

class Test

{ public static void main(String[] args){ try { System.out.println(10/0); } catch(ArithmeticException e) { throw new NullPointerException(); } } } output: RE:NPE

Понравилась статья? Поделить с друзьями:
  • General electric холодильник ошибка pf
  • General climate список ошибок
  • General climate ошибки внутреннего блока кондиционера
  • General climate ошибка на пульте
  • General climate vrv коды ошибок