티스토리 뷰
1. 예외처리코드 ( 다중 catch )
- 예외별로 예외 처리 코드를 다르게 구현한다.
- Ex. try { } catch ( ArratIndexOutOfBoundsException e ) { 예외처리 1 } catch ( NumberFormatException e ) { 예외처리 2 }
- Catch의 순서는 예외 클래스에서 부모 타입을 아래로 자식 클래스를 위에 작성해야 한다.
- Why? 왜냐하면 상위 클래스를 위에 작성하면 밑에 하위 클래스를 작성하지 않아도 예외를 위에서 다 잡아버리기에 특정 예외별로 다른 코드를 작성하려면 자식타입을 먼저 작성해야 한다.
2. 예외처리코드 ( 멀티 catch )
- 자바 7부터는 하나의 catch 블록 내에서 여러 개의 예외처리가 가능하다.
- 동일하게 예외처리를 하고 싶을 때에는 예외를 |로 연결하면 된다.
- Ex. catch( ArratIndexOutOfBoundsException | NumberFormatException e ) { 예외처리
3. 제네릭 ( Generic )
- 제네릭 ( generic ) : 일반적인, 보편적인
- (1) 제네릭은 기본타입을 대상으로 하지 않고, 참조타입을 대상으로 하는 타입이다.
- 제네릭 타입이란? :
- 컴파일 단계에서 잘못된 타입이 사용될 수 있는 문제를 제거할 수 있다.
- 타입을 파라미터(매개변수)로 가지는 클래스와 인터페이스
- 즉, 제네릭 타입은 매개변수로 참조타입을 준다.
- 이때 타입은 int가 아닌 integer와 같은 Wrapper type을 사용한다.
- 제네릭 타입은 선언 시 클래스 또는 인터페이스 이름 뒤에 “ < 매개변수의 이름 > “를 붙인다.
- 이때 “ < > “ 사이에 들어가는 것을 “타입 파라미터(매개변수)”라고 부른다.
- 타입 파라미터는 일반적으로 대문자 알파벳 1글자로 표현한다.
- 개발코드에서는 타입 파라미터 자리에 구체적인 타입을 지정해야 한다.
- 제네릭은 참조타입과 더불어 아래의 3군데에서 사용된다.
- 1. 클래스 - > 제네릭 타입의 클래스
- 2. 인터페이스 - > 제네릭 타입의 인터페이스
- 3. 메소드 - > 제네릭 타입의 메소드
- 타입을 파라미터(매개변수)로 가지는 클래스와 인터페이스
01. 다중 catch
package multi_catch;
public class CatchByExceptionKindExample {
public static void main (String[] args) { // 다중 catch (****)
try {
// ArrayIndexOutOfBoundsException 예외가 발생가능한 코드 - 배열에 원소를 지정해 주지 않았다.
String data1 = args[0];
String data2 = args[1];
// ============================================================
// NumberFormatException 예외가 발생가능한 코드
int value1 = Integer.parseInt(data1);
int value2 = Integer.parseInt(data2);
// ============================================================
// 예외처리 코드는 메소드에 마우스를 올려놓으면 throws뒤에 어떤 예외 코드가 발생할지 적혀있기에 이를 참고하면 된다. (**)
int result = value1 + value2;
System.out.println(data1 + "+" + data2 + "=" + result);
} catch ( ArrayIndexOutOfBoundsException e) { // 예외처리 1
System.out.println("실행매개값의 수가 부족합니다.");
System.out.println("[실행방법]");
System.out.println("java CatchByExceptionKindExample num1 num2");
} catch ( NumberFormatException e) { // 예외처리 2
System.out.println("숫자로 변환할 수 없습니다.");
} finally { // ( optional ) 항상 실행할 코드 작성
System.out.println("다시 실행하세요.");
} // try - catch - finally
} // main
} // end class
02. 다중 catch - catch의 순서
package multi_catch;
public class CatchOrderExample {
public static void main (String[] args) { // 다중 catch - catch의 순서 (****)
try {
// ArrayIndexOutOfBoundsException 예외가 발생가능한 코드 - 배열에 원소를 지정해 주었다. [ 1, a2 ] // OK!
String data1 = args[0];
String data2 = args[1];
// ============================================================
// NumberFormatException 예외가 발생가능한 코드
int value1 = Integer.parseInt(data1);
int value2 = Integer.parseInt(data2);
// ============================================================
// 예외처리 코드는 메소드에 마우스를 올려놓으면 throws뒤에 어떤 예외 코드가 발생할지 적혀있기에 이를 참고하면 된다. (**)
int result = value1 + value2;
System.out.println(data1 + "+" + data2 + "=" + result);
} catch ( ArrayIndexOutOfBoundsException e) { // 예외처리 1 - 자식타입을 위에 작성하고,
System.out.println("실행매개값의 수가 부족합니다.");
System.out.println("[실행방법]");
System.out.println("java CatchByExceptionKindExample num1 num2");
} catch ( Exception e) { // 예외처리 2 - 부모타입을 아래에 적어야 한다!!
System.out.println("숫자로 변환할 수 없습니다.");
} finally { // ( optional ) 항상 실행할 코드 작성 - 옵션이기에 작성하지 않아도 괜찮다.
System.out.println("다시 실행하세요.");
} // try - catch - finally
// 출력 결과 :
// 숫자로 변환할 수 없습니다.
// 다시 실행하세요.
} // main
} // end class
03. 멀티 catch
package multi_catch;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class MultiCatchExample { // 멀티 catch 작성 방법 (*****)
private static void staticMethod() throws Exception { // 메소드에 throws 작성방법 (***)
throw new Exception(); // 예외가 발생하면 throw할 예외객체를 생성해야 한다. (***)
} // staticMethod - throws 뒤에 적는 예외코드의 의미는 예외코드가 발생할 수 있다는 의미이다.
// throw는 실제로 예외코드를 던지는 것이고, throws는 미리 예외코드가 발생할 수 있음을 알려주는 것이다.
public static void main (String[] args) throws Exception { // 멀티 catch (****)
// main도 예외를 위로 던져야 하기 때문에 staticMethod에 작성한 발생할 수 있는 예외 코드를 throws와 같이 작성해야 한다.
try {
String data1 = args[0]; // 배열에 원소를 넣어 주지 않았다.
String data2 = args[1];
int value1 = Integer.parseInt(data1);
int value2 = Integer.parseInt(data2);
int result = value1 + value2;
System.out.println(data1 + "+" + data2 + "=" + result);
MultiCatchExample.staticMethod(); // 정적 멤버는 정적멤버답게 사용하자! (**)
} catch ( ArrayIndexOutOfBoundsException | NumberFormatException e) { // |를 통해서 같은 예외처리코드를 사용할 예외코드를 동시에 작성한다.
System.out.println("실행 매개값의 수가 부족하거나 숫자로 변환할 수 없습니다.");
} catch ( Exception e) { // 예외처리 2 - 부모타입을 아래에 적어야 한다!!
System.out.println("알 수 없는 예외 발생!");
} finally { // ( optional ) 항상 실행할 코드 작성 - 옵션이기에 작성하지 않아도 괜찮다.
System.out.println("다시 실행하세요.");
} // try - multi catch
//
// 출력 :
// 실행 매개값의 수가 부족하거나 숫자로 변환할 수 없습니다.
// 다시 실행하세요.
} // main
} // end class
04. 멀티 catch 02
package multi_catch;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class MultiCatchExample2 {
private static void staticMethod(String name) throws Exception { // 메소드에 throws 작성방법 (***)
throw new IllegalArgumentException(); // 예외가 발생하면 throw할 예외객체를 생성해야 한다. (***)
} // staticMethod - throws 뒤에 적는 예외코드의 의미는 예외코드가 발생할 수 있다는 의미이다.
// throw는 실제로 예외코드를 던지는 것이고, throws는 미리 예외코드가 발생할 수 있음을 알려주는 것이다.
// throws의 다형성 적용 : (*****)
// throws와 throw에 다른 예외코드를 작성해도 정상작동 되기도 하는데
// 그때는 throws 뒤에 부모타입 throw 뒤에 자식타입이 올 때 다형성 적용으로 가능해 진다.
public static void main (String[] args) { // 멀티 catch (****)
// main도 예외를 위로 던져야 하기 때문에 staticMethod에 작성한 발생할 수 있는 예외 코드를 throws와 같이 작성해야 한다.
// try {
//
// String data1 = args[0]; // 배열에 원소를 넣어 주지 않았다.
// String data2 = args[1];
//
// int value1 = Integer.parseInt(data1);
// int value2 = Integer.parseInt(data2);
//
// int result = value1 + value2;
//
// System.out.println(data1 + "+" + data2 + "=" + result);
try {
MultiCatchExample2.staticMethod("1000");
} catch (Exception e) {
e.printStackTrace(); // 오류 뜬 것을 표시해준다.
}
// } catch ( ArrayIndexOutOfBoundsException | NumberFormatException e) { // |를 통해서 같은 예외처리코드를 사용할 예외코드를 동시에 작성한다.
//
// System.out.println("실행 매개값의 수가 부족하거나 숫자로 변환할 수 없습니다.");
//
// } catch ( Exception e) { // 예외처리 2 - 부모타입을 아래에 적어야 한다!!
// System.out.println("알 수 없는 예외 발생!");
// } finally { // ( optional ) 항상 실행할 코드 작성 - 옵션이기에 작성하지 않아도 괜찮다.
// System.out.println("다시 실행하세요.");
// } // try - multi catch
//
// 출력 :
// 실행 매개값의 수가 부족하거나 숫자로 변환할 수 없습니다.
// 다시 실행하세요.
} // main
} // end class
05. 응용
package org.zerock.myapp.banking;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@NoArgsConstructor
public class Account {
// 고유 속성
String owner;
String Number;
String bank;
// 상태 필드
@Getter @Setter int balance = 0; // 잔고 - 롬복을 활용하여 게터와 세터 생성
boolean valid = true; // 통장상태 - 계좌의 유효여부
public Account(String owner, String Number, String bank) {
this.owner = owner;
this.Number = Number;
this.bank = bank;
} // constructor 생성자
boolean deposit(int money) { // 입금
// balance = balance + money;
balance += money; // 누적
return ( balance >= 0) ? true : false;
} // deposit
boolean withdraw(int money) { // 출금
balance -= money;
return ( balance >= 0) ? true : false; // 출금 금액 빼주기
} // withdraw
boolean isValid ( ) {
return true;
} // isValid
} // end class
package org.zerock.myapp.banking;
public class Customer {
String name;
String ssn;
void requestTransfer() {
// 사용관계
Teller teller = new Teller();
Account sourceAccount = new Account("Yoseph", "1234-5678", "Bank1");
sourceAccount.setBalance(5000000); // 롬복을 통해 세터 자동생성
Account targetAccount = new Account("target", "5678-1234", "Bank2");
targetAccount.setBalance(0);
Money transferMoney = new Money(1000000);
try {
boolean isSuccess = teller.processRequest(sourceAccount , targetAccount , transferMoney);
if(isSuccess) { // 이체 성공
System.out.println("친구야 힘내!!");
} // if
} catch (InvalidAccountException | InsufficentBalanceException e) { // 2가지의 예외를 잡고 있다.
System.out.println("친구야 이체가 안된다ㅠㅠ");
e.printStackTrace(); // (*****)
} // try-catch
} // requestTransfer 메소드
} // end class
package org.zerock.myapp.banking;
import lombok.NoArgsConstructor;
//사용자 정의 예외 클래스 선언 - 비지니스 상 예외를 의미한다.
@NoArgsConstructor
public class InsufficentBalanceException extends RuntimeException { // 시시각각 변하는 경우에는 부모로 런타임예외를 사용하는 것이 좋다.
// + checked 예외는 Exception을 상속받는 것이, 실행예외는 RuntimeException을 상속받는 것이 좋다. (***)
InsufficentBalanceException(String message){
super(message); // 부모를 사용
} // InsufficentBalanceException constructor
} // end class
package org.zerock.myapp.banking;
import lombok.NoArgsConstructor;
// 사용자 정의 예외 클래스 선언 - 비지니스 상 예외를 의미한다.
@NoArgsConstructor
public class InvalidAccountException extends RuntimeException { // 예외타입 만들기 (****)
// public InvalidAccountException () {} // default constructor < - - 롬복이 대신 생성해 주었다.
public InvalidAccountException(String message) { // 메세지 남기기
super(message); // 부모인 RuntimeException(String) 사용
} //constructor
} // end class
package org.zerock.myapp.banking;
import lombok.Getter;
public class Money {
@Getter int amount; // 얼마인지
public Money(int amount) {
this.amount = amount;
} // constructor
} // end class
package org.zerock.myapp.banking;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class Teller { // 은행원
boolean processRequest(Account source, Account target, Money transfermoney)
throws InvalidAccountException, InsufficentBalanceException { // 2 개의 예외가 발생할 수 있음을 알려줌
//예외가 발생하면, 발생한다고 메소드 옆에 적어야 한다. (***)
// 그러나 실행 예외는 컴파일러가 확인하지 못하기에, 실행예외는 메소드 옆에 작성하지 않아도 괜찮다.
// 하지만, 그렇게 되면 협업하는 동료가 헷갈릴 수 있기에 작성하여 알려주는 것이 좋다.
// 컴파일러 예외는 throws로 작성해주지 않으면, 바로 오류가 발생하게 된다.(***)
// 1. 소스계좌와 타겟계좌가 모두 유효한가?
if( source.isValid() & target.isValid()) { // Happy Path : 이체 수행
// 소스계좌와 타겟계좌가 모두 유효해야지 true!
int sourceBalance = source.getBalance();
int transMoney = transfermoney.getAmount();
/// 2. 잔고확인
if ( sourceBalance > transMoney) { // 잔고확인
if(source.withdraw(transMoney)) { // 소스계좌에서 transferMoney만큼 뺀다. 소스계좌에서 출금이 성공하면...
boolean isSuccess = target.deposit(transMoney);
System.out.println("이체 성공!");
return isSuccess;
} // if- else 3
return true; // 바깥 if문
} else { // 잔고 부족 : 2. 예외를 발생시킨다. (*****)
throw new InsufficentBalanceException("잔고가 부족합니다.");
} // inner if-else
} else { // Alternative (계좌가 유효하지 않으면 ) : 1. 예외를 발생시킨다. (*****)
throw new InvalidAccountException("계좌가 유효하지 않음");
} // if-else
} // processRequest
} // end class
06. 제네릭 타입
package generic_type;
public class Apple {
;;
} // end class
package generic_type;
public class Box {
private Object object;
public void set ( Object object ) { // 이때 Object는 모든 객체의 조상인 그 Object를 의미하기에 뭐든지 들어갈 수 있다.(**)
this.object = object; // ( Lvalue는 부모객체, Rvalue는 자식객체이다 )
} // setter
public Object get () {
return object;
} // getter
} // end class
package generic_type;
public class BoxExample {
public static void main(String[] args) {
Box box = new Box();
box.set("홍길동"); // 다형성1
String name = (String) box.get(); // object타입을 string타입으로 강제형변환시키고 있다.
// ========================================
box.set(new Apple()); // 다형성1
Apple apple = (Apple) box.get(); // object타입을 Apple타입으로 강제형변환시키고 있다.
} // main
} // end class
'KH 정보교육원 [ Java ]' 카테고리의 다른 글
KH 20일차 - 람다식과 함수적 인터페이 (0) | 2022.03.26 |
---|---|
KH 19일차 - 제네릭 타입 (0) | 2022.03.25 |
KH 17일차 - 인터페이스와 예외처리 (0) | 2022.03.22 |
KH 16일차 - 추상 클래스 및 인터페이스 (0) | 2022.03.21 |
KH 15일차 - protected 접근제한자 및 프로모션 (0) | 2022.03.18 |