예외 처리

예외 처리

반응형

프로그램에서의 오류

컴파일 오류

프로그램 코드 작성 중 발생하는 문법적 오류

프로그램 코드 작성 중 발생하는 문법적 오류 실행 오류

실행 중인 프로그램이 의도하지 않은 동작을 하거나 프로그램이 중지되는 오류

실행 오류는 비정상 종료가 되는 경우 시스템에 심각한 장애를 발생할 수 있음

예외 처리의 중요성

프로그램의 비정상 종료를 피하여 시스템이 원활하게 실행되도록 함

실행 오류가 발생한 경우 오류의 과정을 재현하는 것은 현실적으로 힘들다

오류가 발생한 경우 로그를 남겨서 추후 로그 분석을 통해 그 원인을 파악하여 버그를 수정하는 것이 중요

오류와 예외 클래스

시스템 오류 : 가상 머신에서 발생. 프로그래머가 처리할 수 없는 오류

동적 메모리가 없는 경우, 스택 메모리 오버플로우 등

동적 메모리가 없는 경우, 스택 메모리 오버플로우 등 예외 : 프로그램에서 제어할 수 있는 오류

읽어들이려는 파일이 존재하지 않거나, 네트워크나 DB 연결이 안되는 경우 등

읽어들이려는 파일이 존재하지 않거나, 네트워크나 DB 연결이 안되는 경우 등 자바는 안정성이 중요한 언어로 대부분 프로그램에서 발생하는 오류에 대해 문법적으로 예외 처리를 해야함

try-catch-finally

public class Test { public static void main(String[] args) { FileInputStream fis = null; try { fis = new FileInputStream("a.txt"); } catch (FileNotFoundException e) { System.out.println(e); } finally { if(fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } System.out.println("finally"); } System.out.println("END"); } }

java.io.FileNotFoundException: a.txt (지정된 파일을 찾을 수 없습니다) finally END

try-with-resources

리소스를 사용하는 경우 close()를 하지 않아도 자동으로 해제되도록 함

자바 7부터 제공되는 구문

리소스를 try() 내부에서 선언해야만 함

해당 리소스 클래스가 AutoCloseable 인터페이스를 구현해야 함

FileInputStream의 경우에는 AutoCloseable을 구현하고 있음

자바 9부터 리소스는 try() 외부에서 선언하고 변수만을 try(obj)와 같이 사용할 수 있음

public class AutoCloseableObj implements AutoCloseable{ @Override public void close() throws Exception { System.out.println("closing"); } }

public class Test { public static void main(String[] args) { AutoCloseableObj obj = new AutoCloseableObj(); try(obj){ throw new Exception(); } catch(Exception e){ System.out.println("exception"); } System.out.println("end"); } }

closing exception end

예외 처리 미루기

public class ThrowsException { public Class loadClass(String fileName, String className) throws ClassNotFoundException, FileNotFoundException { FileInputStream fis = new FileInputStream(fileName); Class c = Class.forName(className); return c; } public static void main(String[] args) { ThrowsException test = new ThrowsException(); try { test.loadClass("a.txt", "abc"); } catch (ClassNotFoundException e) { System.out.println(e); } catch (FileNotFoundException e) { System.out.println(e); } catch (Exception e) { System.out.println("Default Exception. 최상위 Exception"); } System.out.println("end"); } }

사용자 정의 예외 클래스

자바에서 제공하는 예외 클래스 외에 프로그래머가 직접 만들어야 하는 예외가 있을 수 있음

기존 예외 클래스 중 가장 유사한 예외 클래스에서 상속받아 사용자 정의 예외 클래스를 만든다.

기본적으로 Exception 클래스를 상속해서 만들 수 있음

※ 패스워드에 대한 예외 처리하기

public class PasswordException extends Exception { public PasswordException(String message){ super(message); } }

public class PasswordTest { private String password; public String getPassword() { return password; } public void setPassword(String password) throws PasswordException{ if(password == null){ throw new PasswordException("비밀번호는 null일 수 없습니다."); } else if(password.length() < 5){ throw new PasswordException("비밀번호는 5자 이상이어야 합니다."); } else if(password.matches("[a-zA-Z]+")){ throw new PasswordException("비밀번호는 숫자나 특수문자를 포함해야 합니다."); } this.password = password; } public static void main(String[] args) { PasswordTest test = new PasswordTest(); String password = null; try { test.setPassword(password); } catch (PasswordException e) { System.out.println(e.getMessage()); // 비밀번호는 null일 수 없습니다. } password = "abc"; try { test.setPassword(password); } catch (PasswordException e) { System.out.println(e.getMessage()); // 비밀번호는 5자 이상이어야 합니다. } password = "abcde"; try { test.setPassword(password); } catch (PasswordException e) { System.out.println(e.getMessage()); // 비밀번호는 숫자나 특수문자를 포함해야 합니다. } password = "abcde1s"; try { test.setPassword(password); System.out.println("잘 입력되었습니다."); // 잘 입력되었습니다. } catch (PasswordException e) { e.printStackTrace(); } } }

오류의 로그를 남기기 (java.util.logging.Logger)

※ logging

시스템 운영에 대한 기록

오류가 발생했을 때 그 오류에 대한 기록을 남겨 디버깅을 용이하게 함

로그 파일에 기록하는 코드를 추가하여 필요한 정보가 로그로 남을 수 있도록 한다

디버깅, 시스템 에러 추적, 성능, 문제점 향상 등을 위해 사용

어느정도까지 로그를 남길 것인가?

너무 적은 로그 : 정확한 시스템의 상황을 파악하기 어려움

너무 많은 로그 : 빈번한 FILE I/O의 오버헤드와 로그 파일의 백업 문제 등

※ java.util.logging

자바에서 기본적으로 제공되는 log package

파일이나 콘솔에 로그 내용을 출력할 수 있음

jre/lib/logging.properties 파일을 편집하여 로그의 출력방식 로그 레벨을 변경할 수 있음

logging 패키지에서 제공하는 로그 레벨은 severe, warning, info, config, fine, finer, finest 임

오픈소스로는 log4j를 많이 사용하고 있음

※ Logger 만들기

시나리오

학생 정보 시스템에 로그를 기록하도록 한다.

학생의 이름에 오류가 있는 경우 예외 처리를 하고 예외 상황을 로그로 남긴다.

학생의 이름은 null 이거나 중간에 space가 3개 이상인 경우 오류가 발생한다.

학생 정보 시스템에 로그를 기록하도록 한다. 학생의 이름에 오류가 있는 경우 예외 처리를 하고 예외 상황을 로그로 남긴다. 학생의 이름은 null 이거나 중간에 space가 3개 이상인 경우 오류가 발생한다. 구현하기

Logger 인스턴스를 생성한다.

로그를 남기기 위한 FileHandler를 생성한다.

FileHandler의 level을 지정하고

Logger에 생성된 addHandler() 메서드로 FileHandler를 추가한다.

import java.io.IOException; import java.util.logging.FileHandler; import java.util.logging.Level; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; public class MyLogger { Logger logger = Logger.getLogger("mylogger"); private static MyLogger instance = new MyLogger(); public static final String errorLog = "log.txt"; public static final String warningLog = "warning.txt"; public static final String fineLog = "fine.txt"; private FileHandler logFile = null; private FileHandler warningFile = null; private FileHandler fineFile = null; private MyLogger(){ try{ logFile = new FileHandler(errorLog, true); warningFile = new FileHandler(warningLog, true); fineFile = new FileHandler(fineLog, true); } catch (SecurityException e){ e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } logFile.setFormatter(new SimpleFormatter()); warningFile.setFormatter(new SimpleFormatter()); fineFile.setFormatter(new SimpleFormatter()); logger.setLevel(Level.ALL); fineFile.setLevel(Level.FINE); warningFile.setLevel(Level.WARNING); logger.addHandler(logFile); logger.addHandler(warningFile); logger.addHandler(fineFile); } public static MyLogger getLogger(){ return instance; } public void log(String msg){ logger.finest(msg); logger.finer(msg); logger.fine(msg); logger.config(msg); logger.info(msg); logger.warning(msg); logger.severe(msg); } public void fine(String msg){ logger.fine(msg); } public void warning(String msg){ logger.warning(msg); } }

public class LoggerTest { public static void main(String[] args) { MyLogger myLogger = MyLogger.getLogger(); myLogger.log("test"); } }

11월 12, 2021 3:50:35 오전 Inner.MyLogger log INFO: test 11월 12, 2021 3:50:35 오전 Inner.MyLogger log WARNING: test 11월 12, 2021 3:50:35 오전 Inner.MyLogger log SEVERE: test

public class StudentNameFormatException extends IllegalArgumentException{ public StudentNameFormatException(String message){ super(message); } }

public class Student { private String studentName; MyLogger myLogger = MyLogger.getLogger(); public Student(String studentName){ if(studentName == null){ throw new StudentNameFormatException("name must not be null"); } if(studentName.split(" ").length > 3){ throw new StudentNameFormatException("name is too long"); } this.studentName = studentName; } public String getStudentName(){ myLogger.fine("begin getStudentName()"); return studentName; } }

public class StudentTest { public static void main(String[] args) { MyLogger myLogger = MyLogger.getLogger(); String name = null; try{ Student student = new Student(name); } catch (StudentNameFormatException e){ myLogger.warning(e.getMessage()); } try { Student student = new Student("Edward Jon KIm Test"); } catch (StudentNameFormatException e){ myLogger.warning(e.getMessage()); } Student student = new Student("James"); } }

11월 12, 2021 3:52:18 오전 Inner.MyLogger warning WARNING: name must not be null 11월 12, 2021 3:52:18 오전 Inner.MyLogger warning WARNING: name is too long

반응형

from http://yunseodozpwf.tistory.com/38 by ccl(A) rewrite - 2021-11-12 04:01:47