JavaRush /Java Blog /Random-KO /Java의 예외: 포착 및 처리

Java의 예외: 포착 및 처리

Random-KO 그룹에 게시되었습니다
안녕하세요! 이 사실을 알려드리고 싶지는 않지만 프로그래머 업무의 큰 부분은 오류를 처리하는 것입니다. 그리고 대부분의 경우 - 자체적으로. 실수하지 않는 사람은 없는 법이다. 그리고 그런 프로그램도 없습니다. 물론 오류를 처리할 때 가장 중요한 것은 오류의 원인을 이해하는 것입니다. 그리고 프로그램에는 그러한 이유가 많이 있을 수 있습니다. 어느 시점에서 Java 제작자는 다음과 같은 질문에 직면했습니다. 프로그램에서 이러한 잠재적인 오류를 어떻게 처리해야 할까요? 그것들을 완전히 피하는 것은 비현실적입니다. 프로그래머는 상상조차 할 수 없는 것을 작성할 수 있습니다. :) 이는 오류를 처리하기 위한 메커니즘을 언어에 구축해야 함을 의미합니다. 즉, 프로그램에 오류가 발생한 경우 추가 작업을 위해 스크립트가 필요합니다. 오류가 발생하면 프로그램은 정확히 무엇을 해야 합니까? 오늘 우리는 이 메커니즘에 대해 알아 보겠습니다. 그리고 이를 "예외 " 라고 합니다 .

Java의 예외는 무엇입니까

예외는 프로그램 작동 중에 발생한 일부 예외적이고 계획되지 않은 상황입니다. Java에는 예외의 예가 많이 있을 수 있습니다. 예를 들어, 파일에서 텍스트를 읽고 첫 번째 줄을 콘솔에 표시하는 코드를 작성했습니다.
public class Main {

   public static void main(String[] args) throws IOException {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   }
}
하지만 그런 파일은 존재하지 않습니다! 프로그램의 결과는 예외가 됩니다 FileNotFoundException. 결론:

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
각 예외는 Java에서 별도의 클래스로 표시됩니다. 모든 예외 클래스는 공통 "조상", 즉 상위 클래스에서 나옵니다 Throwable. 예외 클래스의 이름은 일반적으로 발생 이유를 간략하게 반영합니다.
  • FileNotFoundException(파일을 찾을 수 없습니다)
  • ArithmeticException(수학 연산을 수행할 때는 예외)
  • ArrayIndexOutOfBoundsException(배열 셀의 개수가 길이를 초과하여 지정되었습니다.) 예를 들어 길이가 10인 배열 배열에 대해 셀 배열[23]을 콘솔에 출력하려고 하면
Java에는 거의 400개의 클래스가 있습니다! 왜 그렇게 많은가요? 프로그래머가 더 편리하게 작업할 수 있도록 하기 위한 것입니다. 상상해보세요: 프로그램을 작성했고, 실행될 때 다음과 같은 예외가 발생합니다.
Exception in thread "main"
어-어:/ 아무것도 확실하지 않습니다. 어떤 종류의 오류인지, 어디서 나온 것인지는 불분명합니다. 유용한 정보가 없습니다. 그러나 이러한 다양한 클래스 덕분에 프로그래머는 클래스 이름에 포함된 오류 유형과 가능한 원인 등의 주요 사항을 스스로 얻습니다. 결국 콘솔에서 보는 것은 완전히 다릅니다.
Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
문제가 무엇인지, 문제를 해결하기 위해 “어느 방향으로 파헤쳐야 하는지”가 즉시 명확해집니다! 클래스의 인스턴스와 마찬가지로 예외도 객체입니다.

예외 포착 및 처리

Java에서 예외를 처리하려면 특수 코드 블록인 , trycatch가 있습니다 finally. 예외: 차단 및 처리 - 2프로그래머가 예외가 발생할 것으로 예상하는 코드는 블록에 배치됩니다 try. 그렇다고 해서 반드시 이 위치에서 예외가 발생한다는 의미는 아닙니다. 이는 그곳에서 그런 일이 일어날 수 있고 프로그래머가 이를 알고 있다는 것을 의미합니다. 수신할 것으로 예상되는 오류 유형은 블록 catch("catch")에 배치됩니다. 또한 예외가 발생할 경우 실행해야 하는 모든 코드가 배치되는 곳이기도 합니다. 예는 다음과 같습니다.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("Error! File not found!");
   }
}
결론:

Ошибка! Файл не найден!
우리는 코드를 두 블록에 넣었습니다. 첫 번째 블록에서는 "파일을 찾을 수 없음" 오류가 발생할 수 있습니다. 이것은 블록입니다 try. 두 번째에서는 오류가 발생하면 무엇을 해야 할지 프로그램에 알려줍니다. 또한 특정 유형의 오류가 있습니다 FileNotFoundException. 다른 예외 클래스를 블록 괄호에 전달하면 catch포착되지 않습니다.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (ArithmeticException e) {

       System.out.println("Error! File not found!");
   }
}
결론:

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
블록의 코드는 우리가 이 블록을 가로채도록 "구성"했고 블록의 코드가 다른 유형( )을 버렸기 catch때문에 작동하지 않았습니다 . 에 대한 스크립트를 작성하지 않았기 때문에 프로그램은 에 대해 기본적으로 표시되는 정보를 콘솔에 표시했습니다 . 여기서 3가지에 주의를 기울여야 합니다. 첫 번째. try 블록의 코드 줄에서 예외가 발생하면 그 뒤의 코드는 더 이상 실행되지 않습니다. 프로그램 실행은 즉시 블록으로 "점프"됩니다 . 예를 들어: ArithmeticExceptiontryFileNotFoundExceptionFileNotFoundExceptionFileNotFoundExceptioncatch
public static void main(String[] args) {
   try {
       System.out.println("Divide a number by zero");
       System.out.println(366/0);//this line of code will throw an exception

       System.out.println("This");
       System.out.println("code");
       System.out.println("Not");
       System.out.println("will");
       System.out.println("done!");

   } catch (ArithmeticException e) {

       System.out.println("The program jumped to the catch block!");
       System.out.println("Error! You can't divide by zero!");
   }
}
결론:

Делим число на ноль 
Программа перепрыгнула в блок catch! 
Ошибка! Нельзя делить на ноль! 
두 번째 줄의 블록에서는 try숫자를 0으로 나누려고 시도했는데 그 결과 예외가 발생했습니다 ArithmeticException. 그 후에는 블록의 6-10행이 try더 이상 실행되지 않습니다. 앞서 말했듯이 프로그램은 즉시 블록을 실행하기 시작했습니다 catch. 두번째. 여러 개의 블록이 있을 수 있습니다 catch. 블록의 코드가 try하나가 아닌 여러 유형의 예외를 발생시킬 수 있는 경우 각 예외에 대해 고유한 블록을 작성할 수 있습니다 catch.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       System.out.println(366/0);
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("Error! File not found!");

   } catch (ArithmeticException e) {

       System.out.println("Error! Division by 0!");

   }
}
이 예에서는 두 개의 블록을 작성했습니다 catch. try해당 블록에서 가 발생하면 첫 FileNotFoundException번째 블록이 실행됩니다 catch. 발생하면 ArithmeticException두 번째 항목이 실행됩니다. 최소 50개의 블록을 작성할 수 catch있지만, 물론 50가지 유형의 오류를 던질 수 있는 코드는 작성하지 않는 것이 좋습니다 :) 셋째. 코드에서 어떤 예외가 발생할 수 있는지 어떻게 알 수 있나요? 물론 일부는 추측할 수 있지만 모든 것을 머릿속에 담는 것은 불가능합니다. 따라서 Java 컴파일러는 가장 일반적인 예외에 대해 알고 있으며 어떤 상황에서 발생할 수 있는지 알고 있습니다. 예를 들어, 코드를 작성했고 컴파일러가 작업 중에 두 가지 유형의 예외가 발생할 수 있다는 것을 알고 있는 경우 해당 예외를 처리할 때까지 코드가 컴파일되지 않습니다. 아래에서 이에 대한 예를 살펴보겠습니다. 이제 예외 처리에 관해 설명하겠습니다. 처리하는 방법에는 두 가지가 있습니다. 우리는 이미 첫 번째 것을 만났습니다. 메소드는 블록에서 독립적으로 예외를 처리할 수 있습니다 catch(). 두 번째 옵션이 있습니다. 메서드가 호출 스택에 예외를 발생시킬 수 있습니다. 무슨 뜻이에요? printFirstString()예를 들어, 우리 클래스에는 파일을 읽고 콘솔에 첫 번째 줄을 표시하는 동일한 메서드가 있습니다 .
public static void printFirstString(String filePath) {

   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
현재 우리 코드는 처리되지 않은 예외가 있기 때문에 컴파일되지 않습니다. 1행에는 파일 경로를 나타냅니다. 컴파일러는 그러한 코드가 쉽게 FileNotFoundException. 3번째 줄에서는 파일의 텍스트를 읽습니다. IOException이 과정에서 입출력(Input-Output) 과정에서 오류가 발생하기 쉽습니다 . 이제 컴파일러는 이렇게 말합니다. “야, 나는 이 예외 중 하나가 발생할 경우 어떻게 해야 하는지 당신이 말해 줄 때까지 이 코드를 승인하거나 컴파일하지 않을 것이다. 그리고 당신이 작성한 코드를 기반으로 그런 일이 확실히 일어날 수 있습니다!” . 갈 곳이 없습니다. 둘 다 처리해야합니다! 첫 번째 처리 옵션은 이미 우리에게 익숙합니다. 코드를 블록에 배치 try하고 두 개의 블록을 추가 해야 합니다 catch.
public static void printFirstString(String filePath) {

   try {
       BufferedReader reader = new BufferedReader(new FileReader(filePath));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error, file not found!");
       e.printStackTrace();
   } catch (IOException e) {
       System.out.println("Error while inputting/outputting data from file!");
       e.printStackTrace();
   }
}
그러나 이것이 유일한 선택은 아닙니다. 메서드 내부에서 오류에 대한 스크립트를 작성하는 것을 방지하고 간단히 예외를 맨 위에 던질 수 있습니다. throws이는 메소드 선언에 작성된 키워드를 사용하여 수행됩니다 .
public static void printFirstString(String filePath) throws FileNotFoundException, IOException {
   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
단어 뒤에는 throws이 메서드가 작업 중에 발생할 수 있는 모든 유형의 예외를 쉼표로 구분하여 나열합니다. 이 작업이 수행되는 이유는 무엇입니까? 이제 프로그램의 누군가가 메소드를 호출하려면 printFirstString()그는 스스로 예외 처리를 구현해야 합니다. 예를 들어, 프로그램의 다른 부분에서 동료 중 한 명이 귀하의 메서드를 호출하는 메서드를 작성했습니다 printFirstString().
public static void yourColleagueMethod() {

   //...your colleague's method does something

   //...and at one moment calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Eugene\\Desktop\\testFile.txt");
}
오류, 코드가 컴파일되지 않습니다! 메소드에 printFirstString()오류 처리 스크립트를 작성하지 않았습니다 . 따라서 작업은 이 방법을 사용하는 사람들의 어깨에 있습니다. 즉, 메서드는 yourColleagueMethod()이제 동일한 두 가지 옵션에 직면합니다. 를 사용하여 "흐르는" 두 예외를 모두 처리하거나 try-catch추가로 전달해야 합니다.
public static void yourColleagueMethod() throws FileNotFoundException, IOException {
   //...the method does something

   //...and at one moment calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Eugene\\Desktop\\testFile.txt");
}
두 번째 경우에는 처리가 스택의 다음 메서드, 즉 호출할 메서드의 어깨에 맡겨집니다 yourColleagueMethod(). 이것이 바로 이러한 메커니즘을 "예외를 위쪽으로 던지기" 또는 "맨 위로 전달"이라고 부르는 이유입니다. 를 사용하여 예외를 발생시키면 throws코드가 컴파일됩니다. 이 순간 컴파일러는 “그래, 알았어. 귀하의 코드에는 잠재적인 예외가 많이 포함되어 있지만 어쨌든 컴파일하겠습니다. 이 대화로 다시 돌아오겠습니다!” 그리고 예외를 처리하지 않은 프로그램 어딘가에서 메서드를 호출하면 컴파일러는 약속을 이행하고 이에 대해 다시 알려줍니다. 마지막으로 블록에 대해 이야기하겠습니다 finally(말장난은 죄송합니다). 이것은 예외 처리 triumvirate의 마지막 부분입니다 try-catch-finally. 그 특징은 모든 프로그램 작동 시나리오에서 실행된다는 것입니다.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error! File not found!");
       e.printStackTrace();
   } finally {
       System.out.println("And here is the finally block!");
   }
}
이 예에서는 두 경우 모두 블록 내부의 코드가 finally실행됩니다. 블록의 코드가 try완전히 실행되고 예외가 발생하지 않으면 블록은 마지막에 실행됩니다 finally. 내부 코드가 try중단되고 프로그램이 해당 블록으로 점프하는 경우 catch내부 코드가 실행된 후에도 catch해당 블록은 계속 선택됩니다 finally. 왜 필요한가요? 주요 목적은 코드의 필수 부분을 실행하는 것입니다. 상황에 관계없이 완료해야 하는 부분입니다. 예를 들어 프로그램에서 사용하는 일부 리소스를 확보하는 경우가 많습니다. 우리 코드에서는 스트림을 열어 파일에서 정보를 읽고 이를 BufferedReader. 우리 회사는 reader폐쇄되고 자원이 확보되어야 합니다. 이는 어떤 경우에도 수행되어야 합니다. 프로그램이 예상대로 작동하는지 또는 예외가 발생하는지 여부는 중요하지 않습니다. 이 작업을 블록으로 수행하는 것이 편리합니다 finally.
public static void main(String[] args) throws IOException {

   BufferedReader reader = null;
   try {
       reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       e.printStackTrace();
   } finally {
       System.out.println("And here is the finally block!");
       if (reader != null) {
           reader.close();
       }
   }
}
이제 우리는 프로그램이 실행되는 동안 어떤 일이 발생하든 관계없이 점유된 리소스를 처리했음을 절대적으로 확신합니다. :) 이것이 예외에 대해 알아야 할 전부는 아닙니다. 오류 처리는 프로그래밍에서 매우 중요한 주제입니다. 두 개 이상의 기사가 이에 대해 다루고 있습니다. 다음 강의에서는 어떤 유형의 예외가 있는지, 그리고 자신만의 예외를 만드는 방법을 배우겠습니다. :) 거기서 만나요!
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION