Exception

류기탁·2021년 12월 14일
0

Java

목록 보기
1/5

예측 가능한 문제를 선제적으로 대응하고 해결하기

1. 예외처리

가. 에러

프로그램이 비정상적으로 종료되고 오작동 되는 경우. 발생시점에 따라 다음과 같이 나눌 수 있다.

  • 컴파일에러 : 컴파일 시에 발생하는 에러
  • 런타임에러 : 실행시에 발생하는 에러
  • 논리적에러 : 실행은 되지만, 의도와 다르게 동작하는 것

    스택 오버플로우, 메모리 부족 등이 있다.

나. 예외(Exception)

  • 프로그램 코드에 대해 수습될 수 있는 비교적 상태가 약한 에러.
  • Exception Handling이란 예외 처리이다.

다. 예외 클래스

Checked Exception 대처코드가 없으면, 컴파일을 진행하지 않음
UnChecked Exception 예외에 대한 대처 코드가 없더라도 컴파일은 진행됨
Error 계열 예측이 불가능함 예외에 대한 대처코드
런타임 에러 예측가능한 모든 예외 이 문제는 코드를 개선해야지, try catch 하면 안됨.

라. 예외 처리 - try / catch

  • try블록에서 에외가 발생하면, JVM이 Exception 클래스 객체생성후 던진다.(throw)
  • 던져진 exception을 처리할 수 있는 catch 블록에서 받은 후 처리한다.
        int[] intArray = {10};
        try { //문제 발생 가능 코드
        	System.out.println(intArray[2]);
        } catch (Exception e) { // 예외 처리 코드
        	System.out.println("프로그램 종료합니다.");
        	}
        }

마. Throwable 메소드

메소드설명
public String getMessage발생된 예외에 대한 구체적인 메시지를 반환한다.
public Throwable getCause()예외의 원인이 되는 Throwable 객체나 NULL을 반환한다.
print StackTrace()예외가 발생된 메소드가 호출되기 까지의 메소드 호출 스택을 출력한다. 디버깅의 수단으로 주로 사용된다.

바. 다중 예외처리

try블록에서 여러종류의 예외가 발생한 경우
하나의 try 블록에서 여러개의 catch 블록이 추가 가능하다.

    try {
        //코드
    } catch () {
        // 1번 예외
    } catch () {
        // 2번 예외
    } catch (Exception e){
        // Exception e 는 모든 예외 
    }

    public static void main(String[] args) {
         try {
            Class.forName("abc.Def"); // ClassNotFoundException
            new FileInputStream("Hello.java"); // FileNotFoundException
            DriverManager.getConnection("Hello"); // SQLException
            // TODO: 다양한 예외를 처리하는 코드를 작성하시오.
         } catch (ClassNotFoundException e) {
        	 System.out.println(e.getMessage());
         } catch (FileNotFoundException e ) {
        	 System.out.println(e.getMessage());
         } catch (SQLException e) {
        	 System.out.println(e.getMessage());
         }
         System.out.println("프로그램 정상 종료");

사. finally

finally는 예외 발생 여부와 상관없이 언제나 실행한다.
return 이 있더라도, finally블록을 먼저수행하구 return을 실행한다.

  • 목적 : try 블록에서 사용한 리소스을 반납하고자 할 때
 public static void main(String[] args) {
        // TODO: InstallApp을 이용하면서 자원이 확실히 정리되도록 해보자.
    	InstallApp install = new InstallApp();
    	install.copy();
    	try {
    		install.install();
    	} catch (Exception e) {
    		e.printStackTrace();
    	} finally {
    		install.delete();
    	}
        // END:
        System.out.println("설치 종료");

    }

아. throws

메소드에서 처리해야할 하나 이상의 예외를 호출한 곳을 전달한다.
처리위임인 것이다.
전달 받은 메소드는 예외 처리의책임이 생긴다.

 public static void main(String[] args)   {
        try{
        	methodCall1();
        } catch (ClassNotFoundException e) {
        	e.printStackTrace();
        }
        System.out.println("done");
    }

    private static void methodCall1() throws ClassNotFoundException  {
        methodCall2();
    }

    private static void methodCall2() throws ClassNotFoundException   {
        checkedExceptionMethod();
        uncheckedExceptionMethod();
    }

    private static void checkedExceptionMethod() throws ClassNotFoundException {
        Class.forName("Hello");
    }

자. throw

고의로 예외를 발생시킬수 있다.

    public static void main(String args[]) {
        try {
            Exception e = new Exception("고의로 발생시킴");
            throw e ;
            // 위두문장을
            throw new Exception("고의로 발생") // 으로 줄일 수 있다.
        }
    }

2. 가이드

몇 가지 오류 예시들, 해결 방법

가. 생성자, 초기화 오류

  • super클래스에 기본 생성자가 없는데 생성자를 호출할 때
  • 생성자 부분에서 객체를 생성하는데 안해서 nullpointException이 발생
  • 부모에서 default 생성자를 만들어서 인자가 있는 생성자를 호출한다.

나. 자바 예외 종류 예외발생, 처리 방법

예시

오류 발생 : 밑의 코드에서 throws 뒤에 빨간 줄 그어 있다.
원인 : 폴더안에 QuantityException과 똑같은 클래스가 있다.

@Override
	public void sell(String isbn, int quantity) throws QuantityException, ISBNNotFoundException {
		Book book = searchByIsbn(isbn);				// 고유번호 도서 조회
		if(book == null) throw new ISBNNotFoundException(isbn); // 고유번호 도서 조회 실패시 ISBNNotFoundException 사용자 정의 예외 발생시킴
		
		int res = book.getQuantity() - quantity;	// 판매 후 새로운 재고 수량 계산
		if(res < 0) throw new QuantityException();	// 재고수량 부족시 QuantityException 사용자 정의 예외 발생시킴
		
		book.setQuantity(res); 						// 판매후 남은 재고수량으로 재고수량 변경
	}

해결 : 상위 예외 클래스를 상속받아줘야하고, 새로 선언해주자.

public class QuantityException extends RuntimeException { // extends RuntimeException이 포인트이다.
	public QuantityException() {
		super("수량부족");
	}

}
public class ISBNNotFoundException  extends RuntimeException{

	/**	존재하지 않는 도서 고유번호 */
	private String isbn;
	
	/** 고유번호를 받아 생성하는 생성자 */
	public ISBNNotFoundException(String isbn) { // 이렇게 받아서 처리할 수도 있다.
		this.isbn = isbn;
	}
	/**
	 * 존재하지 않는 도서 고유번호를 반환한다.
	 * @return 존재하지 않는 도서 고유번호
	 */
	public String getIsbn() {
		return isbn;
	}
}

다. Overriding 오류 - Object 클래스 메소드

  • Equals / hashcode 를 오버라이드 하지 않아서 오류가 발생
  • 싱글톤디자인으로 만들지 않은 경우 Getter메소드 들을 static public으로 하지 않을 때 / private를 불러오는 경우

예시 : toString 오버라이딩

오류 발생 :

Multiple markers at this line
- overrides java.lang.Object.toString
- Cannot reduce the visibility of the
inherited method from Object

 String toString() {
		return isbn + '\t' + "| " + title + "  \t" + "| " + author + '\t' + "| " + publisher + '\t'
				+ "| " + price + '\t' + "| " + desc + '\t'+ "| " + quantity + '\t';
	}

해결 : public 을 붙여줌.

public String toString() {
		return isbn + '\t' + "| " + title + "  \t" + "| " + author + '\t' + "| " + publisher + '\t'
				+ "| " + price + '\t' + "| " + desc + '\t'+ "| " + quantity + '\t';
	}

라. Singleton 오류

  • 싱글톤 패턴이란, 전역변수를 사용하지 않고, 객체를 하나만 생성하도록 하며, 생성된 객체를 어디에서 든지 참조할 수 있도록 하는 패턴이다.
  • 싱글톤 코드
package com.jurib.debugex;

public class SigletonTest {

	public static void main(String[] args) {
        //		Myclass2 mc = new Myclass(); 
		// 문제 1: 싱글통이라 이렇게 객체 못만든다.
		Myclass2 mc = Myclass2.getInstance();
		// 해결 1 : 이렇게 만들어줘야한다.
	}

}

class Myclass2{
	private int x;
	private static Myclass2 inst = new Myclass2();

	private  Myclass2(){
		this.x = 5;
	}
	public static Myclass2 getInstance() {
		return inst;
	}
}
// 메인 :
Myclass2 single 

class MyClass1 {
	private int[] array;
    // 핵심 2 : 자기 자신의 멤버 변수를 가져야함.
	private static MyClass1 instance = new MyClass1(); 	
    // instance: 자기자신을 가짐

    // 핵심 1 : 생성자를 private으로 만들어야함
	private MyClass1() {
		this.array = new int[5];	// 생성자: private, 멤버 변수 초기화
	}
	
    // 핵심 3 : public으로 접근 할 수 있게 만들어줘야한다.
	public static MyClass1 getInstance() {
		return instance;
	}

	public int[] getArray() {
		return array;
	}

}

마. Serializable 오류

package KDS04;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Test_Serialzable {
	//
	public static void main(String[] args) throws Exception {	
		// 해당 클래스에 Serializable 인터페이스 implements하기
		// writeObject하기
		// readObject하기
		// 객체 출력하기 (toString 오버라이딩)
		// 객체 직렬화
        
		Myclass mc = new Myclass(1,"2","3");
		ObjectOutputStream oos = new ObjectOutputStream(
				new FileOutputStream("aaa.dat")
				);
		// 객체를 스트림화 시키
		// 오류 1 : fileNotException 
		// 1 해결 : main 옆에 throws 붙여주기 

		
		// 파일로 저장한 경우
		oos.writeObject(mc);
		// 오류 2 : Exception in thread "main" java.io.NotSerializableException: KDS04.Myclass
		// 해결 2 : 클래스에 시리얼라이즈블 임플리먼트하기
		
		// 파일저장했으니까, 읽어야됨
		// 읽어올 때는 캐스팅
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("aaa.dat"));

		// 오류 3: Type mismatch: cannot convert from Object to Myclass
		// 해결 3: 형변환 밑에와 같이
		// 
		//		Myclass mc2 = ois.readObject(); 
		Myclass mc2 = (Myclass) ois.readObject();
		// (ArrayList<머시기>) 이런것도 넣어줘야함
		
		// 읽었으니까, 출력하기
		System.out.println(mc2);
		// 오류 4 : toString이 없는 경우
		// 클래스에서 toString() 메소드 만들어주기 
		
		
		// 문제 2222: 싱글톤 디자인패턴 해주기
		// 복습해보자.
	}

}

// 해결2 : 임플리먼트 씨리얼 라이즈블 
class Myclass implements Serializable {
	int i;
	String s;
//	String ssn; // 대충번호
	transient String ssn; // transient 붙여주면 ㅣ비밀번호 효과 뜸
	
	// 해결2 : 이거 밑에거 써주기
	private static final long seiralVersionUID = 1L;
	private static final long serialVersionUID = 1L;

	public Myclass(int i, String s, String ssn) {
		this.i = i;
		this.s = s;
		this.ssn = ssn;
	}

	// 해결 4
	@Override
	public String toString() {
		return "Myclass [i=" + i + ", s=" + s + ", ssn=" + ssn + "]";
	}
	
	
}

바. Comparable과 Comparator 코딩 오류

package com.jurib.debugex;

import java.util.ArrayList;
import java.util.Collections;

public class ComparatorTest {

	// 방법1. 대상 클래스에 Comparable 인터페이스 implements하고 compareTo 함수 오버라이딩하기
	// 방법2. Lambda식 Comparator 사용하기

	public static void main(String[] args) {
		MyClass2Manager manager = new MyClass2Manager();
		
		// 방법1
		Collections.sort(manager.getList());
		for (MyClass2 mc : manager.getList()) {
			System.out.println(mc); // 출력하려면 대상클래스에 toString 오버라이딩 하기
		}
		Collections.sort(manager.getList());
		
		// 방법2
		Collections.sort(manager.getList(), (mc1, mc2) -> mc1.str.compareTo(mc2.str));
		for (MyClass2 mc : manager.getList()) {
			System.out.println(mc); // 출력하려면 대상클래스에 toString 오버라이딩 하기
		}

	}

}

class MyClass2 implements Comparable<MyClass2> {
	int i;
	String str;

	public MyClass2(int i, String str) {
		this.i = i;
		this.str = str;
	}

	@Override
	public int compareTo(MyClass2 o) {
		return this.i - o.i; 			 //	int 비교할 때
		//return this.str.compareTo(o.str); String 비교할 때
	}

	@Override
	public String toString() {
		return "MyClass2 [i=" + i + ", str=" + str + "]";
	}

}

class MyClass2Manager {

	private ArrayList<MyClass2> al = new ArrayList<>();

	public ArrayList<MyClass2> getList() {
		return al;
	}

	public MyClass2Manager() {
		al.add(new MyClass2(3, "222"));
		al.add(new MyClass2(1, "111"));
		al.add(new MyClass2(2, "333"));
	}

}
profile
오늘도 행복한 하루!

0개의 댓글