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========");
	}
}
java.util 패키지에 포함되어 있음
split() 메서드와 달리, 복수의 구분자 지정 가능true 전달시 구분자를 토큰에 포함split() 메서드와 달리) 배열을 반환하지 않으므로 for문이 아니라 메서드를 이용하여 토큰에 접근hasMoreTokens()
true, 그렇지 않으면 false를 반환하는 메서드nextToken()
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() 메서드로 구분자를 통해 만들어진 문자열을 하나씩 반환
		}
	}
}
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()); // 구분자를 통해 만들어진 문자열을 하나씩 반환
		}
	}
}
.class 확장자를 갖기 때문에 컴파일 전 코드를 확인해야 인터페이스인지 클래스인지 구분 가능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);
	}
}
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();
	}
}
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());
	}
}
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();
	}
}
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());
	}
}
java.lang 패키지에 포함된 기본 클래스java.lang 패키지에 포함된 기본 클래스java.lang 패키지에 포함된 기본 클래스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("프로그램 정상 종료"); // 예외 발생으로 프로그램 비정상 종료되어 출력되지 않음
	}
}
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("프로그램 정상 종료"); // 예외 처리를 했기 때문에 예외가 발생해도 출력됨
	}
}
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("프로그램 정상 종료");
	}
}
close()하는 등, 자원 정리가 필요한 경우에 사용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("========");
	}
}
throws 예약어 다음에 발생할 가능성이 있는 예외 클래스명을 명시하고, 메서드 내에 tryReadLine() 메서드는 try~catch문을 작성하지 않으면 컴파일 에러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("입출력 예외가 발생했습니다.");
		}
	}
}
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]);
	}
}