에러(오류) 종류
- 시스템 에러: 컴퓨터의 오작동으로 인해 발생하는 에러 ⇒ 소스코드로 해결이 안됨( 가장 심각한 에러)
- 컴파일 에러: 소스코드상의 문법적인 문제로 발생하는 에러 ⇒ 소스코드 수정으로 문제 해결 가능(빨간 밑줄로 알려줌)
- 런타임 에러: 소스코드 상으로는 문제가 없는데 프로그램 실행 중 발생하는 에러 ⇒ 사용자의 잘못일 수도 있고, 개발자가 예측 가능한 경우를 제대로 처리 안해놓은 것 일수도 있음
- 논리 에러: 소스코드 상의 문법적인 문제도 없고(빨간 밑줄이 없다), 실행했을 때도 굳이 문제가 되지 않지만 프로그램 의도상 맞지 않는 오류 ⇒ 예를 들면 true 값이 들어가야 하는데 false가 들어가서 내 의도와 정반대로 실행되는 경우
시스템 에러를 제외한 컴파일 에러, 런타임 에러, 논리 에러와 같은 비교적 덜 심각한 것들을 “예외” 라고 한다.(Exception)
이러한 “예외”들이 “발생”했을 경우에 대비해서 “처리”하는 방법을 정의해둔 것을 “예외처리”라고 한다 ⇒ 만약에 XXX오류가 발생한다면 어떤 코드를 실행시킬래?( 일종의 조건문처럼 해석된다)
예외처리를 하는 이유: 예외 발생시 프로그램이 비정상적으로 종료되기 때문에 그것을 막고자 하기 위함
예외처리 방법
- try~catch 문을 이용
- throws를 이용 (떠넘기기)
RuntimeException 클래스
프로그램 실행시 발생되는 예외들의 부모클래스
RuntimeException 클래스의 자식클래스들
- ArrayIndexOutOfBoundsException : 배열의 부적절한 인덱스로 접근할 때 발생하는 예외
- NegativeArraySizeException : 배열의 크기를 음수로 지정할 경우 발생하는 예외
- ClassCastException : 허용할 수 없는 형변환이 진행될 경우 발생하는 예외
- NullPointerException: 주소값이 아직 null 임에도 불구하고 접근하고자 할 때 발생하는 예외
- ArithmeticException: 나누기 연산 시 0으로 나눌 때 발생하는 예외
⇒이러한 RuntimeException과 관련된 예외들은 충분히 예측 가능한 상황이기 때문에 예외 자체가 발생이 안되게끔 조건문으로 해결 가능함(권장)
⇒굳이 예외처리(예외가 발생했을 때 실행할 내용을 정의해두는것)를 할 필요가 없음
EX)사용자로부터 두 개의 정수값을 입력받아서 나눗셈 연산 결과를 출력
System.out.print("첫 번째 정수: ");
int num1=sc.nextInt();
sc.nextLine();
System.out.print("두 번째 정수: ");
int num2=sc.nextInt();
sc.nextLine();
해결방법1. 조건문으로 처리(애초에 예외 자체가 발생되지 않게끔 if문으로 조건검사 후 계산 진행)=>예외처리가 아님
if(num2!=0) { //나눗셈 진행
System.out.println("나눗셈 연산 결과: "+(num1/num2));
}else { //num2가 0이면
System.out.println("0으로 나눌 수 없음");
}
System.out.println("프로그램 종료");
해결방법2. 예외처리 구문으로 해결(예외가 발생했을 경우를 대비해서 실행할 내용을 미리 정의해두는것)
try~catch문
[표현법]
try{
//예외가 발생할법한 구문
}catch(발생될예외클래스 변수명){
//해당 예외가 발생할 경우 실행할 구문
}
EX)ArithmeticException, InputMismatchException 예외 발생
System.out.print("정수 입력(0 제외): ");
try {
int num=sc.nextInt(); //정수 이외의 값을 입력하면 InputMismatchException가 발생
sc.nextLine();
System.out.println("나눗셈 결과: "+(10/num)); // num이 0일 경우 ArithmeticException이 발생함
}catch(InputMismatchException e) {
System.out.println("정수를 입력해야함");
}catch(ArithmeticException e) {
System.out.println("0으로 나눌 수 없음");
e.printStackTrace(); //오류를 추적하는 메소드로 현재 예외가 발생한 정보를 볼 수 있다
}//다중 catch 블럭: 예외가 여러개 발생할 가능성이 있는 경우, 그 경우의 수만큼 catch 블럭을 작성 가능
System.out.println("프로그램 종료");
EX)NegativeArraySizeException, ArrayIndexOutOfBoundsException 예외 발생
System.out.print("배열의 크기: ");
int size=sc.nextInt();
sc.nextLine();
try {
int[] arr=new int[size];
System.out.println("100번째 인덱스값: "+arr[100]);
}catch(NegativeArraySizeException e) { //NegativeArraySizeException: 배열의 크기를 음수로 지정할 경우 발생하는 예외
System.out.println("배열의 크기로 음수를 제시할 수 없습니다");
}catch(ArrayIndexOutOfBoundsException e) { // ArrayIndexOutOfBoundsException: 배열의 부적절한 인덱스로 접근할 때 발생하는 예외
System.out.println("부적절한 인덱스로 접근했습니다");
}
System.out.println("프로그램 종료");
다형성을 접목하여 예외처리
System.out.print("배열의 크기: ");
int size=sc.nextInt();
sc.nextLine();
try {
int[] arr=new int[size];
System.out.println("100번째 인덱스값: "+arr[100]);
}catch(RuntimeException e) {
//다형성을 적용하여 부모 타입의 예외 클래스로 catch 블럭을 작성 가능
//장점: catch 블럭이 하나로 줄어듬
//단점: 정확히 어떤 오류가 발생했는지는 알 수 없음
System.out.println("배열의 크기를 음수로 입력했거나 부적절한 인덱스로 접근했음");
}
System.out.println("프로그램 종료");
System.out.print("배열의 크기: ");
int size=sc.nextInt();
sc.nextLine();
try {
int[] arr=new int[size];
System.out.println("100번째 인덱스값: "+arr[100]);
}catch(NegativeArraySizeException e) {
System.out.println("배열의 크기로 음수를 제시할 수 없습니다");
}catch(RuntimeException e) {
System.out.println("배열의 크기를 음수로 입력했거나 부적절한 인덱스로 접근했음");
}
//다중 catch 블럭의 경우 순서가 중요하다
//=>상대적으로 범위가 작은 자식타입의 예외클래스에 해당하는 catch 블럭을 먼저 기술해야 한다
//=>범위가 큰 부모클래스 먼저 기술한다면 자식클래스에 해당하는 catch블럭에서 Unreachable 오류가 발생한다
System.out.println("프로그램 종료");
RuntimeException 관련된 에러
- 조건문으로 해결 가능: 예외 자체가 발생 안되게끔 예방해주는 선처리 효과⇒개발자가 소스코드로 애초에 핸들링하는 것(예외처리X)
- 예외처리 구문으로 해결 가능: 예외가 발생할 시점을 대비해서 그 때 실행할 내용을 미리 정의해 두는것⇒예외가 발생하고 나서의 후처리 담당
- 예측이 가능한 상황⇒ 조건문으로 해결하는 것을 더 권장한다
- 예측이 불가능한 상황⇒ 예외처리 구문으로 해결해야 한다(안쓰면 컴파일오류 발생)
- RuntimeException=Unchecked Exception ⇒ 예측 가능한 예외
Checked Exception
반드시 예외처리를 해줘야 되는 예외들(즉, 예측 불가능한 상황에서 발생하기 때문에 미리 예외 처리 구문을 작성해야 함) ⇒ 주로 외부 매체와 어떤 입출력 시 발생
1. try ~ catch문 사용
//Scanner와 같이 키보드로 값을 입력받을 수 있는 객체를 하나 생성
//java.io.BufferedReader 클래스로부터 객체 생성(단, 문자열로만 입력이 가능)
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.print("아무 문자열이나 입력하세요: ");
//String str=br.readLine(); //한줄 단위로 사용자가 입력한 문자열을 입력받겠다
//이 메소드를 호출했을 때 IOException이 발생할수도 있음을 애초에 컴파일 에러로 알려준것(빨간 밑줄)
try {
String str=br.readLine();
System.out.println("문자열의 길이: "+str.length());
}catch(IOException e) {
System.out.println("예외 발생함");
}
2. throws문 사용
throws: ‘지금 여기서 당장 예외를 처리하겠다’가 아닌 현재 이 메소드를 호출한 곳에서 처리하게끔 떠넘기겠다. ⇒ 즉, 나를 호출한 곳에서 try~catch문을 쓰겠다
public void method1() {
try {
method2();
}catch(IOException e) {
System.out.println("예외 발생함");
}
}
//throws 구문 추가
public void method2() throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.print("아무 문자열이나 입력하세요: ");
String str=br.readLine();
System.out.println("문자열의 길이: "+str.length());
}
Runtime Exception (Unchecked Exception) : 예외 발생 시점(해당 코드가 실행되다가 오류나면)
⇒ 예외처리가 필수는 아님
Checked Exception : 예외 발생 시점(언젠가 실행되다가는 맞지만 반드시 처리를 해줘야하기 때문에 육안상 컴파일 에러로 보임)
⇒ 예외 처리가 필수임
'JAVA' 카테고리의 다른 글
[JAVA] 인터페이스 (0) | 2022.02.28 |
---|---|
[JAVA] 추상클래스 (0) | 2022.02.28 |
[JAVA] 상속 (0) | 2022.02.28 |
[JAVA] getter와 setter (0) | 2022.02.24 |
[JAVA] 객체와 클래스 (0) | 2022.02.22 |