에러: 개발자가 해결할 수 없는 치명적인 오류 (문법적으로 불가한 내용)
예외: 개발자가 해결할 수 있는 오류 (문법은 가능하나 로직을 수정하면 정상적으로 수행가능)
실행 예외
예외가 발생하면 JVM은 해당하는 실행 예외 객체를 생성한다.
실행 예외는 컴파일러가 예외 처리 여부를 확인하지 않는다. -> 개발자가 예외 처리 코드를 추가
- Arithmeticexception
- 13/0 같은 것
- IllegalArgumentException
- 메서드 매개변수에 맞지않는 인수 전달할 때
- IndexOutOfBoundsException
- 인덱스 범위 벗어날 때
일반 예외
컴파일러는 에러가 발생할 가능성을 발견하면 컴파일 오류를 발생시킨다.
- 인덱스 범위 벗어날 때
- ClassNotFoundException
- 존재하지 않는 클래스를 사용하려고 할 때
- etc..
예외 처리 방법
try - catch 문
try{
//예외 발생
}catch(예외클래스1 참조변수){
//핸들러
}catch(예외클래스2 참조변수){
//핸들러
}
위에서 예외 발생 클래스가 다르고 핸들러가 같을 경우 다음과 같이 쓸 수 있다.
try{
//예외 발생
}catch(예외클래스1 | 예외클래스2 참조변수){
//핸들러
}
finally: 예외 처리와 상관 없이 항상 실행을 한다.
try{
//예외 발생
}catch(예외클래스1 | 예외클래스2 참조변수){
//핸들러
}finally{
System.out.print("항상 실행1");
}
System.out.print("항상 실행2");
위에서 "항상 실행1"구문과 "항상 실행2"구문은 예외 처리하고 무조건 실행을 하는데 굳이 finally를 써야하는가?
아니다. > 다만 가독성을 위해, 이 구문을 강조하기 위해 사용한다.
예외 떠넘기기
메서드에서 발생한 예외를 내부에서 처리하기가 부담스러울 땐 throws 키워드를 사용해 예외를 상위 코드
블록으로 양도가 가능하다.
사용방법을 보자
public class ThrowsDemo{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
try{
square(in.nextLine());
}
catch(NumberFormatException e){
}catch(Arithmeticexception e){
}
}
private static void square(String e) throws Arithmeticexception, NumberFormatException {
int n = Intger.parseInt(s);
System.out.println(n/0);
}
}
위 코드를 보면, square 메소드에서 예외를 던진다. 이때 throw하는 예외 케이스는 두 가지이다. 산술 연산 예외, 숫자 형식 예외
입력 받은 숫자가 string이 아닐 경우 NumberFormatException를
위를 잘 수행하고 나면 n/0이 실행되는데 이 때 Arithmeticexception를 발생시켜 main함수에 던지고
main에서 catch하여 처리한다.
- throw는 1개 이상의 예외를 던질 수 있다.
- 상위 블록으로 던져서 사용이 가능하다
- 형식은
function(매개변수) throw 예외 클래스 { 함수 정의 }
이다.강제 예외 발생
-> throw new Exception();
-> 정상 동작하더라도 이 구문을 만나면 강제로 예외를 던진다.
Thread.sleep는 꼭 예외처리를 해주어야 한다.
예외 떠넘기기로 넘겨도 되고 자신이 처리를 해주어도 된다.
하지만 예외 떠넘기기로 넘겨주면 정상작동 하지 못한다.
제네릭
제네릭: 정해지지 않은 자료형, 실행 중에 자료형이 결정된다.
(c++의 템플릿같은 존재)
제네릭 객체 생성
제네릭클래스 <적용할 타입> 변수 = new 제네릭클래스<>();
실 사용
public class Cup<T>{ private T beverage; public T getBeverage(){ return beverage; } pbulic void setBeverage(T beverage){ this.beverage = beverage; } } public class Source{ public static void main(String[] args){ Cur<Boricha> c = new Cup<Boricha>(); c.setBeverage(new Boricha()); Boricha b = c.getBeverage(); } }
Cup 클래스 내 beverage 필드는 타입이 정해지지 않았다.
하지만 객체생성하면서 Boricha라는 타입으로 만들어준다.
따라서 c라는 인스턴스는 Boricha라는 beverage의 필드를 가지게 된다.
약속
- E: Element
- K: Key
- N: Number
- T: Type
- V: Value
제네릭 제약
- 기초 타입을 제네릭 인수로 사용불가
- int -> Integer
- double -> Double
- etc..
- 정적 제네릭 타입 사용금지
- 정적 타입들은 프로그램 실행과 동시에 메모리에 메서드 영역에 올라간다
- 제네릭은 프로그램 실행 중에 타입이 결정되므로 정적 타입으로 사용이 불가하다.
- 제네릭 타입의 인스턴스화 금지
- new T() 불가!!
- 제네릭 타입의 배열 생성 금지
- 제네릭은 정해지지 않은 자료형이다보니 배열을 생성하게되면 메모리 공간을 제대로 할당이 불가하다.
- 실행 중에 제네릭 타입 점검 금지
- 변수 instance of ArrayLIst
금지!!
- 변수 instance of ArrayLIst
제네릭 클래스의 객체
는 예외로 던지거나 잡을 수 없다.- 제네릭의 서브 타입을 허용하지 않는다.
- 기초 타입을 제네릭 인수로 사용불가
메서드에서 매개변수를 사용: 타입 매개변수를 사용한다는 의미
<타입매개변수> 반환타입 메서드명(){}
실사용
public static <T extends Number> void showArray(T[] a){ for(T t : a) ... } public static void main(String[] args){ Intger[] ia = {1, 2}; Charcter[]ca = {'H', 'E'} showArray(ia); //1번 showArray(ca); //2번 }
1번에서 매개변수를 Integer타입으로 넣어주었다.
- showArray메소드는 모두 Integer 타입의 변수로 사용이 가능하다.
하지만 2번에서 에러가 발생한다.
- extends Number로 즉 받는 매개변수 타입들은 Number 클래스 내에 있는 타입으로 제한된다.
- 2번은 Charcter이므로 에러 발생한다.
extends로 제한하기
- 부모가 인터페이스인 경우도 implements가 아닌 extends로 사용한다.
'Java > 이론 정리' 카테고리의 다른 글
배열 (0) | 2021.01.19 |
---|---|
객체 지향 (0) | 2021.01.19 |
Java 기본 문법 (0) | 2021.01.19 |
최근댓글