
1. 예외 처리
1) Exception
: 프로그램에서 발생할 수 있는 예외 상황을 객체로 취급하는 클래스
- java.lang.Exception
- 모든 예외의 최상위 클래스임
① 예외 : 예측 할 수 있는 문제상황, 적절한 처리를 통해 처리할 수 있음
② 에러 : 코드 상의 결함으로 발생하는 프로그램 내부에서 처리할 수 없는 문제상황
→ 코드의 방향이 잘못되었기 때문에 코드 자체를 수정해야함
2) 예시
① 정수를 입력받아 출력하도록 하는 코드
Scanner sc = new Scaner(System.in);
int n1;
System.out.print("정수 입력 : ");
n1 = sc.nextInt();
System.out.println("n1 : " + n1);
sc.close();
- 코드 실행 중, 만약 사용자가 정수가 아닌 값을 입력하면 예외가 발생함
- Exception in thread "main" java.util.InputMismatchException

~ 예외 처리
Scanner sc = new Scanner(System.in);
int n1;
String input;
System.out.print("정수 입력 : ");
input = sc.next();
if(isNumeric(input)) { // if가 본래 목적과 다르게 사용됨
n1 = Integer.parseInt(input);
System.out.println("n1 : " + n1);
}
else {
System.err.println("정수를 입력하지 않았습니다 !");
}
sc.close();

② 배열에 정수를 저장하는 코드
int[] arr = new int[5];
arr[5] = 30;
System.out.println(arr[5]);
- 배열의 범위보다 높은 값을 넣으면 예외가 발생함
- Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException

3) try ~ catch
- if는 프로그램의 분기를 나눔
→ 예외처리에 if를 사용하는 경우에는 if가 본래 목적과 다르게 사용됨
→ 분기를 나누는 if인지, 예외를 처리하는 if인지 일일이 구별을 해야함
→ try ~ catch를 사용
import java.util.InputMismatchException;
import java.util.Scanner;
public class Ex02 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n1;
System.out.print("정수 입력 : ");
try { // 다음 코드를 시도하여
n1 = sc.nextInt();
System.out.println("n1 : " + n1);
} catch(InputMismatchException e) {
// 지정한 타입의 예외가 발생하면 객체 e로 받음
System.out.println(e.getMessage());
e.printStackTrace(); // 예외 발생 스택을 순서대로 출력함
System.err.println("정수를 입력해야 합니다.");
}
System.out.println("끝"); // 예외가 발생하더라도 코드는 실행함
sc.close();
}
}
- printStackTrace() : 예외 발생 스택을 순서대로 출력함
- try ~ catch를 사용하면, 예외가 발생하더라도 코드는 끝까지 실행됨

- 예시
① 배열의 범위를 넘어서는 값을 입력했을 때 발생하는 예외 처리
~ 방법 1)
import java.util.InputMismatchException;
import java.util.Scanner;
public class Ex03 {
public static void main(String[] args) {
int[] arr = { 10, 30, 20, 40, 50 };
Scanner sc = new Scanner(System.in);
int index;
System.out.print("몇번째 정수를 출력할까요 : ");
try {
index = sc.nextInt();
System.out.printf("arr[%d] : %d\n", index, arr[index]);
} catch(ArrayIndexOutOfBoundsException e) {
// System.out.println(e); // e.toString()
System.err.println("index의 범위를 넘어서는 값을 입력했습니다.");
}
}
}

~ 방법 2)
try {
System.out.print("몇번째 정수를 출력할까요 : ");
index = sc.nextInt();
System.out.printf("arr[%d] : %d\n", index, arr[index]);
} catch(ArrayIndexOutOfBoundsException e) {
// System.out.println(e); // e.toString()
System.err.println("index의 범위를 넘어서는 값을 입력했습니다.");
} catch(InputMismatchException e) {
// System.out.println(e);
System.err.println("정수를 입력해야 합니다.");
} finally {
sc.close();
System.out.println("프로그램 종료");
}
- finally : 예외 발생 여부에 상관없이 무조건 수행하는 코드

* 함수에서 return은 종료를 의미하지만, return 이후에도 finally는 반드시 수행하고 함수가 종료됨
static void test() {
try {
System.out.println("try");
return;
} finally {
System.out.println("Finally !");
}
}
} finally {
sc.close();
System.out.println("프로그램 종료");
}
test();
} // end of main

- 직접 만든 클래스로 예외를 규정할 수 있음
- 배열에 중복된 값이 들어오면 예외가 발생하도록 하는 코드
~ 중복을 확인하는 함수
static boolean isDuplicate(String[] arr, String str) {
for(int i = 0; i < arr.length; i++) {
if(str.equals(arr[i])) {
return true;
}
}
return false;
}
~ 배열의 모든 칸에 문자열이 들어있는지 확인하는 함수
static boolean isFull(String[] arr) {
for(int i = 0; i< arr.length; i++) {
if(arr[i] == null) {
return false;
}
}
return true;
}
~ 배열의 빈 칸에 요소를 추가하는 함수
static void insert(String[] arr, String str) {
for(int i = 0; i < arr.length; i++) {
if(arr[i] == null) {
arr[i] = str;
break;
}
}
}
~ main 함수
public static void main(String[] args) {
String[] arr = new String[5];
Scanner sc = new Scanner(System.in);
String str;
while(isFull(arr) == false) {
System.out.print("문자열 입력 : ");
str = sc.nextLine();
if(isDuplicate(arr, str)) {
// 내가 규정한 새로운 예외 객체를 생성한다.
try {
// 내가 직접 만든 클래스로도 예외를 규정하고 사용할 수 있음
MyException ex = new MyException();
throw ex; // throw로 예외 객체를 던지면
} catch(MyException e) { // catch가 받을 수 있음
// System.out.println("이미 입력된 데이터입니다.");
// System.out.println(e);
e.printStackTrace();
continue;
// break의 반대. 반복문에서 위로 탈출하여 다시 반복문을 수행함
}
}
insert(arr, str); // 입력 받은 객체가 중복이 아니라면 insert 실행
}
~ 배열 출력
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
sc.close();
}
}
② 두 정수와 연산자를 입력받아서 결과를 화면에 출력하는 코드를 작성하기 (해당 과정에서 발생할 수 있는 예외를 try ~ catch 구문으로 작성)
~ 강사님 풀이 : switch ~ case문 사용
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n1, n2, result;
char oper;
try {
System.out.print("n1 : "); n1 = Integer.parseInt(sc.nextLine());
System.out.print("연산 : "); oper = sc.nextLine().charAt(0);
System.out.print("n2 : "); n2 = Integer.parseInt(sc.nextLine());
switch(oper) {
case '+': result = n1 + n2; break;
case '-': result = n1 - n2; break;
case '*': result = n1 * n2; break;
case '/': result = n1 / n2; break;
default:
MyOperatorException ex = new MyOperatorException();
throw ex;
}
System.out.println("결과 : " + result);
} catch(NumberFormatException e) { // 문자열을 숫자로 변환할 때 발생할 수 있는 예외
System.out.println("정수를 입력해야 합니다");
} catch(ArithmeticException e) { // 정수를 0으로 나눌때 발생할 수 있는 예외
System.out.println("정수를 0으로 나눌 수 없습니다");
} catch(MyOperatorException e) { // 연산자에 지정된 문자 이외 값을 입력할 경우 발생시키는 예외
e.printStackTrace();
} catch(Exception e) { // 모든 예외를 받아서
System.out.println(e);
System.out.println(e.getMessage());
e.printStackTrace(); // 예외 발생 현황을 추적하면서 출력한다 (기본값)
} finally {
sc.close();
}
System.out.println("종료");
}
~ 내 풀이 : if문 사용
import java.util.Scanner;
class MyExcept extends Exception {
private static final long serialVersionUID = 1L;
@Override
public String toString() { // Override from Object
return "연산자가 아닌 다른 값을 입력받았습니다.";
}
@Override
public String getMessage() { // Override from Throwable
return "연산자가 아닌 다른 값을 입력받았습니다.";
}
}
public class Ex05 {
static boolean notOperation(char oper) {
if(oper == '+' || oper == '-' || oper == '*' || oper == '/' || oper == '%') {
return true;
}
return false;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n1;
int n2;
char oper;
double result = 0;
try {
System.out.print("정수1 입력 : ");
n1 = Integer.parseInt(sc.nextLine());
System.out.print("정수 2 입력 : ");
n2 = Integer.parseInt(sc.nextLine());
System.out.print("연산자 입력 : ");
oper = sc.nextLine().charAt(0);
if(notOperation(oper) == false) {
try {
MyExcept ex = new MyExcept();
throw ex;
} catch(MyExcept e) {
// 연산자에 지정된 문자 이외 값을 입력할 경우 발생시키는 예외
System.err.println("연산자가 아닌 값을 입력했습니다.");
}
}
else {
if(oper == '+') result = n1 + n2;
else if(oper == '-') result = n1 - n2;
else if(oper == '*') result = n1 * n2;
else if(oper == '/') result = n1 / n2;
else if(oper == '%') result = n1 % n2;
System.out.printf("%d %c %d = %.2f", n1, oper, n2, result);
}
} catch(NumberFormatException e){ // 문자열을 숫자로 변환할 때 발생할 수 있는 예외
System.err.println("int형 정수가 아닌 값을 입력했습니다.");
} catch(ArithmeticException e) { // 정수를 0으로 나눌때 발생할 수 있는 예외
System.err.println("0으로는 나눌 수 없습니다.");
} catch(Exception e) { // 모든 예외를 받아서
System.out.println(e);
System.out.println(e.getMessage());
e.printStackTrace(); // 예외 발생 현황을 추적하면서 출력함 (기본값)
// 가급적이면 마지막에 사용할 것
} finally {
sc.close();
}
System.out.println("종료");
}
}
4) throws
: 현재 함수에서 발생한 예외의 처리를 caller에게 전가시킴
void method1 throws NullPointerException {
String str = null;
System.out.println(str.charAt(0));
}
void method2() throws ArrayIndexOutOfBoundsException{
int[] arr = { 2, 7, 8, 4, 6 };
System.out.println(arr[5]);
}
- 예외를 처리할 때에는 해당 함수 내부에서 try ~ catch를 사용해서 처리할 지, 아니면 throws를 사용
public static void main(String[] args) {
Test6 ob = new Test6();
try {
ob.method1();
} catch(NullPointerException e) {
// throws NullPointerException (런타임 예외라서 처리 안해도 실행 가능)
System.out.println("NullPointerException");
}
try {
Thread.sleep(1000);
// throws InterruptedException (런타임 예외가 아니라서 의무적으로 처리)
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
ob.method2();
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("ArrayIndexOutOfBoundsException");
}
}
- RuntimeException : 의무적으로 처리하지 않아도 되는 예외
→ throws NullPointerException (런타임 예외라서 처리 안해도 실행 가능)
→ throws InterruptedException (런타임 예외가 아니라서 의무적으로 처리)
2. Thread
1) Thread 클래스
: 하나의 프로그램에서 여러 함수가 동시다발적으로 실행되도록 처리하는 클래스
2) 사용 순서
① Thread 클래스를 상속한 새로운 클래스를 작성함
② Thread 클래스의 public void run() 메서드를 오버라이딩하여 원하는 내용을 작성함
③ 새로운 클래스의 객체를 생성하여 start() 메서드를 호출함
- 예시 ) 숫자와 알파벳을 동시에 출력하는 코드
~ 0 ~ 25까지의 숫자를 출력하는 클래스 만들기
→ Thread 클래스를 상속한 클래스를 작성하고, Thread 클래스의 run()을 오버라이딩하여 다중 작업하고 싶은 내용을 작성함
→ 함수로 작성해도 되고, 함수의 내용을 바로 작성해도 됨
class N extends Thread {
void show() {
for(int i = 0; i < 25; i++) {
System.out.print(i + " ");
}
}
@Override
public void run() {
show();
}
}
~ A ~ Z 까지의 알파벳을 출력하는 클래스 만들기
class A {
void show() {
for(char ch = 'A'; ch <= 'Z'; ch++) {
System.out.print(ch + " ");
}
}
- 실행내용을 작성한 함수이지만, 다중실행은 되지 않음
- run() 메서드의 내용을 별도의 스레드에서 실행하도록 함
~ main 함수
public static void main(String[] args) {
N ob1 = new N();
A ob2 = new A();
// ob1.show();
// ob1.run(); // 실행내용을 작성한 함수이지만, 다중실행은 되지 않음
ob1.start(); // run() 메서드의 내용을 별도의 스레드에서 실행하도록 함
ob2.show();
System.out.println();
}
4) Runnable 인터페이스
- 자바에서 다중 스레드를 구현하려면, Thread 클래스를 상속해야 함
- 자바에서는 다중 상속을 허용하지 않음
- 이미 슈퍼클래스를 가지는 클래스를 스레드로 처리하기 위해서는 Runnable 인터페이스를 상속받아야함
class NumberThread extends Object implements Runnable {
@Override
public void run() {
for(int i = 0; i < 10; i++) {
System.out.print(i + " ");
}
}
}
public static void main(String[] args) {
NumberThread ob = new NumberThread();
Thread th = new Thread(ob);
th.start();
→ Runnable 객체를 Thread 생성자 매개변수로 전달함
→ start를 호출하면, run()의 내용을 별도의 스레드에서 실행함
~ Runnable은 함수형 인터페이스라서, 람다식 객체 생성이 가능함
Thread th2 = new Thread(() -> {
for(char ch = 'a'; ch <= 'z'; ch++) {
System.out.print(ch + " ");
}
});
th2.start();
new Thread(() -> System.out.print("Hello ")).start();
for(char ch = 'A'; ch <= 'G'; ch++) {
System.out.print(ch + " ");
}
System.out.println();
}

- 예시) 10초동안 얼마나 많은 문자열을 입력할 수 있는지 확인하는 코드
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
class Timers extends Object implements Runnable {
private int second;
private boolean over;
public Timers(int second) {
this.second = second;
}
public void check() {
for(int i = second; i != -1; i--) {
System.out.printf("\t[%02d:%02d]\n", i / 60, i % 60);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
}
over = true;
}
public boolean isOver() {
return over;
}
@Override
public void run() {
check();
}
}
~ 10초가 지나면 지금까지 입력받은 모든 문자열을 한줄씩 출력함
public class Ex09 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
List<String> list = new ArrayList<String>();
Timers timer = new Timers(10);
Thread th = new Thread(timer);
th.start();
// timer.check();
while(timer.isOver() == false) {
System.out.print("문자열 입력 : ");
list.add(sc.nextLine());
}
list.forEach(str -> System.out.println(str));
sc.close();
'JAVA > JAVA Note' 카테고리의 다른 글
| [JAVA Note] 22. 직렬화 (1) | 2022.11.16 |
|---|---|
| [JAVA Note] 21. 파일 입출력 (1) | 2022.11.16 |
| [JAVA Note] 19. Collection (1) | 2022.11.16 |
| [JAVA Note] 18. Object (0) | 2022.11.06 |
| [JAVA Note] 17. 추상화 (0) | 2022.11.06 |
댓글