1차시 StringTokenizer 클래스, java.text 패키지
StringTokenizer 클래스
- 문자열을 토큰으로 분리하는 데 사용
- 토큰(분리한 문자열)은 공백이나 줄 바꿈 등 구분자를 사용해 문자열을 분리
- 기본 구분자는 공백, 탭, 줄 바꿈, 복귀, 용지 먹임 문자
/* StringTokenizer 클래스의 활용 */
import java.util.StringTokenizer; //StringTokenizer 사용을 위해서는 import 선언 필수!
public class StringTokenizerDemo {
public static void main(String[] args) {
String s = "of the people, by the people, for the people"; //String 객체 생성
//" ," 공백과 콤마를 구분자로 파싱한 StringTokenizer 객체 생성
StringTokenizer st = new StringTokenizer(s, " ,");
//StringTokenizer st = new StringTokenizer(s);
//이렇게 하는 경우 기본 구분자인 공백으로 파싱!
//남아 있는 토큰의 개수 반환 메서드
System.out.println(st.countTokens()); //(1)토큰의 개수 출력
//토큰이 남아 있을 때까지 다음 토큰을 꺼내어 출력
while (st.hasMoreTokens()) { //남아 있는 토큰이 있는지 여부 반환 메서드
System.out.print("[" + st.nextToken() + "] "); //(2)다음 토큰을 꺼내 오는 메서드
}
}
}
//코드 실행 결과 (1), (2)
//9
//[of] [the] [people] [by] [the] [people] [for] [the] [people]
Random 클래스
- 난수 반환
- 동일한 시드를 사용해 생성된 Random 객체는 동일한 난수 발생
/* Random 클래스의 활용 */
import java.util.Random; //import java.util.*로 선언도 가능
public class RandomDemo {
public static void main(String[] args) {
Random r = new Random(); //랜덤 객체 생성
for (int i = 0; i < 5; i++) //난수 5번 발생
System.out.print(r.nextInt(100) + " "); //0 ~ 100 사이의 int 타입 난수 발생시킴
//대체적으로 랜덤은 0부터 시작, 따라서 이렇게 난수를 발생시키면 0 ~ 99까지의 난수만 발생
//Systme.out.print(r.nextInt(100)+1 + " ");
//이렇게 산술 연산해서 범위 지정해야 100도 난수로 발생시킬 수 있음!
}
}
java.text 패키지
- 현지화가 필요한 데이터의 효율적 처리를 위한 패키지
- 시스템을 현지에 맞게 데이터를 가져가는 것! (데이터가 변하는 것은 아님)
- 패키지의 Format 클래스는 지역에 민감한 데이터를 현장에 맞게 문자열로 표현하고 포맷할 수 있도록 지원
MessageFormat 클래스
- 문자열을 특정 포맷에 맞추어 깔끔하게 처리하는 클래스
/* MessageFormat 클래스 사용 방법 */
//(1) {0}, {1}, {2}가 인덱스!
MessageFormat.format("{0} * {1} = {2}", 3, 4, 3 * 4);
//(2) 객체 배열을 만들어서 배열의 인덱스를 그대로 매핑하는 방법
MessageForamt.format("{0} * {1} = {2}", new Object[]{3, 4, 3 * 4});
//대체적으로 (2)를 더 많이 사용
import java.text.MessageFormat; //MeessageFormat은 java.text 패키지 소속!
public class MessageFormatDemo {
public static void main(String[] args) {
String java = "Java";
int version = 8;
//패턴 메시지 version: 패턴 메세지의 {0}에 대응
//패턴 메시지 java: 패턴 메세지의 {1}에 대응
//인덱스인 {1}과 {0}은 포맷이므로 순서를 바꿀 수 있지만
//version과 java는 정확하게 순서대로 카운트 됨!
//그래서 {0}에 version, {1}에 java
String s = MessageFormat.format("language : {1}\nversion : {0}", version, java);
//\n은 줄 바꾸기
System.out.println(s);
//배열로 접근 - 객체 배열을 만들어서 배열의 인덱스를 그대로 매핑
Object[] data = { java, version }; //업캐스팅 발생
//Object는 객체에 대한 최상위 클래스
//java라는 String 객체가 배열에 들어와서 <부모 자식>의 형태가 되므로 업캐스팅 발생!
MessageFormat f = new MessageFormat("language : {0}\nversion : {1}");
//{0}에 java, {1}에 version 매핑
System.out.println(f.format(data));
//MessageFormat.format(배열)의 형태
}
}
DecimalFormat 클래스
- 10진수를 포맷. 정수, 실수, 과학적 표기, 퍼센트 표시, 화폐 표시 등을 포함한 다양한 종류의 수를 지원
- #이랑 0으로 판단해서 범위 지정
/* DecimalFormat 클래스의 활용 */
import java.text.DecimalFormat; //DecimalFormat 클래스는 java.text 패키지 소속!
public class DecimalFormatDemo {
public static void main(String[] args) {
DecimalFormat f1 = new DecimalFormat("#");
DecimalFormat f2 = new DecimalFormat("000000000.00");
DecimalFormat f3 = new DecimalFormat("#.000");
DecimalFormat f4 = new DecimalFormat("#,###.##");
DecimalFormat f5 = new DecimalFormat("-#.#");
DecimalFormat f6 = new DecimalFormat("#.##E00");
DecimalFormat f7 = new DecimalFormat("+#.#;-#.#");
DecimalFormat f8 = new DecimalFormat("#.00%");
//입력 숫자: 1234567.890
System.out.println(f1.format(1234567.890));
System.out.println(f2.format(1234567.890));
System.out.println(f3.format(1234567.890));
System.out.println(f4.format(1234567.890));
System.out.println(f5.format(1234567.890));
System.out.println(f6.format(1234567.890));
System.out.println(f7.format(1234567.890));
System.out.println(f7.format(-1234567.890));
System.out.println(f8.format(1234567.890));
}
}
2차시, 3차시 예외 처리
예외의 개념
- 에러(error): 개발자가 해결할 수 없는 치명적인 오류
- 예외(exeption): 개발자가 해결할 수 있는 오류
- 예외가 발생하면 비정상적인 종료를 막고, 프로그램을 계속 진행할 수 있도록 우회 경로를 제공하는 것이 바람직
- 예외를 그대로 보여주는 게 아니라 우회해서 보여준다는 뜻!
- 예외 처리는 자바에만 있는 기능 ~ (자바는 예외를 객체로 처리)
- 오류(error)에 오류(error)와 예외(exception)이 포함됨
- 일반 예외만 컴파일러가 확인 (코드에서 빨간 색 밑줄 뜨는 거)
- 실행 예외는 코드에서 처리하든지 JVM에 맡기든지 개발자가 선택
실행 예외
- 예외가 발생하면 JVM은 해당하는 실행 예외 객체 생성
- 실행 예외는 컴파일러가 예외 처리 여부를 확인 X, 따라서 개발자가 예외 처리 코드의 추가 여부 결정
/* 실행 예외 1 */
import java.util.NoSuchElementException; //import java.util.*; 가능
import java.util.StringTokenizer; //StringTokenizer 클래스
public class UnChecked1Demo {
public static void main(String[] args) {
String s = "Time is money";
StringTokenizer st = new StringTokenizer(s); //구분자가 없으므로 기본 구분자인 공백으로 파싱
//토큰이 남아 있을 때까지 다음 토큰을 꺼내어 출력
while (st.hasMoreTokens()) {
System.out.print(st.nextToken() + "+");
}
//예외 발생 시점
System.out.print(st.nextToken()); //더 이상 가져올 토큰이 없어 예외를 발생시킴
//이미 while문 안에서 토큰 다 출력했음
}
/* 실행 예외 2 */
//java.lang 패키지 에러는 import 생략 가능
public class UnChecked2Demo {
public static void main(String[] args) {
int[] array = { 0, 1, 2 };
//예외 발생 시점
System.out.println(array[3]); //범위를 벗어난 인덱스를 사용해 예외 발생 시킴
}
}
일반 예외
- 소스 코드에서 빨간 색 밑줄이 보이는 경우
- 컴파일러는 일반 예외가 발생할 가능성을 발견하면 컴파일 오류를 발생
- 개발자는 예외 처리 코드를 반드시 추가
/* 일반 예외 */
public class CheckedDemo {
public static void main(String[] args) {
Thread.sleep(100);
//일반 예외가 발생할 수 있는 코드.
//예외 처리를 하지 않아 컴파일 오류 발생
}
}
예외 처리 방법
1. 예외 잡아 처리하기 (try~catch~finally 문)
2. 예외 떠넘기기 (throws문)
예외 잡아 처리하기
- 예외가 발생한 시점에 예외 객체를 잡아 바로 처리할 때는 try~catch문 사용
- 예외 발생 여부와 관계 없이 반드시 수행할 실행문이 있다면 try~catch 코드에 finally 블록 추가
- 예외와 관련된 정보는 Throwable 클래스에 있는 메서드에서 얻을 수 있다.
- 핸들러의 부모가 Throwable 객체
/* try~catch문을 사용해 예외 잡아 처리하기 */
/* (1) ~ (4) 순서대로 실행 */
//java.lang 패키지에 포함되는 예외라 import 생략 가능
public class TryCatch1Demo {
public static void main(String[] args) {
int[] array = { 0, 1, 2 }; //(1)
try {
//array는 3개의 원소만 있으므로 array[3]은 없음! 예외 발생!
System.out.println("마지막 원소 => " + array[3]); //(2) 예외 발생해서 출력 X
//이전 실행문에서 예외가 발생했으므로 다음 실행문은 실행 X
System.out.println("첫 번째 원소 => " + array[0]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("원소가 존재하지 않습니다."); //(3)
}
//꼭 실행해야 하는 문장은 try문 밖에 위치!
System.out.println("어이쿠!!!"); //(4)
}
}
//실행 결과
//원소가 존재하지 않습니다.
//어이쿠!!!
/* 인수를 받아 나눗셈을 수행하는 과정에서 발생하는 예외 잡아 처리하기 */
public class TryCatch2Demo {
public static void main(String[] args) {
int dividend = 10;
try {
int divisor = Integer.parseInt(args[0]);
System.out.println(dividend / divisor);
//ArratIndexOutOfBoundsException은 배열의 범위를 벗어난 인덱스 사용 시 발생
//여기서는 main()의 인수가 없을 때 발생
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("원소가 존재하지 않습니다.");
//NumberFormatException은 main()의 인수를 숫자로 바꿀 수 없을 때 발생
} catch (NumberFormatException e) {
System.out.println("숫자가 아닙니다.");
//ArithmeticException은 main()의 인수가 9일 때 나눌 수 없으므로 발생
} catch (ArithmeticException e) {
System.out.println("0으로 나눌 수 없습니다.");
//finally는 예외 발생과 관계 없이 항상 실행 (finally 블록은 선택 사양)
//finally 블록 사용 시 코드의 가독성 증가
} finally {
System.out.println("항상 실행됩니다.");
}
System.out.println("종료.");
}
}
/* 예외 잡아 처리하기 - 컴파일 오류 발생 코드 */
public class TryCatch3Demo {
public static void main(String[] args) {
int[] array = { 0, 1, 2 };
try {
int x = array[3];
//Exception 객체를 처리하는 catch 블록에서 모든 예외를 처리하므로
//ArrayIndexOutOfBoundsException 객체를 처리하는 catch 블록은 도달할 수 없음
//따라서 컴파일 오류 발생
//Exception 객체가 최상위(부모)라서 나중의 다른 것들은 의미가 없음!
//부모는 맨 마지막에 위치해야 오류 발생 X!
} catch (Exception e) {
System.out.println("어이쿠!!!");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("원소가 존재하지 않습니다.");
}
System.out.println("종료.");
}
}
예외 떠넘기기
- 메서드에서 발생한 예외를 내부에서 처리하기가 부담스러울 때는 throws 키워드를 사용해
예외를 상위 코드 블록으로 양도 가능
- 현재 메서드에서 예외를 처리하지 않고 현재 메서드를 호출한 곳으로
발생한 예외 객체를 대신 처리해 달라고 떠넘기는 것!
/* 예외 떠넘기기 사용 방법 */
public void write(String filename)
throws IOEception, ReflectiveOperationException { //예외 1개 이상 선언 가능
//파일 쓰기와 관련된 실행문...
} //throws는 예외를 다른 메서드로 떠넘기는 키워드!
//자바 API 문서를 보면, 많은 메서드가 예외를 발생시키고 상위 코드로 예외 처리를 떠넘김.
/* 호출된 메서드가 호출한 메인 메서드에 예외 떠넘기기 */
import java.util.Scanner;
public class ThrowsDemo {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
try {
//square()에서 예외 발생 시 스스로 처리하지 않고 여기서 처리
square(in.nextLine());
} catch (NumberFormatException e) {
System.out.println("정수가 아닙니다.");
}
}
//호출한 메서드에서 예외를 처리하도록 떠넘기기
private static void square(String s) throws NumberFormatException {
//s가 문자열이 아니면 NumberFormatException 예외 발생
int n = Integer.parseInt(s);
System.out.println(n * n);
}
}