오늘은 상당히 쉬워 보이면서도 구조가 그물처럼 엮여있어서 드디어 어느 정도 감을 잡은 것 같다.
그래도 앞으로도 계속 반복해서 할 필요가 있어보인다
오늘의 시작은 예외처리이다.
예외처리는 에러가 발생할 수 있는 코드를 실행하는 것이다.
코드를 보면
try {
num = Integer.parseInt(sc.nextLine());
System.out.println("num : " + num);
return;
} catch (NumberFormatException e) {
System.out.println("
System.out.println(e);
e.printStackTrace();
}
try라는 코드를 사용해서 예외가 발생할 수 있는 코드를 일단 실행해 본다.
이 코드에는 Scanner의 int값만 들어갈 수 있는데 String값을 넣으면 에러가 날것이다.
그것을 catch에서 에러코드를 다른 형태로 출력할 수 있는 것이다.
catch (NumberFormatException e) 이것은 예상되는 예외(자바에서 정해놓은)가 발생하면
아래 코드를 실행한다는 것이다.
이중 e.printStackTrace(); 이건 위 예외처리의 상세설명을 출력하는 것이다.
일반적인 에러에서 몇 번째 줄의 어떤 점이 잘못되었다고 설명해 주는 기본값이
e.printStackTrace(); 이것이다.
public void start() throws Exception {
for(int i = (int)(minute * 60); i != -1; i--) {
System.out.printf("[%02d : %02d]\n", i / 60, i % 60);
Thread.sleep(1000);
카운트다운을 하는 코드가 있다고 한다.
이 짧은 코드에서는 크게 문제가 없겠지만 많은 쓰레스를 다루는 코드에서는 에러가 발생할 가능성이 높다.
그 에러를 계속 놔둘 수는 없으니 전가시키는 것이 throws이다.
아까로 설명했다시피 예외처리를 try-catch로 처리를 해야 한다.
하지만 try-catch는 throws메서드에 넣을 수 없다.
왜냐하면 이것을 이곳에 넣어버리면 이 예외들은 JVM(자바 가상머신) > OS순으로 넘어가 버린다.
그렇기에 try-catch를 main에 넣어서 전가시켜 버리는 것이 가장 깔끔하다.(무조건 그런 건 아님)
그래서
public static void main(String[] args) {
Timer ob = new Timer(minute);
try {
ob.start();
}catch(Exception e) {
e.printStackTrace();
}
이런 식으로 caller에서 받을 수 있다.
참고로 callee는 요청을 받은 쪽이고 caller은 요청을 하는 쪽을 말한다.
메서드는 CPU의 스레드 하나하나가 각각의 스레드를 작동시킨다.
쓰레드를 사용하기 위해서는
class PrintNumber extends Thread {
@Override
public void run() {
for (char ch = 'A'; ch <= 'Z'; ch++) {
System.out.print(ch + " ");
}
}
}
이런 식이 extends Thread를 입력해서 상속받아야 한다.
그리고 run이라는 메서드를 오버라이딩하여 main에서 호출할 수 있다.
Thread th1 = new PrintAlphaber();
Thread th2 = new PrintNumber();
th1.start();
th2.start();
이렇게 Thread의 인스턴스를 만들고 스레드를 start로 실행할 수 있다.
Thread는 상속(extends)으로 구성된다.
그리고 자바는 다중상속을 허용하지 않는다.
만약, 이미 슈퍼클래스를 지정한 서브클래스에 대해 스레드를 구현하고 싶다면
interface Runnable을 사용해야 한다.
class PrintN extends Object implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 25; i++) {
System.out.print(i + " ");
}
}
클래스를 implements Runnable로 인터페이스를 상속받는다.
그리고 run() 메서드를 만들고 기능(내용)을 추가한다.
PrintN ob = new PrintN();
Thread th1 = new Thread(ob);
th1.start();
위에서 만든 클래스의 인스턴스를 만들고
그 값을 Thread에 넣는다.
그럼 스레드로 코드가 실행이 된다.
마지막문제는 랜덤으로 나오는 숫자의 덧셈이다.
코드의 내용은 5초 이내로 답을 맞히면 정답, 못 맞추면 오답을 출력하고
정답을 맞히거나 오답이면 타이머는 멈춘다.
public class Timer implements Runnable {
private int second = 5;
Question question;
boolean over;
public void setQuestion(Question question) {
this.question = question;
}
public boolean isOver() {
return over;
}
@Override
public void run() {
try {
for (int i = second;question.isComplete()== false && i != -1; i--) {
Thread.sleep(1000);
System.out.printf("[%02d : %02d]\n", i / 60, i % 60);
}
over = true;
} catch (InterruptedException e) {
}
}
}
제일 위에서부터 보면 Runnable 인터페이스를 상속받는다.
second = 5 //초단위는 5로 고정시키고
Question question // Question클래스의 함수를 이 클래스에서 인스턴스를 생성하여 사용할 때 필요하다.
boolean over; // 이건 나중에 반복이 끝나거나 결과가 나왔을 때 상태를 확인하기 위함이다.
setter생성자를 만들고(다른 클래스에서 호출하기 위해서)
run메서드를 만든다.
run의 내용은 예외처리를 위한 try안에 for(int i = second;question.isComplete()== false && i!= -1; i--)
i는 5초부터 Question클래스에 있는 메서드인 isComplete()가 false이면서 i가 0일 때까지 카운트다운을 한다.
위 for문을 Thread.sleep를 이용해 자연스럽게 카운트다운을 한다.
반복문이 끝나면 over은 true로 바뀐다.
public class Question implements Runnable{
private int input;
private int num1,num2,answer;
private Random ran = new Random();
Scanner sc = new Scanner(System.in);
boolean complete = false;
Timer timer;
ArrayList<String> list = new ArrayList<String>();
public boolean isComplete(){
return complete;
}
public void setTimer(Timer timer) {
this.timer = timer;
}
public Question() {
num1 = ran.nextInt(10)+1;
num2 = ran.nextInt(10)+1;
answer = num1 + num2;
}
@Override
public void run() {
System.out.printf("%d + %d = ", num1,num2);
input = Integer.parseInt(sc.nextLine());
complete = true;
if(timer.isOver() == false) { // isOver이 true이니까 뭐??
System.out.println("시간 초과");
}else if(answer != input) {
System.out.println("오답");
}else {
System.out.println("정답");
}
sc.close();
}
}
이 클래스의 시작은
Question메서드를 만들어서
num1, num2에 랜덤 되는 10개의 정수를 넣어주고
answer변수에 이 두 개의 함을 넣는다.
run메서드를 오버라이딩하여
값을 입력하고 if(timer.isOver()) {
System.out.println("오답 (시간 초과)");
} // 코드에 문제가 있어서 확인 중
else if(input!= answer) {
System.out.println("오답");
} // 입력값과 다르면 오답
else {
System.out.println("정답~");
} // 그 외는 정답으로 처리한다.
마지막으로 main클래스에서
public class Main {
public static void main(String[] args) {
Question ob1 = new Question();
Timer ob2 = new Timer();
ob1.setTimer(ob2);
ob2.setQuestion(ob1);
Thread th1 = new Thread(ob1);
Thread th2 = new Thread(ob2);
th1.start();
th2.start();
}
}
Question클래스의 인스턴스와 Timer인스턴스를 만든다.
그리고 아까 각각의 클래스에 만들어 둔 setter을 불러와서 위 인스턴스의 값을 넣어준다.
자세하게 말하자면 ob2.setQuestion(ob1)은 Timer클래스에서 만든 setQuestion생성자에 Question의 값을 넣어준다는 뜻이다.
이렇게 만든 것들을 Thread 인스턴스로 만들어 각각 값을 넣어준다.
그 스레드를 실행한다.
요즘 학원에 다니면서 나 자신의 대해 회의감이 들기 시작했다.
나 자신이 멍청한 건가 아님 정말 내용이 어려운 건가.
주위에 있는 사람들을 잘하는데 난 왜 못 따라가는 걸까라는 불안감이 생기는 것 같다.
강사님이 엄청난 속도로 진도를 빼고 계시는 것을 알고 있기에 나도 학원에서 공부한 내용을
집에서와 다시 이해하고 코드를 짜보고 있다.
언제 즈음 나도 그 잘하는 쪽에서 재밌게 코드를 짤 수 있을지는 모르겠지만 이것도 나 자신이
이겨내야 하는 관문 중 하나일 것이다.
오늘로 학원은 16일 차이다. 갈길은 멀지만 이 속도로는 순식간에 끝에 도달할 것 같다.
학원수업을 복습하고 나면 정처리를 공부할 시간이 없다.
힘들더라도 쉬는 시간을 줄이고 공부시간을 늘려서 공부를 해야 할 필요성을 느끼게 된다.
몸은 힘들겠지만 지금 고생해 놓으면 근미래가 편해진다.(잠은 최대한 평균으로 자고)
지금은 힘들지만 미래의 나 자신은 이것을 성공담으로 말하는 날을 기대하며
오늘은 여기서 마치겠다.
'JAVA 공부' 카테고리의 다른 글
자바의 기초 - 소켓, Buffer,Thread(채팅) (0) | 2023.04.09 |
---|---|
자바의 기초 - 예외처리, 파일 입출력(전화번호 관리 프로그램) (0) | 2023.04.05 |
자바의 기초 - 주단위 능력평가(회원관리 프로그램 CRUD) (0) | 2023.03.31 |
자바의 기초 - 상속,다형성 (0) | 2023.03.27 |
자바의 기초 - 학원 자유주제(tv의 기능구현) (0) | 2023.03.26 |