AWS 클라우드환경 네이티브 수업 68일차
진행
1. 예외처리
2. 스레드
아파서 결석했음.....
요약
1. 예외처리(Exception)
(try~ catch , 예외클래스의 계층구조와 종류, finally, throws와 throw)
2. 스레드 (Thread 개념, Join, Runnable)
3. ArrayList
예외처리 (Exception)
0으로 나눈다거나 배열에서 없는 인덱스 값을 불러오는 등, 오류가 날 상황이 많다.
이런 오류를 무시하거나 오류 시 적절한 처리를 하고 싶을 때 사용한다.
구조는 아래와 같다.
try {
내용
} catch(예외1) {
내용
} catch(예외2) {
내용
}
try 의 문장에서 예외 발생 X => catch 다음의 문장들은 수행이 되지 않는다.
try 의 문장에서 예외 발생 O => 예외에 해당되는 catch문이 수행된다.
- catch의 괄호 안에는 처리하려고 하는 예외와 같은 타입의 참조변수를 선언해야한다.
- 여러개의 catch가 있을 시 () 안의 참조변수와 생성된 instanceof 연산자를 이용하여 검사
=> true 면 {} 문장 실행, false 면 넘어간다. - 모든 예외 클래스는 Exception 클래스의 자손이기 때문에 Exception 으로 선언하면 모든 예외가 잡힌다.
아래의 예를 보자.
package Lecture;
public class Lecture1 {
public static void main(String[] args) {
System.out.println(1);
System.out.println(2);
try {
System.out.println(3);
System.out.println(0/0); // 예외발생
System.out.println(4); // 건너뜀
} catch (ArithmeticException error1) { // 실행됨
System.out.println(5);
}
System.out.println(6);
}
}
결과
1
2
3
5
6
try 안의 문장을 진행하다 예외가 발생하는 순간
예외처리 구문으로 이동해서 진행되는 것을 확인할 수 있다.
또한 catch는 여러개 사용이 가능하다.
package Lecture;
public class Lecture1 {
public static void main(String[] args) {
System.out.println(1);
System.out.println(2);
try {
System.out.println(3);
System.out.println(0/0); // 예외발생
System.out.println(4); // 이 구문은 실행되지 않는다.
// 여러개의 catch는 아래로 갈수록 범위가 넓어져야한다.
} catch(ArithmeticException ae) {
// instanceof는 객체 타입을 확인하는 연산자
// 형변환 가능여부를 확인하며 true / false 로 결과를 반환
if(ae instanceof ArithmeticException)
System.out.println("true");
System.out.println("ArithmeticException");
} catch(Exception e) { // ArithmeticException을 제외한 모든 예외가 처리된다.
System.out.println("Exception");
}
System.out.println(6);
}
}
결과
1
2
3
true
ArithmeticException
6
위의 예문을 보면 catch () 안의 쓸 수 있는 예외는 또 무엇이 있는지 궁금할거당.
예외는 어떤 것들이 있는지 알아보도록 하자.
Exception의 계층구조 및 종류
예외를 다루는 클래스들의 최상위 클래스는 Throwable
이를 상속하는 클래스는 각각 Exception과 Error
Error는 메모리가 부족하다든지 하는 치명적인 에러를 말한다. 코드로 처리하고 싶어도 처리가 안된다.
반면에 Exception은 try~catch로 잡을 수 있는 작은 에러이다.
Exception의 종류
Exception (Checked Exception)
- 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외
- Exception 처리 코드 여부를 compiler가 check
=> 따라서, 예외를 처리 하지 않으면 컴파일 자체가 되지 않는다.
예) 사용자가 존재하지 않는 파일을 처리하려 한다던지 (FileNotFoundException),
입력한 데이터의 형식이 잘못되었다던지 (DataFormatException)
=> 반드시 처리 필요.
RuntimeException (Unchecked Exception)
- 프로그래머의 실수로 발생하는 예외
- 컴파일하는 데는 문제가 없지만 code적인 부분의 에러므로 실행하면 문제가 발생
보통 자주 사용되는 예외는 RuntimeException이고 종류는 아래와 같다.
RuntimeException의 종류 | 설명 |
ArithmeticException | 수학적 예외 / Ex) 0으로 나눔 |
NullPointerException | 레퍼런스가 null을 참조할 때 발생 |
ArrayIndexOutOfBoundsException | 배열의 범위를 초과할 때 |
NegativeArraySizeException | 배열의 크기가 음(-)일 때 |
ArrayStoreException | 배열에 대입하는 값이 올바르지 않을 때 |
IllegalArgumentException | 매개 변수에 잘못된 값이 대입될 때 |
SecurityException | 보안상의 예외 |
finally
try~catch 문과 상관없이 예외가 발생해도 반드시 실행을 시키고 싶을 때 사용하는 구문이다.
아래의 예를 보면서 이해해보자.
package Lecture;
public class Lecture1 {
public static void main(String[] args) {
System.out.println(1);
System.out.println(2);
try {
System.out.println(3);
System.out.println(0/0); // 예외발생
System.out.println(4); // 실행 안됨
} catch(ArithmeticException error1) {
// printStackTrace()
// 예외발생 당시의 호출스택(call stack)에 있었던 메서드의 정보와
// 예외 메시지를 화면에 출력.
error1.printStackTrace();
// getMessage() - 발생한 예외 클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.
System.out.println("예외 메세지 : " + error1.getMessage());
} finally {
System.out.println("finally를 수행해야 집에 갈 수 있습니다.");
}
System.out.println(6);
}
}
결과
1
2
3
java.lang.ArithmeticException: / by zero
at Lecture.Lecture1.main(Lecture1.java:13)
예외 메세지 : / by zero
finally를 수행해야 집에 갈 수 있습니다.
6
throws와 throw
예외를 강제로 발생시키고 싶을 때 사용하는 구문이다.
throws는 예외를 발생시킬 가능성이 있는 메소드에 exception이 있을 수 있다~ 선언할 때 사용하고,
throw는 강제로 예외를 발생시키는 경우에 사용한다.
각각의 사용법은 아래와 같다.
public void doException() throws Exception {
if (...) {
throw new Exception();
}
}
먼저 throws의 예를 보면서 이해해보자.
package Lecture;
public class Lecture1 {
static void ArrayError(int size) throws NegativeArraySizeException{
int[] a=new int[size]; // size가 음수일 때만 예외 발생
System.out.println(a.length);
}
public static void main(String[] args){
try{
ArrayError(10); // 양수가 들어감. 예외가 발생하지 않음
}catch(NegativeArraySizeException e){
System.out.println("배열의 크기는 양수여야해");
}
}
}
결과
10
위의 ArrayError 메소드가 양수로 들어가면 정상적으로 배열이 생성됨으로 예외가 발생하지 않는다.
하지만 음수가 들어가게 된다면 아래와 같은 결과가 나온다.
package Lecture;
public class Lecture1 {
static void go(int size) throws NegativeArraySizeException{
int[] a=new int[size]; // size가 음수일 때만 예외 발생
System.out.println(a.length);
}
public static void main(String[] args){
try{
go(-1); // 양수가 들어감. 예외가 발생하지 않음
}catch(NegativeArraySizeException e){
System.out.println("배열의 크기는 양수여야해");
}
}
}
결과
배열의 크기는 양수여야해
이처럼 throws는 예외를 발생시킬 수도 있는 메소드에 사용한다.
다음으로 throws의 예를 보면서 이해해보자.
package Lecture;
public class Lecture1 {
public static void main(String[] args) {
try {
Exception e = new Exception("고의로 Exception을 발생시켰습니다.");
throw e; // 예외를 발생시킨다.
// 위의 두 줄을 한 줄로 줄여쓸 수 있다.
// throw new Exception("고의로 Exception을 발생시켰습니다.");
} catch (Exception e) {
System.out.println("에러 메세지 : " + e.getMessage());
}
System.out.println("프로그램이 정상 종료되었습니다.");
}
}
스레드 (Thread)
동작하고 있는 프로그램을 프로세스(Process)라고 한다.
보통 한 개의 프로세스는 한 가지의 일을 하지만, 쓰레드를 이용하면 한 프로세스 내에서
두가지 이상의 일을 동시에 할 수 있다.
스레드의 구조는
1. 넣고자 하는 클래스에 Thread를 상속
2. 해당 클래스 안에 run() 이라는 메소드 추가
3. 메인 메소드에서 start() 라는 메소드로 실행
구동방식은
스레드 클래스 메인에서 스레드 클래스의 객체를 만들고
start() 메소드를 사용하면 run() 메소드가 실행되는 방식이다.
간단한 예시로 보자면 아래와 같다.
public class Example extends Thread {
public void run() {
System.out.println("thread 구동~!");
}
public static void main(String[] args) {
Example example = new Example();
example.start();
}
}
결과
thread 구동~!
조금 복잡한 예시로 스레드가 어떻게 동시에 일하는지 보자.
package Lecture;
public class Lecture1 extends Thread {
int vari;
public Lecture1(int vari) {
this.vari = vari;
}
public void run() {
System.out.println(this.vari + " thread start."); // 쓰레드 시작
try {
Thread.sleep(1000); // 1초 대기한다. sleep(1)은 0.001초
} catch (Exception e) {
}
System.out.println(this.vari + " thread end."); // 쓰레드 종료
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) { // 총 10개의 쓰레드를 생성하여 실행한다.
Thread t = new Lecture1(i);
t.start();
}
System.out.println("main end."); // main 메소드 종료
}
}
결과
0 thread start.
5 thread start.
3 thread start.
1 thread start.
4 thread start.
2 thread start.
main end.
7 thread start.
9 thread start.
6 thread start.
8 thread start.
3 thread end.
6 thread end.
2 thread end.
0 thread end.
9 thread end.
7 thread end.
8 thread end.
1 thread end.
4 thread end.
5 thread end.
결과를 보면 진행된 스레드의 순서도 뒤죽박죽이고 main 메소드가 끝난 위치가 중간이다.
이는 스레드가 동시에 실행되었고 메인메소드는 스레드 종료 전에 끝난 것을 볼 수 있다.
스레드와 메인의 순서는 실행할 때마다 뒤죽박죽으로 나온다.
스레드 (Thread) - Join
스레드가 종료가 다 되고나서 main을 종료시키고 싶을 때 쓰는 구문이다.
아래의 예시를 보면서 이해해보자.
package Lecture;
//ArrayList를 위해 추가
import java.util.ArrayList;
public class Lecture1 extends Thread {
int vari;
public Lecture1(int vari) {
this.vari = vari;
}
public void run() {
System.out.println(this.vari + " thread 시작!");
try {
Thread.sleep(1000);
}catch(Exception e) {
}
System.out.println(this.vari + " thread 끝!!");
}
public static void main(String[] args) {
// 배열을 만들어서 각 인덱스에 스레드를 넣는다.
ArrayList<Thread> threads = new ArrayList<>();
for(int i=0; i<10; i++) {
Thread t = new Lecture1(i);
t.start();
threads.add(t);
}
for(int i = 0; i < threads.size() ; i++) {
// 배열에 저장된 스레드를 가져온다.
Thread t = threads.get(i);
try {
// t 쓰레드가 종료할 때까지 기다린다.
t.join();
}catch(Exception e) {
}
}
System.out.println("main end");
}
}
결과
0 thread 시작!
2 thread 시작!
1 thread 시작!
3 thread 시작!
5 thread 시작!
4 thread 시작!
6 thread 시작!
8 thread 시작!
7 thread 시작!
9 thread 시작!
9 thread 끝!!
1 thread 끝!!
0 thread 끝!!
7 thread 끝!!
2 thread 끝!!
3 thread 끝!!
6 thread 끝!!
5 thread 끝!!
4 thread 끝!!
8 thread 끝!!
main end
이처럼 main이 끝나는 지점에
ArrayList에 저장된 스레드를 각각 for 문으로
join() 메소드를 실행시키면 스레드가 다 끝난 뒤 main이 끝나게 된다.
ArrayList에 관한 설명은 맨 아래에 적도록 하겠다.
Runnable
Thread는 상속을 받아야한다는 점이 있다.
하지만 그러면 다른 것을 상속 받을 수가 없어서 불편하다.
이를 위해 있는 것이 Runnable이다.
쉽게 말해 Thread의 인터페이스 판이라고 생각하면 된다.
위에서 본 예제를 Runnable에 맞춰서 바꿔보자
package Lecture;
//ArrayList를 위해 추가
import java.util.ArrayList;
// 인터페이스로 받았음~
public class Lecture1 implements Runnable {
int vari;
public Lecture1(int vari) {
this.vari = vari;
}
public void run() {
System.out.println(this.vari + " thread 시작!!");
try {
Thread.sleep(1000);
}catch(Exception e) {
}
System.out.println(this.vari + " thread 끝!!");
}
public static void main(String[] args) {
ArrayList<Thread> threads = new ArrayList<>();
for(int i = 0 ; i < 10 ; i++) {
// 원래라면 생성자만 적는 것을 Thread로 감쌌다.
Thread t = new Thread(new Lecture1(i));
t.start();
threads.add(t);
}
for(int i = 0 ; i < threads.size() ; i++) {
Thread t = threads.get(i);
try {
t.join();
}catch(Exception e) {
}
}
System.out.println("main end.");
}
}
단 2줄만 바꾸면 결과는 같다.
상속을 implements로
Thread 객체 만드는 부분에서 생성자 참조 이전에 Thread 참조를 추가로 받으면
끝.
ArrayList
8/16 Vector 클래스와 비교해서 보길 바란다.
Collection 프레임워크의 일부이며 java.util 패키지에 소속되어 있다.
배열보다는 느리지만 조작을 더 많이 할 수 있는 장점이 있다.
Vector 와 마찬가지로 내부에 값이 추가되면 자동으로 크기가 조절되고
데이터들은 한 자리씩 뒤로 이동된다.
1. 선언
ArrayList list = new ArrayList(); // 타입 설정 안함 => Object로 사용
ArrayList<타입> a = new ArrayList<>(); // 해당 타입으로 사용
ArrayList<타입> b = new ArrayList<타입>(10); // 초기 용량 세팅
ArrayList<타입> c = new ArrayList<타입>(Arrays.asList(1, 2, 3, 4)); // 초기 값 세팅
2. 값 추가 - add()
Vector와 똑같다.
3. 값 제거 - remove()
Vector와 한가지 차이가 있다.
// 안에 있는 같은 Object를 삭제. 만약 같은 값이 두 개인 경우 첫 번째 같은 값을 제거
remove(Object)
// ArrayList의 index에 해당하는 값을 삭제
remove(index)
// 전체 인덱스 제거
clear()
4. 값 수정 - set()
5. 값 출력 - get()
6. 크기 구하기 - size()
Vector와 똑같다.
7. 값이 ArrayList 안에 있나 검색하기
// Object가 있는지 여부만 파악
// 있으면 true, 없으면 false 반환
contains(Object);
// Object의 Index를 찾는다.
// Object가 없다면 -1을 출력
indexOf(Object);
'코딩수업 > AWS 클라우드환경 네이티브' 카테고리의 다른 글
(미완) 8/26 자바(Java) 자바 입력의 전체적 개요, 채팅 프로그램 만들기 (0) | 2022.08.26 |
---|---|
8/25 자바(Java) IP Address, URL, InetAddress 클래스, URL 클래스, Socket programming, TCP/UDP (0) | 2022.08.25 |
8/23 자바(Java) GUI 활용 - 오목 게임 만들기 이어서 (4) | 2022.08.24 |
8/22 자바(Java) GUI 활용 - JPanel 활용, 계산기, 오목 게임 (0) | 2022.08.22 |
8/19 자바(Java) GUI 활용, 8/18 빙고 만들기 이어서.... (0) | 2022.08.19 |
댓글