Study Web Development

11월 10일

이전으로

자바

10. 자바 기본 클래스의 이해

10-5 Calendar

  1. 새 클래스 CalendarMain02 생성
package kr.s03.date;

import java.util.Calendar;
import java.util.Scanner;

public class CalendarMain02 {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		System.out.println("희망 연도와 월을 입력하세요! (예: 연도 > 2021, 월 > 7)");
		System.out.print("연도 > ");
		int year = input.nextInt();
		System.out.print("월 > ");
		int month = input.nextInt();
		input.close();
		
		System.out.println("[ " + year + "년 " + month + "월 ]");
		System.out.println("========");
		System.out.println("일  월  화  수  목  금  토");
	
		// 현재 날짜와 시간을 구함; new로 객체 생성 불가
		Calendar cal = Calendar.getInstance();
		// 희망 연도, 월, 일 세팅; 월의 범위는 0~11이기 때문에 입력 월-1, 일은 달력이 1일부터 시작하기 때문에 1일로 세팅
		cal.set(year, month-1, 1);
		// 1일의 요일을 구하기; 요일의 범위는 1=일요일, 7=토요일
		int week = cal.get(Calendar.DAY_OF_WEEK);
		// 월의 마지막 날짜 구하기
		int lastOfDate = cal.getActualMaximum(Calendar.DATE);
		
		// 첫 날짜를 표시하기 전 공백 처리
		for(int i=1;i<week;i++) {
			System.out.printf("%3s", " "); // 3칸 잡고 공백 넣음
		}
		// 1일부터 마지막 날짜까지 표시
		for(int i=1;i<=lastOfDate;i++) {
			System.out.printf("%3d", i); // 3칸 잡고 날짜 넣음
			if(week%7==0) System.out.println(); // 토요일이면 줄바꿈
			week++;
		}
		System.out.println("\n========");
	}
}

10-3 StringTokenizer

  1. 새 패키지 kr.s04.string 생성 후 새 클래스 StringTokenizerMain01 생성
package kr.s04.string;

import java.util.StringTokenizer;

public class StringTokenizerMain01 {
	public static void main(String[] args) {
		String source = "100,200,300,400";
		StringTokenizer st = new StringTokenizer(source, ",");
		while(st.hasMoreTokens()) { // hasMoreTokens() 메서드로 구분자를 통해 만들어진 문자열이 있는지 검증
			System.out.println(st.nextToken()); // nextToken() 메서드로 구분자를 통해 만들어진 문자열을 하나씩 반환
		}
	}
}
  1. 새 클래스 StringTokenizerMain02 생성
package kr.s04.string;

import java.util.StringTokenizer;

public class StringTokenizerMain02 {
	public static void main(String[] args) {
		String source = "2021-11-10 11:21:50";
		StringTokenizer st = new StringTokenizer(source, "-: "); // 복수의 구분자 지정 가능
		while(st.hasMoreTokens()) { // 구분자를 통해 만들어진 문자열이 있는지 검증
			System.out.println(st.nextToken()); // 구분자를 통해 만들어진 문자열을 하나씩 반환
		}
	}
}

7. 객체의 활용

7-7 인터페이스

인터페이스의 기능
  1. ch06-object2 프로젝트에 새 패키지 kr.s11.inter 생성하고 새 클래스 InterMain01 생성
package kr.s11.inter;

interface A1 {
	// 상수; 인터페이스는 생성자가 없으므로 객체 생성이 불가능하고, 상수는 각자 호출시 메모리에 올라감
	public static final int W = 10; // 원형
	int X = 20; // public static final 생략해도 원형대로 선언됨
	static int Y = 30; // public final 생략해도 원형대로 선언됨
	final int Z = 40; // public static 생략해도 원형대로 선언됨
}

public class InterMain01 {
	public static void main(String[] args) {
		// 인터페이스는 객체 생성 불가
		// A1 ap = new A1();
		
		// static 상수이므로 인터페이스명.상수명 형식으로 호출함
		System.out.println("W = " + A1.W);
		System.out.println("X = " + A1.X);
		System.out.println("Y = " + A1.Y);
		System.out.println("Z = " + A1.Z);
	}
}
  1. 새 클래스 InterMain02 생성
package kr.s11.inter;

interface A2 {
	// 추상 메서드; 인터페이스는 객체 생성이 불가하므로 일반 클래스에서 구현하여 사용
	public abstract void getA(); // 원형
	void getB(); // public abstract 생략해도 원형대로 선언됨
}

// 인터페이스를 클래스에 구현
class B2 implements A2 {
	// 인터페이스의 추상 메서드를 구현; 구현되지 않은 추상 메서드가 있을 경우 오류 발생
	@Override public void getA() {
		System.out.println("getA 메서드");
	}
	@Override public void getB() {
		System.out.println("getB 메서드");
	}
}

public class InterMain02 {
	public static void main(String[] args) {
		B2 bp = new B2();
		bp.getA();
		bp.getB();
	}
}
  1. 새 클래스 InterMain03 생성
package kr.s11.inter;

interface Inter1 {
	// 추상 메서드
	public abstract int getA();	
}

interface Inter2 {
	// 추상 메서드
	public abstract int getB();
}

// Inter1과 Inter2가 Inter3에 상속; 인터페이스끼리는 상속이 가능하며, 다중 상속도 인정됨
interface Inter3 extends Inter1, Inter2 {
	// 추상 메서드
	public abstract int getData();
}

interface Inter4 {
	// 추상 메서드
	public abstract String getStr();
}

// 클래스에 Inter3과 Inter4를 구현; 한 클래스에 여러 인터페이스를 동시에 구현 가능
class InterSub implements Inter3, Inter4 {
	// Inter3의 추상 메서드 구현
	@Override public int getA() {
		return 10;
	}
	@Override public int getB() {
		return 20;
	}
	@Override public int getData() {
		return 30;
	}
	// Inter4의 추상 메서드 구현
	@Override public String getStr() {
		return "서울";
	}
}

public class InterMain03 {
	public static void main(String[] args) {
		InterSub is = new InterSub();
		System.out.println(is.getA());
		System.out.println(is.getB());
		System.out.println(is.getData());
		System.out.println(is.getStr());
	}
}
  1. 새 클래스 InterMain04 생성
package kr.s11.inter;

interface I {
	// 추상 메서드
	public abstract void play();
}

// 인터페이스 I를 클래스 B에 구현
class B implements I {
	@Override public void play() {
		System.out.println("피아노를 연주합니다.");
	}
	public void study() {
		System.out.println("외국어를 공부합니다.");
	}
}

public class InterMain04 {
	public static void main(String[] args) {
		B bp = new B();
		bp.play();
		bp.study();
		
		I i = bp; // 클래스 자료형에서 인터페이스 자료형으로 자동 형변환
		i.play();
		// i.study(); // 호출 범위를 벗어나므로 호출 불가
		
		B bp2 = (B)i; // 인터페이스 자료형에서 클래스 자료형으로 강제 형변환
		bp2.play();
		bp2.study();
	}
}
  1. 새 클래스 InterMain05 생성
package kr.s11.inter;

interface Inter {
	// 추상 메서드
	public abstract void play();
}

class A implements Inter {
	@Override public void play() {
		System.out.println("피아노를 연주합니다.");
	}
}

class C implements Inter {
	@Override public void play() {
		System.out.println("첼로를 연주합니다.");
	}
}

class Admin {
	public void autoPlay(Inter i) {
		// i를 통해 객체에 접근해서 메서드를 호출함; 공통 자료형을 사용하지 못하면 메서드를 클래스 자료형마다 별도로 만들어야 하며, Object 자료형의 경우 play() 메서드 호출 불가
		i.play();
	}
}

public class InterMain05 {
	public static void main(String[] args) {
		Admin ad = new Admin();
		ad.autoPlay(new A());
		ad.autoPlay(new C());
	}
}

11. 예외 처리

11-1 예외

11-2 예외 처리

  1. 새 자바 프로젝트 ch08-exception 생성하고 새 패키지 kr.s01.exception 생성 후 새 클래스 ExceptionMain01 생성
package kr.s01.exception;

public class ExceptionMain01 {
	public static void main(String[] args) {
		int[] array = {10,20,30};
		// 인위적으로 예외를 발생시키기 위해 없는 인덱스 3을 호출
		for(int i=0;i<=array.length;i++) {
			System.out.println("array[" + i + "] : " + array[i]);
		} // for문 종료
		System.out.println("프로그램 정상 종료"); // 예외 발생으로 프로그램 비정상 종료되어 출력되지 않음
	}
}
  1. 새 클래스 ExceptionMain02 생성
package kr.s01.exception;

public class ExceptionMain02 {
	public static void main(String[] args) {
		// 예외 처리; 예외가 발생해도 정상 종료될 수 있도록 프로그램적으로 처리
		int[] array = {10, 20, 30};
		
		// 인위적으로 예외 발생
		for(int i=0;i<=array.length;i++) {
			// 예외 처리; 예외는 없는 인덱스를 호출하는 순간 발생
			try { // 예외가 발생할 가능성이 있는 코드를 명시
				System.out.println("array[" + i + "] : " + array[i]);
			}
			catch(ArrayIndexOutOfBoundsException e) { // 예외 발생시 catch 블럭으로 이동하여 예외가 발생한 이유를 출력하거나 대체 코드를 실행; catch()에는 예외 발생시 생성되는 예외 객체의 자료형을 지정해야 함
				System.out.println("없는 인덱스 " + i + "을/를 호출함");
			}
		} // for문 종료
		System.out.println("프로그램 정상 종료"); // 예외 처리를 했기 때문에 예외가 발생해도 출력됨
	}
}
  1. 새 클래스 ExceptionMain03 생성
package kr.s01.exception;

public class ExceptionMain03 {
	public static void main(String[] args) {
		int var = 50;
		// 예외가 발생하면 예외 객체가 생성되고, 예외 객체가 전달된 catch 블럭으로 이동해서 수행문을 실행
		try {
			int data = Integer.parseInt(args[0]);
			System.out.println(var/data);
		}
		// 다중 catch문 사용; Exception과 하위 예외 클래스를 동시에 명시할 경우, 하위 예외 클래스를 먼저 명시하고 마지막에 Exception을 명시해야 동작상의 문제가 발생하지 않음; 부모 클래스는 자식 클래스의 예외 객체를 모두 흡수할 수 있고, catch()문은 순차적으로 확인하기 때문
		catch(NumberFormatException e) { // 데이터가 "100"이면 100으로 parsing하지만 "100?"이면 예외 발생
			System.out.println("숫자가 아닙니다.");
		}
		catch(ArrayIndexOutOfBoundsException e) { // 프로그램 실행시 인자를 전달하지 않은 경우, 배열이 만들어지지 않아 args[0] 호출시 예외 발생
			System.out.println("입력한 데이터가 없습니다.");
		}
		catch(ArithmeticException e) { // var/0 연산시 예외 발생
			System.out.println("0으로 나눌 수 없습니다.");
		}
		catch(Exception e) { // 예외가 발생할 것으로 예상되지만 정확한 클래스명을 모를 경우, 부모 클래스 자료형으로 자동 형변환하여 예외 처리 가능
			System.out.println("예외가 발생했습니다.");
		}
		System.out.println("프로그램 정상 종료");
	}
}

11-5 finally의 필요성

  1. 새 클래스 ExceptionMain04 생성
package kr.s01.exception;

public class ExceptionMain04 {
	public static void main(String[] args) {
		// try~catch~finally
		System.out.println("예외가 발생하지 않는 경우");
		try {
			System.out.println("1");
			System.out.println("2");
		}
		catch(Exception e) {
			System.out.println("3");
		}
		finally {
			System.out.println("4");
		}
		System.out.println("========");
		System.out.println("예외가 발생하는 경우");
		try {
			System.out.println("1");
			System.out.println(10/0); // 인위적으로 ArithmeticException 발생
			System.out.println("2");
		}
		catch(Exception e) {
			System.out.println("3");
		}
		finally {
			System.out.println("4");
		}
		System.out.println("========");
	}
}

11-3 throws 예약어

  1. 새 클래스 ExceptionMain05 생성
package kr.s01.exception;

import java.io.IOException; // BufferedReader의 예외를 처리하기 위해 필요
import java.io.BufferedReader; // 범용적으로 Scanner보다 많이 사용됨
import java.io.InputStreamReader; // BufferedReader를 사용하기 위해 필요

public class ExceptionMain05 {
	// 메서드에 throws 예약어를 사용하여 발생할 가능성이 있는 예외 클래스들을 명시하면, 메서드 내에 try~catch 블럭을 생략하고, 예외가 발생하면 예외를 보관하고 메서드를 호출한 곳에서 try~catch 블럭을 만들고 그 곳으로 예외를 양도
	public void printData() throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		System.out.print("단 입력 > ");
		int dan = Integer.parseInt(br.readLine()); // readLine() 메서드는 \n, \r, \r\n이 제거된 한 줄의 데이터를 문자열로 반환하므로 문자열 parsing 필요; readLine() 메서드 사용시 IOException이 발생할 수 있고, IOException은 일반적 Exception이라 throws 혹은 try~catch하지 않으면 컴파일 오류 발생
		System.out.println(dan + "단");
		System.out.println("========");
		for(int i=1;i<=9;i++) {
			System.out.println(dan + " * " + i + " = " + dan*i);
		}
	}
	
	public static void main(String[] args) {
		ExceptionMain05 ex = new ExceptionMain05();
		// ex.printData(); // throws 예약어 사용한 메서드 호출시 의무적으로 try~catch 블럭 작성해야 함
		try {
			ex.printData();
		}
		catch(NumberFormatException e) {
			System.out.println("잘못 입력하셨습니다. 숫자만 입력하세요.");
		}
		catch(IOException e) { // IOException은 입력 대기 중인데 프로그램을 강제 중단하거나, 시스템 환경이 불안정한 경우 등에 발생 가능하며 돌발적으로 발생하기 때문에 예외 처리를 의무화하는 것; 이 예제에서는 프로그램 강제 중단시 parseInt()의 인자가 없기 때문에 NumberFormatException도 함께 발생
			System.out.println("입출력 예외가 발생했습니다.");
		}
	}
}

과제

  1. 프로젝트 ch07-langnUtil의 패키지 kr.s02.mathtest에 새 클래스 RandomMain02 생성
package kr.s02.mathtest;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class RandomMain02 {	
	public static void main(String[] args) {
		/*
		 * [실습] 가위바위보 게임
		 * 컴퓨터가 난수를 발생시켜 0=가위, 1=바위, 2=보를 낸다.
		 * 메뉴 > 1. 게임하기, 2. 종료
		 * [출력 예시]
		 * 가위바위보 입력 > 0. 가위, 1. 바위, 2. 보
		 * 경우 1) 무승부! (컴퓨터 : 가위, 당신 : 가위)
		 * 경우 2) 컴퓨터 승리! (컴퓨터 : 가위, 당신 : 보)
		 * 경우 3) 당신 승리! (컴퓨터 : 가위, 당신 : 바위)
		 */
		RandomMain02 game = new RandomMain02();
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		all: while(true) {
			System.out.println("메뉴 > 1. 게임하기, 2. 종료");
			System.out.print("메뉴 > ");
			int menu=0;
			try {
				menu=Integer.parseInt(br.readLine());
			}
			catch(Exception e) {
				System.out.println("예외 발생");
			}
			switch(menu) {
			case 1:
				System.out.println("가위바위보 입력 > 0. 가위, 1. 바위, 2. 보");
				System.out.print("가위바위보 입력 > ");
				int player=-1;
				try {
					player=Integer.parseInt(br.readLine());
				}
				catch(Exception e) {
					System.out.println("예외 발생");
				}
				game.judge(player);
				break;
			case 2:
				System.out.println("게임 종료"); break all;
			default:
				System.out.println("메뉴를 잘못 입력하셨습니다."); break;
			}
		}
	}
	
	public void judge(int player) {
		java.util.Random random = new java.util.Random();
		int ai=random.nextInt(3);
		
		String[] card={"가위", "바위", "보"};
		String[] winlose={"무승부!", "승리!"};
		String[] winner={"", "컴퓨터 ", "당신 "};
		
		int result=1;
		int who=1;
		
		if(player==ai) {
			result=0;
			who=0;
		}
		else if(player==0){
			if(ai==2) {
				who=2;
			}
		}
		else if(player==1) {
			if(ai==0) {
				who=2;
			}
		}
		else if(player==2) {
			if(ai==1) {
				who=2;
			}
		}
		else {
			System.out.println("가위바위보를 잘못 입력하셨습니다.");
			return;
		}
		
		System.out.printf("%s%s (컴퓨터: %s, 당신: %s)\n", winner[who], winlose[result], card[ai], card[player]);
	}
}

다음으로