열심히 끝까지

디바이스 융합 자바(Java) day14 - 예외,예외처리,버퍼,스레드 본문

디바이스 융합 자바(Java)기반 풀스택 개발자 양성과정(수업내용)

디바이스 융합 자바(Java) day14 - 예외,예외처리,버퍼,스레드

노유림 2022. 6. 24. 16:00

[예외와 예외처리]
정수만 입력해야 하는데 문자를 입력해서 뜨는 빨간 글을 막을 방법 없나요?
   >> 없다..
   >> 이것을 예외(Exception)이라고 한다!!

- 예외란?
   >> 문법상으로는 문제가 없었는데,
        실제로 수행해보니 발생하는 문제!

   >> 실행중에 예외가 발생하게 되면 
        프로그램이 즉시 종료!!
       > 이때 지연(delay)와 종료는 완전 다르다!

   >> 예외가 발생하면 프로그램이 즉시 종료되기에
         개발자들에게 개빡치는 상황 발생...ㅋㅋㅋ;
           > 이 때 예외처리를 해주어야 한다

- 예외처리의 목적   
   >> 프로그램이 즉시 종료되는 현상을 방어!!

※ 예외발싱 시 할 일 ※
  1. 어떤 타입의 예외인지 파악(예외도 클래스화 되어있다!)
  2. 예외가 왜 발생했는지 원인을 파악할 것!  -> 설명 참고해볼것

ex ) 

package class02;
public class Test02 {
	public static void main(String[] args) {
		int[] data = {1, 2, 3};
		System.out.println(data[3]);
	}
}

  3. 발생한 라인이 어떤 라인인지 확인할 것
  4. 발생한 예외 스크린샷!

  5. 블로그 포스팅하여 기억해 둘 것!

 

ex ) 예외처리 방법

package class02;
import java.util.Scanner;
public class Test02 {
	public static void main(String[] args) {
		int[] data = {1, 2, 3};
		Scanner sc = new Scanner(System.in);
		System.out.print("인덱스 넘버 입력) ");
		int num = sc.nextInt();
		try {
			System.out.println("AAA");
			// 예외가 발생할만한 구간을 설정
			System.out.println(data[num]); 
			// 예외는 발생 즉시 try -> catch로 즉시 이동!
			System.out.println("BBB");
		}
		catch(ArrayIndexOutOfBoundsException e) {
			System.out.println("0이상 "+data.length + "미만 까지만 입력해주세요!");
			// 예외처리는 
			// 1. 무슨 에러였는지(개발자)
			// 2. 어떻게 해야하는지(사용자)
			e.printStackTrace(); // 메서드를 통해서 어떤 에러였는지 알려준다!
		}
	}
}

예외에 맞게 예외처리를 해야한다!!
ArrayIndexOutOf... 이거를
Arithmetic 이거로 막지 못한다!!

 


---예외처리 예시2

package class02;
import java.util.Scanner;
public class Test03 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int a = sc.nextInt();
		int b = sc.nextInt();
		try {
			System.out.println(a/b);
		}
		catch(ArithmeticException e) { // 예외에 맞게 예외처리를 해야한다!
			System.out.println("0으로는 나눌 수 없습니다!");
		}
		catch(ArrayIndexOutOfBoundsException e) {
			System.out.println("인덱스넘버를 다시 확인해보세요.");
		}
		System.out.println("프로그램...");
	}
}

- 최상위 예외처리가 존재한다!!
   >> Exception e
          >> 가장 하단에 내려가있어야 한다!!
          >> 가장 위에 있으면 아래에 하위의 Exception 예외처리를 하더라도
               빨간줄이 그어지면서 실행이 되지 않는다!!

 


-------예외 발생 예시

package class02;
import java.util.Scanner;
public class Test03 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int a = sc.nextInt();
		int b = sc.nextInt();
		try {
			System.out.println(a/b);
		}
		catch(ArithmeticException e) {
			System.out.println("0으로는 나눌 수 없습니다!!");
		}
		catch(ArrayIndexOutOfBoundsException e) {
			System.out.println("인덱스넘버를 다시 확인해보세요.");
		}
		catch(Exception e) { // 최상위 exception은 가장 하단에 내려가있어야 한다!!
			e.printStackTrace(); 
			System.out.println("아직 처리되지 않은 예외가 발생함!");
		}
		System.out.println("프로그램...");
	}
}

 

 

- finally
   >>  예외발생여부와 상관 없이 무조건 수행되는 구간!


----- finally 예시

package class02;
import java.util.Scanner;
public class Test03 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int a = sc.nextInt();
		int b = sc.nextInt();
		try {
			System.out.println(a/b);
		}
		catch(ArithmeticException e) {
			System.out.println("0으로는 나눌 수 없습니다!!");
		}
		catch(ArrayIndexOutOfBoundsException e) {
			System.out.println("인덱스넘버를 다시 확인해보세요.");
		}
		catch(Exception e) { // 최상위 exception은 가장 하단에 내려가있어야 한다!!
			e.printStackTrace(); 
			System.out.println("아직 처리되지 않은 예외가 발생함!");
		}
		finally {
			System.out.println("예외 발생 여부와 상관 없이 수행되는 구간!");
		}
		System.out.println("프로그램...");
	}
}

 

 

-------------심화과정

package class02;
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;
public class Test04 {
	public static void main(String[] args) {
		List<Integer> al = new ArrayList<Integer>(); // ArrayList AL 생성
		// -1, 0, 1, 2, 3 저장
		al.add(-1);
		al.add(0);
		al.add(1);
		al.add(2);
		al.add(3);
		System.out.println("로그 : 배열리스트 확인 : " + al);
		Scanner sc = new Scanner(System.in); // Scanner 사용하여 입력값 받기
		while(true) {
			try {
				System.out.print("정수입력 ) ");
				int num = sc.nextInt();
				int res = 10/al.get(num);
			}
			catch(InputMismatchException e) {
				System.out.println("로그 : 정수만 입력해주세요!");
				continue;
			}
			catch(IndexOutOfBoundsException e) {
				System.out.println("로그 : 인덱스 범위 예외 발생" + e.getMessage());
				continue;
			}
			catch(ArithmeticException e) {
				System.out.println("로그 : 예외발생 : " + e.getMessage());
				// / by zero 출력 : e.getMessage()
				// e 객체의 getter가 사용!! Exception으로 String message를 가지고 있구나!
				continue;
			}
			catch(Exception e){
				e.printStackTrace();
				System.out.println("로그 : 미확인 예외 발생");
				// continue를 쓰는 것도 좋지만 미확인일 경우 continue를 안 쓰는 것도 방법이다.
			}
			System.out.println("결과 = " + res);
			break;
		}
	}
}

 

- 반복하는 이유?
     버퍼때문에!!!
     >> 공백값
         : 숫자를 입력하면 엔터는 자동으로 소멸된다
           근데 int타입에 문자를 넣으면
           저장을 못하고 exception이 발생하고 continue가 찍혀서 위로 올라온다
           그런데 문자와 엔터값이 저장되어 있는 버퍼가 비워지지 않아서 반복하게 된다!! 


--해결 후

package class02;
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;
public class Test04 {
	public static void main(String[] args) {
		List<Integer> al = new ArrayList<Integer>(); // ArrayList AL 생성
		// -1, 0, 1, 2, 3 저장
		al.add(-1);
		al.add(0);
		al.add(1);
		al.add(2);
		al.add(3);
		System.out.println("로그 : 배열리스트 확인 : " + al);
		Scanner sc = new Scanner(System.in); // Scanner 사용하여 입력값 받기
		while(true) {
			int res = 10;
			try {
				System.out.print("정수입력 ) ");
				int num = sc.nextInt();
				res = 10/al.get(num);
			}
			catch(InputMismatchException e) {
				System.out.println("로그 : 정수만 입력해주세요!");
				sc.nextLine(); // 문자열 + 엔터값 먹어주는 아이
				// sc.next()도 가능하다!
				// 이 다음의 스캐너에 입력 후 친 엔터값이 들어가서 계속반복
				// 스캐너의 버퍼를 비워줘야 한다!
				// sc.nextLine()으로 비워주기
				continue;
			}
			catch(IndexOutOfBoundsException e) {
				System.out.println("로그 : 인덱스 범위 예외 발생" + e.getMessage());
				continue;
			}
			catch(ArithmeticException e) {
				System.out.println("로그 : 예외발생 : " + e.getMessage());
				// / by zero 출력 : e.getMessage()
				// e 객체의 getter가 사용!! Exception으로 String message를 가지고 있구나!
				continue;
			}
			catch(Exception e){
				e.printStackTrace();
				System.out.println("로그 : 미확인 예외 발생");
				// continue를 쓰는 것도 좋지만 미확인일 경우 continue를 안 쓰는 것도 방법이다.
			}
			System.out.println("결과 = " + res);
			break;
		}
	}
}

 

-------심화과정

package class02;
import java.util.Scanner;
// 심화 과정
// 나만의 예외 만들기!
class MyException extends Exception{ // Exception을 부모로 두면
	// 내가 만든 예외도 예외클래스가 된다!!
	// 멤버변수 메세지 값을 반드시 설정해서 만들 수 있게!
	// >> 생성자 : 멤버변수 값을 초기화할 때!
	private String message;
	MyException(String message){
		this.message = message;
	}
	public String getMessage() {
		return message;
	}
	// 1. 오버라이딩 << 기존의 메서드가 마음에 들지 않을 때 재정의
	// 2. toString() << 출력하는 것은 아닌 것 같다!
	// 3. 제네릭 << 컬렉션을 생성할 때 어떤 타입을 다룰 지를 강제!
	// 4. abstract << 부모를 만들고 싶을 때(상속받아서 만든거라 상관 없음)
	//             << 추상메서드 : 내 자식의 오버라이딩을 강제하고 싶을 때
	// 5. super << 부모의 무언가를 가져올 때
	// 6. 인터페이스 << 상속관계가 아닌 두 개의 클래스 사이의 메서드 시그니쳐를 정의할 때
	// 7. 오버로딩 << 함수가 있는데 그 함수를 다른 인자값으로 재정의(비슷하거나 똑같은 기능)
	// 8. static << 객체와 무관한...
	// 9. void << 타입 없음, 없을 무
}
public class Test05 {
	public static void main(String[] args) {
		MyException me = new MyException("범위에 맞는 나이를 입력해주세요!");
		Scanner sc = new Scanner(System.in);
		// 나이를 입력하세요.
		// 123435671234123
		try {
			System.out.print("나이 입력 : ");
			int age = sc.nextInt();
			if(age<0 || 200<age) {
				// 예외를 일부러 발생시켜야하는 상황
				throw me;// 예외로 던져주기!!!
				// 예외를 발생시키면 나중에 캐치하기 용이하다!!
			}
		}
		catch(MyException e) {
			System.out.println(e.getMessage());
		}
	}
}

 

----------
강사님 문제(6.24)로 가서 꼭 보기
- try발생 시
  catch로 즉시 이동
     >> try-catch 비정상적으로 종료되는 것을 방어하기 위해서!!
- 제작 순서
   exception 
   e.printStackTrace(); 
   여러 값을 일부러 넣어보면서
   예외가 발생하는 것을 알아보며 예외처리

 - 버퍼 이슈 
   + 
 - 나만의 예외를 만들어보기!!
   : 기존에 존재하던 exception 상속받아 제작
   : 멤버변수를 초기화하기 위해서는 생성자 필요
      *1~9번 내용 꼭 볼 필요 존재!!
   : 내가 만든 예외클래스는 실제로 발생 안한 것
     문법상 잘못되지 않았지만 내가 보내고 싶다면
     if문으로 설정 후 throw 해버린다.
     그러면 catch로 이동
     예외발생하면 로그에 남기 때문에 개 이득!?
     콘솔이 달라지거나 하지 않기 때문에 지금은 잘 모르지만
     나중에 가면 도움이 된다!!!!

--------
시험에도 안나오고 활용도도 낮지만 
정보처리기사 혹은 고급과정, 이름이 있는 회사에서 
중요하게 다루는 이슈 = "스레드"

[스레드]
-> JAVA1/ JAVA2
활용도는 낮지만 정보처리기사에 시험문제 나오고
컴퓨터구조 수업에서도 등장, 
프로세스와 관련된 작업을 해야하는 기업에서 이 스레드를 반드시 물어본다!!! 
알아두면 좋다!

[스레드 Thread]

 - 매우 구현하기 어려운 구조로 되어있다!
 - C언어에서 ..
      : 자바와 다르게 작업자(개발자)가 주소까지도 결정 가능
   Java언어에서..
      : Thread 클래스 자체를 JAVA에서 제공!!
      : 제공하고 있는 클래스를 가져다 쓰면서!!
 - Download(이클립스, 롤, 메이플)받은 프로그램이
   실행되서 프로세스하려면?
       >> 실행될 때, 메모리를 할당받아야한다!!
       >> 끄면 해제되면서 메모리도 다 돌려준다
       >> 모두 켜놓고 작업하면 속도가 느리다!
       >> 프로그램 : 실행시킬 수 있는 무언가를 가진 것
            실행 : 일할 수 있도록 자원을 할당받은 상태
                     그 할당받는 방식중에는 여러가지가 있다
                     ex ) 시분할 방식, 선점형 방식
            프로세스 : 자원을 할당받아서 일을 진행하고 있는 것

정보처리기사 ) 선점형 방식, 시분할(시간분할) 방식
                    >> 프로세스부분..
                            설명을 잘 해놓는 분이 별로 없어 헷갈린다..
 
- 경고창이 뜨는 경우가 있다!?
   : 한글, 메모장, .... << 입력하는데 갑자기 경고창 뜨면서 입력이 안된다!?
      >> 경고창이 뜨면 경고창으로 포커스가 맞춰져서 입력이 안된다
      >> 경고창의 OS가 제일 상단에 있어서 그걸 처리해야
            한글, 혹은 메모장 이런거에 다시 글을 쓸 수 있다! 

 자원을 할당받은 프로세스가 [  ] 작업을 진행합니다.
                                      일들을 실질적으로 처리하는 대상!
                                      그 대상 : 스레드!
수행시키는 로직은 syso 우선 하고
e.printStackTrace();진행하는 것이 맞는데
모종의 이유로 e.printstackTrace()가 우선 나오고
syso가 나중에 실행된 것이다!

 


---예시 

package class05;
// [스레드]
// -> JAVA1/ JAVA2
// 활용도는 낮지만 정보처리기사에 시험문제 나오고
// 컴퓨터구조 수업에서도 등장, 프로세스와 관련된 작업을 해야하는 기업에서
// 이 스레드를 반드시 물어본다!!! 
// 알아두면 좋다!
class Th1 extends Thread{
	// 스레드는 작업을 처리하는 주체(대상)
	@Override
	public void run() {
		for(int i = 1; i <= 10; i++) {
			System.out.println("클래스로 만든 스레드" + i);
		}
	}
}
class Th2 implements Runnable{ // thread라면 run()가지고 있어야해!!!
	// 인터페이스의 모든 메서드는 abstract 추상메서드
	// 추상메서드는 오버라이딩을 강제
	// -> 인터페이스 가지는 "강제성"!
	// 강제해주니 편안-
	@Override
	public void run() {
		for(int i = 1; i <= 10; i++) {
			System.out.println("인터페이스로 만든 스레드" + i);
		}
	}
}
public class Test06 {
	public static void main(String[] args) {
		Th1 t1 = new Th1();
		Th2 t2 = new Th2(); 
		Thread t3 = new Thread(t2);
		t1.start(); // start() << 스레드야 너의 일을 해!! 그 일이란? run()
		t3.start();
	}
}

 

------동기화 코딩

package class05;
class Person implements Runnable{
	Ticketting t = new Ticketting();
	@Override
	public void run() { // 강제로 런하기
		t.pay();
	}
}
class Ticketting{
	static int ticket = 2; // 클래스 변수 == 공유자원
	void pay() {
		if(ticket>0) {
			System.out.println(Thread.currentThread().getName() + "구매성공!");
			// get 멤버변수로 이름이 존재
			ticket--;
		}
		else {
			System.out.println("구매실패ㅠㅠㅠ");
		}
		System.out.println("남은 티켓 : " + ticket);
	}
}
// 스레드 예제 코딩
public class Test07 {
	public static void main(String[] args) {
		Person person = new Person();
		Thread t1 = new Thread(person, "홍길동");
		Thread t2 = new Thread(person, "아무무");
		Thread t3 = new Thread(person, "티모");
		t1.start();
		t2.start();
		t3.start();
	}
}

>> 이렇게 되면 티켓의 개수가 -1이 되버리는 불상사 발생!
ex ) 은행에서 돈을 뺄 때! - 한 명이 점유하면 다른 사람들의 접근을 막아야하는구나!

--- 동기화 한 후의 코딩

package class05;
// [동기화]  Synchronized
//  : 공유자원을 어떤 스레드가 점유하고 있을 때
//    다른 스레드의 접근을 막는 것
class Person implements Runnable{
	Ticketting t = new Ticketting();
	@Override
	public void run() { // 강제로 런하기
		t.pay();
	}
}
class Ticketting{
	static int ticket = 2; // 클래스 변수 == 공유자원
	synchronized void pay() {
		if(ticket>0) {
			System.out.println(Thread.currentThread().getName() + " 구매성공!");
			// get 멤버변수로 이름이 존재
			ticket--;
		}
		else {
			System.out.println(Thread.currentThread().getName() + " 구매실패ㅠㅠㅠ");
		}
		System.out.println("남은 티켓 : " + ticket);
	}
}
// 스레드 예제 코딩
public class Test07 {
	public static void main(String[] args) {
		Person person = new Person();
		Thread t1 = new Thread(person, "홍길동");
		Thread t2 = new Thread(person, "아무무");
		Thread t3 = new Thread(person, "티모");
		t1.start();
		t2.start();
		t3.start();
	}
}