CodeGym /Java Blog /무작위의 /예외: 잡기 및 처리
John Squirrels
레벨 41
San Francisco

예외: 잡기 및 처리

무작위의 그룹에 게시되었습니다
안녕! 언급하기 싫지만 프로그래머 작업의 상당 부분은 오류를 처리하는 것입니다. 대부분 자신의 것입니다. 실수하지 않는 사람은 없다는 것이 밝혀졌습니다. 그리고 그러한 프로그램도 없습니다. 예외: 잡기 및 처리 - 1 물론 오류를 처리할 때 가장 중요한 것은 그 원인을 이해하는 것입니다.. 그리고 많은 것들이 프로그램에 버그를 일으킬 수 있습니다. 어느 시점에서 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. 출력: 스레드 "main"의 예외 java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt(시스템이 지정된 경로를 찾을 수 없음) Java에서 각 예외는 별도의 클래스로 표시됩니다. 이러한 모든 예외 클래스는 공통 "조상"인 Throwable상위 클래스에서 파생됩니다. 예외 클래스의 이름은 일반적으로 예외가 발생한 이유를 간결하게 반영합니다.
  • FileNotFoundException(파일을 찾을 수 없습니다)

  • ArithmeticException(수학적 연산을 수행하는 동안 예외가 발생했습니다)

  • ArrayIndexOutOfBoundsException(인덱스가 배열 범위를 벗어납니다). 예를 들어, 요소가 10개인 배열의 위치 23을 표시하려고 하면 이 예외가 발생합니다.
대체로 Java에는 거의 400개의 이러한 클래스가 있습니다! 왜 그렇게 많은가요? 프로그래머가 더 편리하게 작업할 수 있도록 합니다. 이것을 상상해 보십시오: 프로그램을 작성하고 실행하는 동안 다음과 같은 예외를 생성합니다.

Exception in thread "main"
어. :/ 그다지 도움이 되지 않습니다. 오류가 무엇을 의미하는지 또는 어디에서 왔는지 명확하지 않습니다. 유용한 정보가 없습니다. 그러나 Java의 매우 다양한 예외 클래스는 프로그래머에게 가장 중요한 것, 즉 오류 유형과 가능한 원인(클래스 이름에 포함됨)을 제공합니다. 그것은 보는 또 다른 것입니다

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (The system cannot find the specified path)
문제가 무엇인지, 문제를 해결하기 위해 어디서부터 파헤쳐야 하는지가 즉시 명확해집니다! 모든 클래스의 인스턴스와 같은 예외는 개체입니다.

예외 포착 및 처리

Java에는 예외 작업을 위한 특수 코드 블록( trycatch) 이 있습니다 finally. 예외: 잡기 및 처리 - 2 프로그래머가 예외가 발생할 수 있다고 생각하는 코드는 try블록에 배치됩니다. 여기서 예외가 발생한다는 의미는 아닙니다. 여기서 발생할 수 있다는 뜻이고, 프로그래머는 이 가능성을 알고 있습니다. 발생할 것으로 예상되는 오류 유형이 블록에 배치됩니다 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블록 의 괄호 안에 다른 예외 클래스를 넣으면 FileNotFoundException잡히지 않습니다.

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!");
   }
}
출력: "main" 스레드의 예외 java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt(시스템이 지정된 경로를 찾을 수 없음) 블록 의 코드가 catch실행되지 않았습니다. 우리가 "구성"했기 때문입니다. 이 블록은 를 catch ArithmeticException하고 블록의 코드는 try다른 유형을 던졌습니다 FileNotFoundException. 을 처리하는 코드를 작성하지 않았 FileNotFoundException으므로 프로그램은 에 대한 기본 정보를 표시합니다 FileNotFoundException. 여기서 세 가지에 주목해야 합니다. 첫번째. 블록 의 일부 라인에서 예외가 발생하면 try다음 코드는 실행되지 않습니다. 프로그램 실행은 즉시 해당 catch블록으로 "점프"합니다. 예를 들어:

public static void main(String[] args) {
   try {
       System.out.println("Divide 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("will not");
       System.out.println("be");
       System.out.println("executed!");

   } catch (ArithmeticException e) {

       System.out.println("The program jumped to the catch block!");
       System.out.println("Error! You can't divide by zero!");
   }
}
출력: 0으로 나누기 프로그램이 catch 블록으로 점프했습니다! 오류! 0으로 나눌 수 없습니다! 블록 의 두 번째 줄에서 try0으로 나누기를 시도하여 ArithmeticException. 결과적으로 블록의 3-9행은 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. FileNotFoundException블록 에서 a가 발생하면 try첫 번째 catch블록이 실행됩니다. 가 ArithmeticException발생하면 두 번째 블록이 실행됩니다. catch원한다면 50개의 블록을 쓸 수 있습니다 . 물론 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. 이제 컴파일러는 "이봐, 나는 이 코드를 승인하지 않을 것이고 이러한 예외 중 하나가 발생하면 어떻게 해야 하는지 알려줄 때까지 컴파일하지 않을 것이다. !" 우회할 방법이 없습니다. 둘 다 처리해야 합니다! 우리는 이미 첫 번째 예외 처리 방법에 대해 알고 있습니다. 코드를 블록에 넣고 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("File input/output error!");
       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 then calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
오류가 발생했습니다! 이 코드는 컴파일되지 않습니다! 메서드 에 예외 처리 코드를 작성하지 않았습니다 printFirstString(). 결과적으로 이 작업은 이제 이 방법을 사용하는 사람들의 어깨에 떨어졌습니다. 즉, 메서드에는 이제 동일한 두 가지 옵션이 있습니다. 블록을 사용하여 두 예외를 모두 처리하거나 다시 throw해야 methodWrittenByYourColleague()합니다 .try-catch

public static void yourColleagueMethod() throws FileNotFoundException, IOException {
   // The method does something

   //...and then calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
두 번째 경우에는 호출 스택의 다음 메서드(호출하는 메서드)가 methodWrittenByYourColleague()예외를 처리해야 합니다. 이것이 우리가 이것을 "예외 발생 또는 전달"이라고 부르는 이유입니다. 키워드를 사용하여 예외를 위로 던지면 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's the finally block!");
   }
}
이 예에서 블록 내부의 코드는 finally두 경우 모두 실행됩니다. 블록 의 코드가 try예외를 발생시키지 않고 완전히 실행되면 finally블록이 마지막에 실행됩니다. 블록 내부의 코드가 try예외에 의해 중단되고 프로그램이 블록으로 점프하면 catch블록 finally내부의 코드 다음에 블록이 계속 실행됩니다 catch. 이것이 필요한 이유는 무엇입니까? 주요 목적은 필수 코드를 실행하는 것입니다. 즉, 상황에 관계없이 수행되어야 하는 코드입니다. 예를 들어 프로그램에서 사용하는 일부 리소스를 해제하는 경우가 많습니다. 코드에서 스트림을 열어 파일에서 정보를 읽고 개체에 전달합니다 BufferedReader. 판독기를 닫고 리소스를 해제해야 합니다. 이것은 프로그램이 정상적으로 작동할 때와 예외가 발생했을 때 어떤 경우에도 수행되어야 합니다. 블록 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's the finally block!");
       if (reader != null) {
           reader.close();
       }
   }
}
이제 우리는 프로그램이 실행 중일 때 어떤 일이 발생하든 관계없이 리소스를 관리할 것이라고 확신합니다. :) 예외에 대해 알아야 할 전부는 아닙니다. 오류 처리는 프로그래밍에서 매우 중요한 주제입니다. 많은 기사가 그것에 전념합니다. 다음 단원에서는 어떤 유형의 예외가 있는지, 그리고 자신만의 예외를 만드는 방법을 알아볼 것입니다. :) 그때 만나!
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION