Presentation is loading. Please wait.

Presentation is loading. Please wait.

6 6 ███████████.

Similar presentations


Presentation on theme: "6 6 ███████████."— Presentation transcript:

1 6 6 ███████████

2 Powered by http://www.jabook.org
최 영 관 Powered by 3rd Edition 소설같은 자바 since 2001 6장 배열, 제너릭, 컬렉션

3 6.1 배경

4 6.1.1 데이터 저장 공간 프로그래밍의 기본 데이터 저장공간 배열(Array) 클래스
데이터 저장 공간을 이해하는 것 데이터 저장공간 기본 데이터 타입의 변수 일반적인 클래스의 객체 배열(Array) 클래스 단순 용량적인 측면에서의 데이터 저장공간 컬렉션(Collection)류나 맵(Map)류의 클래스 자료구조적인 측면에서의 데이터 저장공간

5 6.1.2 용량적인 저장 공간 10개의 int형 변수 선언 배열을 이용한 10개의 int형 변수 선언 Top 클래스
int a0, a1, a2, a3, a4, a5, a6, a7, a8, a9; 배열을 이용한 10개의 int형 변수 선언 int[] ar = new int[10]; Top 클래스 class Top { //...클래스의 내용 } Top 클래스 객체 10개 선언 Top t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; 배열을 이용한 Top 클래스 객체 10개 선언 Top[] t = new Top[10]; a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9] t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9]

6 6.1.3 자료구조적인 저장 공간 단순 저장공간의 문제 배열 배열의 검색 해결책
자료를 처리하는 방식의 문제(자료구조적인 측면) 동적인 공간의 문제(메모리 공간) 빠른 검색의 문제 배열 양적인 저장 공간 배열의 검색 사용자가 직접 전체 데이터를 확인해서 검색해야 한다. 해결책 컬렉션류나 맵류의 클래스 사용

7 6.2 배열

8 6.2.1 배열의 소개 배열의 종류 배열의 특징 배열의 검색 배열의 단점 기본 데이터 타입 배열 객체 배열
같은 데이터 타입의 변수를 한꺼번에 여러 개 생성할 수 있다. 배열의 검색 배열은 첨자를 통해서 배열 내에 존재하는 모든 변수를 검색할 수 있다. 배열의 단점 배열을 생성할 때 첨자를 이용해서 배열의 크기를 정해버리면 배열의 크기를 변경할 수 없다.

9 6.2.2 배열의 특징 기본 데이터 타입을 이용한 배열 클래스의 예 클래스를 이용한 배열 클래스의 예 배열의 특징 I
같은 데이터 타입의 변수를 한꺼번에 여러 개 생성할 수 있다. 배열의 크기는 배열의 첨자로 결정된다. 첨자에 해당하는 만큼의 같은 데이터 타입을 가진 변수가 생성된다. 배열의 특징 II 배열의 요소는 변수이다. 배열의 메모리는 연속적으로 잡히게 된다. 배열의 특징 III 배열의 이름은 연속된 변수들을 참조하기 위한 참조값이다. 배열 자체는 객체이다. int형 변수 10개를 만드는 구문(int형 배열의 생성) int[] ar = new int[10]; 배열을 위한 데이터 타입 int[]는 데이터 타입이다. int[]는 배열 클래스형이다. 배열의 데이터 타입 배열 데이터 타입 = 기존의 데이터 타입 + [] 기본 데이터 타입을 이용한 배열 클래스의 예 byte[] int[] long[] float[] double[] 클래스를 이용한 배열 클래스의 예 String[] Image[]

10 6.2.3 배열의 분석 배열의 분석 int[] ar = new int[10]; ar 배열의 생성 기본 데이터 타입 배열
기본 데이터 타입으로 배열을 선언하면 메모리의 생성을 의미한다. 기본 데이터 타입은 변수의 선언과 동시에 메모리가 생성되기 때문에 기본 데이터 타입으로 배열을 선언하면 배열의 전체 메모리가 생성된다. 배열의 정의 배열은 객체다. 배열의 특징 배열의 첨자는 배열의 크기를 의미한다. 배열의 이름은 참조값이다. 배열끼리의 할당은 참조값 값복사다. 배열의 개수를 확인하는 멤버 배열의 개수는 length 멤버를 이용해서 알 수 있다. int size = ar.length; // size는 10이 된다. 배열의 분석 배열 클래스 참조 변수 메모리 생성 연산자 배열 개수 지정 int[] ar = new int[10]; 데이터 타입 배열의 이름 배열의 생성 첨자 ar[0] 변수 ar[1] 변수 ar[2] 변수 참조 변수 int[] ar ar[3] 변수 배열의 개수 = 첨자 ar[4] 배열 변수 클래스명 ar[5] 변수 ar[6] 변수 ar[7] 변수 ar[8] 변수 ar[9] 변수

11 6.2.4 배열의 초기화 배열의 선언과 할당의 분리 배열의 생성과 배열의 접근을 테스트하는 예제
public class ArrayMain{ public static void main(String[] args){ int[] ap = new int[]{0,1,2,3,4,5,6,7,8,9}; int[] aw = {10,11,12,13,14,15,16,17,18,19}; int[] ad = new int[10]; //선언과 할당의 분리 ad[0] = 20; ad[1] = 21; ad[2] = 22; ad[3] = 23; ad[4] = 24; ad[5] = 25; ad[6] = 26; ad[7] = 27; ad[8] = 28; ad[9] = 29; //1. int[] ap 출력 for(int i=0; i<ap.length; i++){ System.out.print(ap[i] + "\t"); } //2. int[] aw 출력 for(int i=0; i<aw.length; i++){ System.out.print(aw[i] + "\t"); //3. int[] ad 출력 for(int i=0; i<ad.length; i++){ System.out.print(ad[i] + "\t"); int[] ar = new int [10]; ar[0] = 100; ar[1] = 200; ar[2] = 343; ar[3] = 325; ar[4] = 5; ar[5] = 2; ar[6] = 7; ar[7] = 30; ar[8] = 35; ar[9] = 43; 각각의 변수에 하나씩 값할당 배열의 선언과 할당의 분리 int[] ar = new int[] {100, 200, 343, 325, 5, 2, 7, 30, 35, 43}; int[] ar = {100, 200, 343, 325, 5, 2, 7, 30, 35, 43}; 배열의 선언과 동시에 초기화 이 방법들은 선언과 초기화를 동시에 하는 방법이다. 위의 방법 둘 다 사용할 수 있다. 1 2

12 6.2.5 배열의 복사 배열의 참조값 값복사 부분 배열 복사를 위한 System.arraycopy()
int[] ar1 = new int[]{0,1,2,3,4,5,6,7,8,9}; int[] ar2 = ar1; 3 메모리 영역 4 Index Table new int[]{0,1,2,3,4,5,6,7,8,9} ar1[0] = 0; ar1[1] = 1; ar1[2] = 2; ar1[3] = 3; ar1[4] = 4; ar1[5] = 5; ar1[6] = 6; ar1[7] = 7; ar1[8] = 8; ar1[9] = 9; 참조값 실제 메모리 주소 객체의 실제 주소 1 2 10001 FFFF:07CA 배열의 실제 메모리 참조값 (해시코드) 실제 주소 부분 배열 복사를 위한 System.arraycopy() int[] source = new int[]{5, 4, 6, 9, 7, 9}; int[] target = {100, 200, 300, 400, 500, 600,700}; //부분 배열 복사의 예 System.arraycopy(source, 2, target, 3, 4); for(int i=0; i<target.length; i++) { System.out.println("target["+i+"]:" + target[i]); } clone()을 이용한 메모리 차원의 배열복사 int[] source = new int[]{5, 4, 6, 9, 7, 9}; //clone()을 이용한 메모리 복사 int[] target = (int[])source.clone(); for(int i=0; i<target.length; i++){ System.out.println("target["+i+"] : " + target[i]); }

13 6.2.6 객체 배열 dog[1] = new Dog("워리","똥개");
class Dog { private String name; private String kind; public Dog(String name, String kind) { this.name = name; this.kind = kind; } public String toString() { return kind + ":" + name; public class ObjectArrayMain { public static void main(String[] args) { //1. 객체배열의 생성 Dog[] dog = new Dog[5]; for(int i=0; i<dog.length; i++) System.out.println("Dog[" + i + "] : " + dog[i]); //2. 객체배열의 참조 변수에 메모리할당 dog[0] = new Dog("쫑쫑이","불독"); dog[1] = new Dog("워리","똥개"); dog[2] = new Dog("개똥이","진도개"); dog[3] = new Dog("발리","푸들"); dog[4] = new Dog("투덜이","잡종"); 객체 배열 객체 배열을 선언했을 때 첨자의 수만큼 참조 변수가 만들어진다. 각각의 참조 변수에 대한 객체의 메모리는 생성되지 않는다. 기본 데이터 타입 배열 vs 객체 배열 기본 데이터 타입 배열은 배열 생성과 동시에 메모리가 생성된다. 객체 배열은 객체 변수(참조 변수)의 이름들만 생성되고, 객체들의 실제 메모리는 생성되지 않는다.

14 6.2.7 결론 자바의 배열 자바의 배열 표기법 배열의 복사 NullPointerException 배열의 이름은 참조 변수다.
자바에서 배열은 객체이다. int[]까지가 배열 데이터 타입이다. 자바의 배열 표기법 int[] ar = new int[10]; int ar[] = new int[10]; 배열의 복사 System.arraycopy()를 이용한 부분 배열 복사 clone()을 이용한 배열 통복사 NullPointerException 객체 변수에 메모리가 없다.

15 6.3 배열의 참조

16 6.3.1 배열의 참조 매개변수의 참조값 값복사 배열끼리의 할당 객체의 참조값
int[] ar = new int[]{0,1,2,3,4,5,6,7,8,9}; 4 배열 매개변수로 메서드 호출 3 참조 값복사가 발생 메모리 영역 sum(ar); ar 에 10001의 참조값 temp 에 10001의 참조값 int[] temp = ar; 참조값 값복사 발생 new int[]{0,1,2,3,4,5,6,7,8,9} Index Table ar[0] = 0; ar[1] = 1; ar[2] = 2; ar[3] = 3; ar[4] = 4; ar[5] = 5; ar[6] = 6; ar[7] = 7; ar[8] = 8; ar[9] = 9; 참조값 실제 메모리 주소 5 2 배열의 실제 메모리 10001 FFFF:07CA 객체의 실제 주소 1 int sum ( int[] temp ) { //배열의 총합계산 } 메서드의 원형 참조값 실제 주소 배열끼리의 할당 int[] ar1 = new int[]{0,1,2,3,4,5,6,7,8,9}; int[] ar2 = ar1; 객체의 참조값 객체의 참조값만 있으면 해당 객체를 핸들할 수 있다.

17 6.3.2 배열 할당의 참조 직접할당을 이용한 참조값 값복사 int[] aref = new int[]{0,1,2,3};
int[] bref = aref; int[] cref = bref; new int[]{0,1,2,3} 실제 메모리 주소 FFFF:07CA Index Table 실제 주소 메모리 영역 ar[0] = 0; ar[1] = 1; ar[2] = 2; ar[3] = 3; 객체의 실제 주소 1 2 참조값 직접할당을 이용한 참조값 값복사 배열의 실제 메모리 10001 3 4 5 int[]형의 배열 생성 int[] aref = new int[]{0,1,2,3}; 참조값 값복사(참조값 할당) int[] bref = aref; int[] cref = bref; 주의할 점 배열의 이름은 참조 변수다. 배열끼리 할당할 때 데이터 타입은 같아야 한다. 위의 배열들은 데이터 타입이 모두 int[]이다.(aref, bref, cref)

18 6.3.3 객체의 참조 class Baby{ private String name;
public void setName(String name){ this.name = name; } public void cry() { System.out.println(name + " 가(이) 응애응애"); public class BabyRefMain { public static void main(String[] args) { Baby b = new Baby(); b.setName("둘리"); b.cry(); Baby s = b; //참조값 값복사 발생 s.setName("아기공룡"); s.cry();

19 6.3.4 매개변수로서의 배열 class ArrayParam {
public int[] copyArray( int[] src) {//배열 복사를 위한 메모리를 메서드 내에서 생성 int[] des = new int[src.length]; //새로운 배열 생성 for(int i=0; i<src.length; i++) des[i] = src[i]; //값복사 return des; } public void copyArray (int[] src, int[] des) {//배열 복사를 위한 메모리를 매개변수로 받음 int[] source = new int[]{1,2,3,4,5}; //배열 생성 ArrayParam p = new ArrayParam(); //객체 생성 1. copyArray(int[] src) 호출 int[] result = p.copyArray(source); for(int i=0; i<result.length; i++){ System.out.println("result["+i+"] : " + result[i]); 2. copyArray(int[] src, int[] des) 호출 int[] target = new int[source.length]; p.copyArray(source, target); for(int i=0; i<target.length; i++) { System.out.println("target["+i+"] : " + target[i]);

20 int[][] ar = new int[2][3];
6.3.5 다차원 배열 int[][] ar = new int[][]{{100, 200, 300}, {400,500,600}}; int[][] ar = {{100, 200, 300}, {400,500,600}}; 2차원 배열의 선언과 초기화를 동시에 이 방법들은 선언과 초기화를 동시에 하는 방법입니다. 위의 방법 둘 다 사용할 수 있습니다. 1 2 클래스명 선언과 동시에 초기화 (배열의 개수는 자동으로 [2][3]이 된다) int[][] src = new int[][]{{100,200,300}, {400,500,600}}; int[][] tar = {{701,702,703}, {704,705,706}}; //int[][] src의 정보출력 System.out.print("src.length:" + src.length + "\t"); System.out.print("src[0].length:" + src[0].length + "\t"); System.out.println("src[1].length:" + src[1].length); //int[][] tar의 정보출력 System.out.print("tar.length:" + tar.length + "\t"); System.out.print("tar[0].length:" + tar[0].length + "\t"); System.out.println("tar[1].length:" + tar[1].length); //2차원 배열의 출력 for(int i=0; i<src.length; i++) for(int j=0; j<src[i].length; j++){ System.out.print("src[" + i + "][" + j + "]=" + src[i][j] + "\t"); System.out.print("tar[" + i + "][" + j + "]=" + tar[i][j] + "\n"); } //for문에 블록이 없으면 한 줄에 영향을 준다. 클래스명 ar[0][0] = 100 ar[0][1] = 200 ar[0][2] = 300 int[][] ar = new int[2][3]; ar[1][0] = 400 ar[1][1] = 500 ar[1][2] = 600 2차원 배열의 선언과 할당의 분리 배열 클래스 참조 변수 메모리 생성 연산자 배열 개수 지정 변수 ar 배열의 개수 = 2 X 3 배열 int[][]

21 int[][] ar = new int[2][3];
2차원 배열의 분석(배열의 배열) 배열의 개수 = 2 X 3 배열의 배열 2차원 배열은 배열의 배열입니다. ar의 원소는 ar[0], ar[1] ar[0][0] = 100 ar[0] 참조변수 ar[0][1] = 200 ar[0][2] = 300 ar[1][0] = 400 ar[1][1] = 500 ar[1][2] = 600 ar[1] 1차원 배열 ar 배열 원소는 2개 원소는 3개 int[][] ar = new int[2][3]; 배열 클래스 메모리 생성 연산자 배열 개수 지정 데이터 타입 배열의 이름 배열의 생성 첨자 2차원 배열의 분석(배열의 배열) 변수

22 6.3.6 배열의 배열과 참조의 참조 배열끼리의 직접할당 & 객체끼리의 직접할당 Top 클래스 참조 변수의 참조 변수
배열의 메모리가 복사되지 않고 참조값 값복사가 이루어진다. 객체의 메모리가 복사되지 않고 참조값 값복사가 이루어진다. Top 클래스 class Top{ public String s; public String p; } 참조 변수의 참조 변수 Top t = new Top(); t.s = new String("Hello"); t.p = new String("Hi"); 참조 변수의 참조 변수와 배열의 배열 참조 변수의 참조 변수의 원리는 배열의 배열과 유사한 원리로 되어 있다. Top t = new Top(); Hello String s String p Hi

23 6.4 Generic(자바 5.0)

24 T라는 타입은 아직 정해지지 않았으며 사용할 때 결정한 후 사용한다.
6.4.1 제너릭(Generic)이란? Generic 이란 클래스에 사용할 타입을 디자인시에 지정하는 것이 아니라 클래스를 사용할 때 지정한 후 사용하는 기술을 말한다. Object형을 매개변수로 사용한 예 class Top{ private Object data = null; public void setData(Object data){ this.data = data; } public Object getData(){ return this.data; Generic을 매개변수로 사용한 예 class Top<T>{ private T data = null; public void setData(T data){ public T getData(){ Object형은 어떠한 형으로도 캐스팅가능하기 때문에 형을 알 수 없을 때에는 Object형을 사용하였다. String str = "Hello Object 방식"; Top t = new Top(); t.setData(str); String str2 = (String)t.getData(); 사용할 형을 컴파일러에게 알려준다. String str = "Hello Generic 방식"; Top<String> t = new Top<String>(); t.setData(str); String str2 = t.getData(); Top<String>을 사용했기 때문에 getData() 메서드는 String형을 리턴한다. T라는 타입은 아직 정해지지 않았으며 사용할 때 결정한 후 사용한다.

25 6.4.2 C++의 제너릭의 원리 C++의 경우 Top<String> Top<Integer>
제너릭을 사용하는 순간 컴파일러는 해당 제너릭에 대한 형을 새로 만든다. Top<String> t1 = new Top<String>(); Top<Integer> t2 = new Top<Integer>(); Top<String> Top<Integer> class Top<String>{ private String data = null; public void setData(String data){ this.data = data; } public String getData(){ return this.data; class Top<Integer>{ private Integer data = null; public void setData(Integer data){ this.data = data; } public Integer getData(){ return this.data; Top<String>과 Top<Integer>를 사용했기 때문에 컴파일러는 이것을 보고 Top<String>과 Top<Integer>에 해당하는 형을 통째로 만든다.

26 6.4.3 Java의 제너릭의 원리 자바의 제너릭 코드 내에서 Top<String>형 클래스의 사용
자바 컴파일러는 Top<String>이나 Top<Integer>를 만나게 되면 <String>과 <Integer>를 삭제(Erasure)한 후, 컴파일러는 적절한 곳에 캐스팅(casting)으로 대체한다. 코드 내에서 Top<String>형 클래스의 사용 Top<String> t = new Top<String>(); t.setData(str); String str2 = t.getData(); 자바 컴파일러가 제너릭을 처리하는 방식 Top t = new Top(); String str2 = (String)t.getData(); Top<String>은 클래스의 형이 아니라 캐스팅을 판단하기 위한 표시이다. 자동으로 제거된다. 제너릭이 자동으로 붙여준다. C++에서는 제너릭이 하나의 형이지만 자바에서는 캐스팅을 판단하기 위한 표시이다. 그렇기 때문에 자바의 제너릭은 리플렉션이 적용되지 않는다. 이것은 자바의 제너릭이 타입(형)이 아니기 때문이다.

27 6.4.4 제너릭의 Collection 적용 제너릭의 표현 자바 5.0 이전 버전의 Vector 사용
class Vector <E> 요소(Element)를 제너릭 <E>로 표현한다. class Hashtable <K, V> 키(Key)를 제너릭 <K>로, 값(Value)을 제너릭 <V>로 표현한다. 자바 5.0 이전 버전의 Vector 사용 Vector v1 = new Vector(); v1.add(new String("Hello World")); String str1 = (String)v1.elementAt(0); 자바 5.0 이상 버전의 Vector 사용 Vector<String> v2 = new Vector<String>(); v2.add(new String("Hello World")); String str2 = v2.elementAt(0); 사용자가 직접 캐스팅을 해주어야 한다. 두개 중 어느것을 사용해도 상관 없다. 이전 버전과의 호환성이 중요하다면 제너릭을 사용하기 보다는 사용자가 직접 캐스팅하는 방법을 이용하기 바란다. 캐스팅을 해주지 않아도 된다.(컴파일러가 알아서 캐스팅 해줌)

28 6.5 Collection과 Map

29 6.5.1 배열의 발전된 형태 배열의 발전된 모델 배열과 컬렉션이나 맵계열의 클래스와의 차이점
컬렉션(Collection)과 맵(Map) 계열의 클래스 배열과 컬렉션이나 맵계열의 클래스와의 차이점 배열은 크기를 동적으로 늘릴 수 없지만 컬렉션이나 맵 계열의 클래스는 동적으로 메모리를 확장할 수 있다. Collection류와 Map류의 클래스 자료구조적인 기능의 클래스 Collection과 Map 인터페이스 Collection과 Map은 인터페이스이기 때문에 메서드의 프로토타입만 존재한다. Collection을 구현해서 사용하면 집합적인 저장공간으로서의 기능을 구현한 클래스가 된다. Map을 구현해서 사용하면 검색적인 저장공간으로서의 기능을 구현한 클래스가 된다.

30 6.5.2 Collection과 Map의 특징 Collection과 Map 유형이 배열과 구분되는 점
동적 메모리 확장 Collection과 Map류는 객체만을 저장의 대상으로 한다. Collection의 삽입과 삭제를 위한 추상 메서드 boolean add(Object o) boolean remove(Object o) Map의 삽입과 삭제를 위한 추상 메서드 Object put(Object key, Object value) Object remove(Object key) boolean add(E o) boolean remove(Object o) 자바 1.4까지 자바 5.0(자바 1.5)부터 V put(K key, V value) V remove(Object key) 자바 1.4까지 자바 5.0(자바 1.5)부터

31 6.5.3 Collection과 Map의 상속구조 LinkedList Stack List Vector Collection
링크드리스트 Stack 스택자료구조 List Vector 순서가 있는 저장 공간 Collection 동기화 보장 순서나 집합적인 저장공간 ArrayList 동기화 보장하지 않음 HashSet Set Set계열의 대표클래스 집합적인 저장 공간 SortedSet Hashtable 정렬을 위한 Set 계열의 클래스 Map 동기화 보장하는 Map 계열의 클래스 HashMap 키와 값으로 데이터 핸들 TreeSet 동기화 보장하지 않는 Map 계열의 클래스 SortedMap TreeMap 정렬을 위한 Map 계열의 클래스

32 6.5.4 Collection 인터페이스 boolean add(E o) boolean remove(Object o)
이것을 구현한 클래스들은 모두 집합적인 저장공간으로서의 기능을 가진다. Collection 인터페이스를 구현하고 있는 클래스 Stack, Vector, LinkedList, TreeSet, HashSet Collection 인터페이스의 데이터 삽입 삭제를 위한 추상 메서드 boolean add(Object o); 객체를 삽입하는 메서드 boolean remove(Object o); 특정 객체를 삭제하는 메서드 Collection 인터페이스의 데이터 확인을 위한 추상 메서드(5.0이전 이후 동일) boolean isEmpty(); 비어 있는지 확인하는 메서드 boolean contains(Object o); 특정 객체가 포함되어 있는지 확인하는 메서드 int size(); 포함된 객체의 수를 리턴하는 메서드 Collection 인터페이스의 데이터를 배열로 얻기 위한 추상 메서드 Object[] toArray(); 포함된 모든 객체들을 배열 형태로 리턴하는 메서드 boolean add(E o) boolean remove(Object o) 자바 1.4까지 자바 5.0(자바 1.5)부터 T[] toArray() 자바 1.4까지 자바 5.0(자바 1.5)부터

33 6.5.5 Map 인터페이스 V put(K key, V value); V remove(Object key);
Collection과 달리 Map은 검색적인 개념을 담고 있는 인터페이스 Map으로 구현된 클래스 Attributes, HashMap, Hashtable, TreeMap Map 인터페이스의 데이터 삽입 삭제를 위한 추상 메서드 Object put(Object key, Object value); 데이터를 삽입하는 메서드 Object remove(Object key); 키(key)를 이용해서 데이터를 제거하는 메서드 Object get(Object key); 키(key)를 이용해서 데이터를 검색하는 메서드 Map 인터페이스의 데이터 확인을 위한 추상 메서드(자바 5.0 이전 이후 동일) boolean isEmpty(); 비어 있는지 확인하는 메서드 boolean containsKey(Object key); 특정 키가 있는지 확인하는 메서드 boolean containsValue(Object value); 특정 데이터가 있는지 확인하는 메서드 int size(); 포함된 객체가 몇 개인지 확인하는 메서드 V put(K key, V value); V remove(Object key); V get(Object key); 자바 1.4까지 자바 5.0(자바 1.5)부터

34 6.6 컬렉션 클래스 비교

35 6.6.1 Vector와 ArrayList의 비교 Vector와 ArrayList의 공통점
순서가 있는 Collection이다. List 인터페이스를 구현하고 있다. 데이터를 중복해서 포함할 수 있다. Vector와 ArrayList의 차이점 Vector는 자동으로 동기화를 보장해준다. ArrayList는 동기화를 보장해주지 않는다. ArrayList의 동기화 지원 방법 List list = Collections.synchronizedList(new ArrayList(...)); Vector와 ArrayList의 기능 ArrayList는 배열에 동적 메모리 증가 기능을 구현한 클래스이다. Vector는 ArrayList에 동기화가 보장되도록 최적화한 클래스이다. Collection List Stack Vector ArrayList LinkedList 동기화보장 동기화보장하지 않음

36 6.6.2 Hashtable, HashMap의 비교 Hashtable, HashMap의 공통점
키(Key)와 값(Value)을 이용해서 데이터를 관리한다. Hashtable과 HashMap Hashtable은 동기화가 보장 되지만 HashMap은 동기화가 보장되지 않는다. HashMap의 동기화 지원 방법 Map m = Collections.synchronizedMap(new HashMap(...)); Hashtable, HashMap과 HashSet과의 관계 Hashtable과 HashMap은 둘다 Map 인터페이스를 구현하고 있다. HashSet은 내부적으로 Hash기법을 사용하지만 Set 인터페이스를 구현하고 있다. Map SortedMap Hashtable HashMap 동기화보장 동기화보장하지 않음

37 6.6.3 ArrayList와 HashSet의 비교
객체의 저장공간이다. 동기화를 보장하지 않는다. ArrayList와 HashSet의 차이점 ArrayList List 인터페이스를 구현하는 클래스이다. 순서의 개념이 있다. 데이터의 중복을 허용한다. HashSet Set 인터페이스를 구현하는 클래스이다. 순서의 개념이 아니라 집합의 개념이 있다. 데이터의 중복을 허용하지 않는다. ArrayList와 HashSet의 기능 순서가 중요한 의미를 가진다면 ArrayList를, 순서는 중요하지 않고 데이터가 중복되지 않기를 원한다면 HashSet을 이용하면 된다. Collection Set List HashSet Stack Vector ArrayList LinkedList SortedSet 순서의개념, 중복허용 집합의개념, 중복불허

38 6.6.4 Sorted와 Not Sorted의 비교 Sorted를 지원하지 않음 Sorted를 지원하는 함 TreeMap
HashSet, HashMap Sorted를 지원하는 함 TreeSet과 TreeMap TreeMap Key와 Value로 데이터 관리 Key를 기준으로 오름차순으로 정렬된다. Map 인터페이스를 상속한 SortedMap 인터페이스를 구현한 클래스 TreeSet Set을 인터페이스를 상속한 SortedSet 인터페이스를 구현한 클래스 데이터들이 자동으로 오름차순으로 정렬된다. Comparator 인터페이스 TreeSet과 TreeMap은 사용자가 직접 정렬의 방식을 지정할 수 있다. TreeSet과 TreeMap은 정렬을 위한 Comparator 인터페이스를 구현하면 된다. Collection Set Map HashSet TreeSet SortedMap Hashtable HashMap TreeMap SortedSet

39 6.7 Collection 계열 클래스

40 6.7.1 Stack import java.util.*; public class StackMain{
public static void main(String[] args) { Stack<String> stack = new Stack<String>(); System.out.println(stack.empty()); stack.push(new String("jabook")); stack.push(new String("java")); stack.push(new String("소설같은 자바")); System.out.println(stack.peek()); System.out.println(stack.pop()); System.out.println(stack.search("jabook")); } Collection List LinkedList Stack Vector ArrayList

41 6.7.2 ArrayList import java.util.*; public class ArrayListMain{
public static void main(String args[]) { ArrayList<String> list = new ArrayList<String>(); list.add("홍길동"); list.add("김삿갓"); list.add("이몽룡"); list.add("성춘향"); list.add("변사또"); System.out.println(list); System.out.println("Index 2 : " + list.get(2)); System.out.println("Index 0 : " + list.get(0)); String[] arList = new String[list.size()]; list.toArray(arList); System.out.println("Index 1 : " + arList[1]); System.out.println("Index 3 : " + arList[3]); } Collection List Stack Vector ArrayList LinkedList

42 6.7.3 HashSet import java.util.*; public class HashSetMain{
public static void main(String args[]) { Set<String> set = new HashSet<String>(); set.add("김삿갓"); set.add("홍길동"); set.add("춘향이"); set.add("이도령"); set.add("향단이"); System.out.println("HashSet : " + set); set.remove("이도령"); System.out.println(set.contains("홍길동")); Iterator<String> iter = set.iterator(); while(iter.hasNext()){ String temp = iter.next(); System.out.print(temp + ", "); } System.out.println(); HashSet Collection Set SortedSet

43 6.7.4 Vector I Vector v에 데이터가 삽입된 순서 Vector v = new Vector();
public class VectorMain { public static void main(String[] args) { Vector<String> v = new Vector<String>(); //Vector 객체 생성 System.out.println("Vector 생성 직후의 size : " + v.size()); v.addElement(new String("망아지")); v.addElement(new String("송아지")); v.addElement(new String("강아지")); v.addElement(new String("병아리")); System.out.println("Vector에 데이터 삽입 후의 size : " + v.size()); for(int i=0; i< v.size(); i++){ String temp = v.elementAt(i); System.out.println("Vector v의 " + i + "번째 :" + temp); } Collection List Stack Vector ArrayList LinkedList Vector v에 데이터가 삽입된 순서 Vector v = new Vector(); v.addElement(new String(”망아지")); v.addElement(new String("송아지")); v.addElement(new String("강아지")); v.addElement(new String("병아리")); 인덱스 : 0 인덱스 : 1 인덱스 : 2 인덱스 : 3 new String("망아지") new String(”송아지") new String(”강아지") new String(”병아리")

44 6.7.5 Vector II Vector<Object> v = new Vector<Object>(); //객체 생성 v.addElement(new Character('A')); //Wrapper 클래스의 사용 v.addElement(new String("굼뱅이")); v.addElement(new Integer(100)); //Wrapper 클래스의 사용 v.addElement(new Integer(200)); //Wrapper 클래스의 사용 System.out.println("Vector의 size():" + v.size()); v.insertElementAt(new Float( ), 1); System.out.println("insertElementAt()-size():" + v.size()); v.setElementAt("Hello", 3); System.out.println("setElement()-size():" + v.size()); System.out.println("v의0번째:" + (Character)v.elementAt(0)); System.out.println("v의1번째:" + (Float)v.elementAt(1)); System.out.println("v의2번째:" + (String)v.elementAt(2)); System.out.println("v의3번째:" + (String)v.elementAt(3)); System.out.println("v의4번째:" + (Integer)v.elementAt(4)); if(v.contains("Hello")){ //데이터가 있는지 확인 int find = v.indexOf("Hello"); //데이터 위치 확인 //위치(인덱스)를 이용한 데이터의 추출 System.out.println("v의" + find + "번째:" + (String)v.elementAt(find)); } Vector v에 객체삽입 1번째에 중간삽입, 1번째에 있던 데이터는 2번째가 된다. 3번째 존재하는 데이터를 수정 삽입한 데이터 타입이 다르기 때문에 하나씩 추출한 뒤 형변환 후 사용 "Hello" 검색

45 6.7.6 AutoBoxing(자바 5.0) 자바 1.4까지 자바 5.0 이후
Vector v = new Vector(); //객체 생성 v.addElement(new Integer(100)); //Wrapper 클래스의 사용 v.addElement(new Integer(200)); //Wrapper 클래스의 사용 Integer t0 = (Integer)v.elementAt(0); Integer t1 = (Integer)v.elementAt(1); 자바 5.0 이후 Vector<Integer> v = new Vector<Integer>(); v.addElement(100); //AutoBoxing 발생 v.addElement(200); //AutoBoxing 발생 int a0 = v.elementAt(0);//AutoUnBoxing 발생 int a1 = v.elementAt(1);//AutoUnBoxing 발생 자바 5.0 이상에서는 컴파일러가 내부에서 자동으로 객체를 적절한 상수값으로 변경시켜 준다. 자바 5.0 이상에서는 컴파일러가 내부에서 자동으로 Wrapper 클래스의 객체로 변경시켜 준다.

46 6.8 Map 계열 클래스

47 6.8.1 HashMap import java.util.*; public class HashMapMain{
public static void main(String args[]) { Map<String, Integer> map = new HashMap<String, Integer>(); map.put("홍길동", new Integer(1)); map.put("김삿갓", new Integer(2)); map.put("이도령", new Integer(3)); map.put("춘향이", new Integer(4)); map.put("향단이", new Integer(5)); System.out.println(map.get("홍길동")); System.out.println(map.get("김삿갓")); System.out.println(map.get("이도령")); System.out.println(map.get("춘향이")); System.out.println(map.get("향단이")); } Key Value Hashtable HashMap Map SortedMap

48 6.8.2 Hashtable import java.util.Hashtable; public class HashtableMain { public static void main(String[] args) { Hashtable<String, Object> h = new Hashtable<String, Object>(); //Hashtable에 키와 데이터의 삽입 h.put("Name", new String("홍길동")); h.put("Age", new Integer(27)); h.put("Tel", new String(" ")); h.put("Handphone", new String(" ")); h.put("Etc", new String("I'm a boy")); //키 값을 이용해서 객체 추출 String name = (String)h.get("Name"); Integer age = (Integer)h.get("Age"); } Key Value Hashtable HashMap Map SortedMap

49 6.9 Sorted 계열 클래스

50 6.9.1 TreeSet과 TreeMap HashSet을 이용한 TreeSet 생성
Set<String> set = new HashSet<String>(); set.add(new String("김삿갓")); set.add(new String("홍길동")); set.add(new String("춘향이")); set.add(new String("이도령")); set.add(new String("향단이")); TreeSet<String> ts = new TreeSet<String>(); ts.addAll(set); HashMap을 이용해서 TreeMap 생성 Map<String, Integer> map = new HashMap<String, Integer>(); map.put("홍길동", new Integer(1)); map.put("김삿갓", new Integer(2)); map.put("이도령", new Integer(3)); map.put("춘향이", new Integer(4)); map.put("향단이", new Integer(5)); Map<String, Integer>sortedMap = new TreeMap<String, Integer>(); sortedMap.putAll(map); HashSet TreeSet Set sorted 기능을 이용하기 위해서 HashMap TreeMap Map sorted 기능을 이용하기 위해서

51 6.9.2 TreeSet의 Comparator 구현
class Score{ private int korea=0; private int math=0; public Score(int korea, int math){ this.korea = korea; this.math = math; } public int getSum(){ return this.korea + this.math; public String toString(){ return "국어:" + korea + " 수학:" + math; class MyComparator<T> implements Comparator<T>{ public int compare(T o1, T o2){ Score s1 = (Score)o1; Score s2 = (Score)o2; int r = s1.getSum() - s2.getSum(); if(r>0){ return 1; //오름차순 정렬 }else if(r==0){ return 0; }else { return -1; //내림차운 정렬 TreeSet<Score> tset = new TreeSet<Score>(new MyComparator<Score>()); 비교법지정 데이터 삽입 tset.add(new Score(21, 22)); tset.add(new Score(61, 62)); tset.add(new Score(81, 82)); tset.add(new Score(11, 12)); tset.add(new Score(31, 32)); 사용자 정의 Comparator 삽입과 동시에 자동으로 정렬된다. Comparator는 Sorting을 위한 기준을 제시한다.

52 6.9.3 TreeMap의 Comparator 구현
TreeMap<Score, String> tset = new TreeMap<Score, String>(new MyComparator<Score>()); class Score{ private int korea=0; private int math=0; public Score(int korea, int math){ this.korea = korea; this.math = math; } public int getSum(){ return this.korea + this.math; public String toString(){ return "국어:" + korea + " 수학:" + math; class MyComparator<T> implements Comparator<T> public int compare(T o1, T o2){ Score s1 = (Score)o1; Score s2 = (Score)o2; int r = s1.getSum() - s2.getSum(); if(r>0){ return 1; //오름차순 정렬 }else if(r==0){ return 0; }else { return -1; //내림차운 정렬 비교법지정 데이터 삽입 tset.put(new Score(21, 22), "홍길동1"); tset.put(new Score(61, 62), "홍길동2"); tset.put(new Score(81, 82), "홍길동3"); tset.put(new Score(11, 12), "홍길동4"); tset.put(new Score(31, 32), "홍길동5"); Comparator 삽입과 동시에 자동으로 소팅된다. Comparator는 Sorting을 위한 기준을 제시한다.

53 6.10 Enumeration과 Iterator

54 6.10.1 컬렉션 검색 컬렉션 검색을 위한 인터페이스 Enumeration과 Iterator의 특징
Advanaced for(foreach) Enumeration과 Iterator의 특징 데이터의 마지막에 상관하지 않고 모든 데이터에 접근할 수 있다. Iterator는 자바 1.2에서 제공, Enumeration의 대체용 컬렉션 검색을 위한 제어문(자바 5.0) Advanced for(일명 foreach) 자바 5.0에 새롭게 추가된 컬렉션을 위한 반복 제어문 데이터의 마지막에 상관하지 않고 검색하기 위한 제어문 Advanced for의 예 String[] ar = new String[]{"안녕1", "안녕2", "안녕3"}; for (String tmp : ar ){ System.out.println( tmp ); } 반복변수

55 6.10.2 Vector에서의 Enumeration
첫위치는 어떠한 데이터도 가르키지 않는다. 실제 데이터 데이터가 있는지 확인 hasMoreElements() hasMoreElements() hasMoreElements() 1 1 2 3 4 5 6 true true true nextElement() nextElement() nextElement() nextElement() 할 때마다 키가 움직임 nextElement()는 데이터가 있는지 확인한 후 사용 데이가 있는지 확인할 때 hasMoreElements() 사용 Enumeration 얻어내기 Enumeration<String> en = v.elements(); Enumeration을 이용해서 전체 데이터 추출 while(en.hasMoreElements()){ String temp = en.nextElement(); System.out.println(temp); } Vector 생성과 데이터 삽입 Vector<String> v = new Vector<String>(); v.addElement(new String("망아지")); v.addElement(new String("송아지")); v.addElement(new String("강아지")); v.addElement(new String("병아리"));

56 6.10.3 Hashtable에서의 Enumeration
Hashtable<String, String> h = new Hashtable<String, String>(); h.put("1", new String("홍길동")); h.put("2", new String("안녕하세요")); h.put("3", new String(" ")); h.put("4", new String(" ")); Enumeration 얻기 Enumeration en = h.elements(); Hashtable의 값(Value)을 Enumeration 얻기 Enumeration<String> en = h.elements(); while(en.hasMoreElements()){ //데이터 얻기(다운캐스팅 필요) String temp = en.nextElement(); System.out.println(temp); } Hashtable의 키(Key)에 해당하는 Enumeration 얻기 Enumeration<String> en2 = h.keys(); while(en2.hasMoreElements()){ String temp = en2.nextElement();

57 6.10.4 Iterator(자바 1.2) Vector의 Iterator Hashtable의 Iterator
Vector<String> v = new Vector<String>(); v.addElement(new String("망아지")); v.addElement(new String("송아지")); v.addElement(new String("강아지")); v.addElement(new String("병아리")); Iterator<String> iter = v.iterator(); while(iter.hasNext()){ String temp = iter.next(); System.out.println(temp); } Hashtable의 Iterator Hashtable<String,String> h = new Hashtable<String,String>(); h.put("1", new String("홍길동")); h.put("2", new String("안녕하세요")); h.put("3", new String(" ")); h.put("4", new String(" ")); Iterator<String> iter2 = h.values().iterator(); while(iter2.hasNext()){ String temp = iter2.next();

58 6.10.5 Enumeration과 Iterator의 차이
Fail-Fast 방식 Iterator를 이용해서 순차적으로 접근하고 있는 도중 다른 곳에서 해당 컬렉션에 데이터를 추가하거나 삭제하는 등의 작업이 일어난다면 ConcurrentModificationException이 발생하게 하는 방식 자바 1.2부터 지원 Enumeration은 컬렉션의 집합을 통째로 복사해서(SnapShot) 사용하기 때문에 Fail-Fast를 지원하지 않는다. Enumeration과 Iterator의 차이점 메서드의 이름이 다르다 hasMoreElements()가 hasNext()로 대체 nextElement()가 next()로 대체 Iterator는 remove() 메서드를 제공한다. Fail-Fast 지원 여부 Iterator는 Fail-Fast방식을 지원한다. Enumeration은 Fail-Fast 방식을 지원하지 않는다. 대체적으로 Enumeration보다는 Iterator를 사용하기를 권장한다.

59 6.10.6 for each 문(자바 5.0)의 예 import java.util.*;
public class ForEachMain{ public static void main(String[] args){ ArrayList<String> ar = new ArrayList<String>(); ar.add("안녕1"); ar.add("안녕2"); ar.add("안녕3"); //1. 일반적인 For문 for (Iterator<String> i = ar.iterator(); i.hasNext(); ) { String tmp = i.next(); System.out.println(tmp); } //2. For Each문 Java SE 5.0의 코드 for (String tmp : ar){

60 7 7 ███████████

61 Powered by http://www.jabook.org
최 영 관 Powered by 3rd Edition 소설같은 자바 since 2001 7장 Exception, 문자열, 자바 5.0

62 7.1 예외처리(Exception Handling)

63 7.1.1 개요 자바의 에러 컴파일 타임 에러 실행 타임 에러 자바의 예외처리(Exception Handling)
컴파일 타임 에러(Compile-Time Error) 실행 타임 에러(Run-Time Error) 컴파일 타임 에러 자바의 문법적인 에러이기 때문에 아주 쉽게 처리할 수 있다. 실행 타임 에러 디버깅의 절차를 거치지 않으면 거의 잡을 수 없는 심각한 버그(Bug)인 경우가 많다. 실행 타임의 잘못된 에러는 프로그램 자체를 멈추게 하는 원인이 된다. 자바의 예외처리(Exception Handling) try, catch, finally의 사용

64 7.1.2 에러 이벤트(Error Event) 컴파일 타임 오류(Compile-Time Error)
자바의 문법적 오류로 컴파일이 되지 않는 구문상의 오류 실행 타임 오류(Run-Time Error) 컴파일은 되지만 실행이 되지 않는 로직(Logic)상의 오류 에러 이벤트(Error Event) 자바에서는 에러가 발생했을 때 에러 이벤트(Error Event)라는 것이 발생한다. Exception의 정의 Exception은 실행 타임에 발생하는 에러 이벤트(Error Event)를 말한다.

65 7.1.3 예외 처리 에러처리 방법 I 에러처리 방법 II try와 catch 블록의 사용 에러처리의 의무화
프로그램적으로 에러가 발생하지 않도록 완벽하게 코딩 에러처리 방법 II try와 catch를 이용해서 프로그래머가 에러를 감지해서 처리 try와 catch 블록의 사용 try{ //파일로딩 //try 블록은 에러 감지블록 }catch(FileNotFoundException e){ //catch 블록은 에러 처리블록 } 에러처리의 의무화 자바에서는 에러가 발생할 가능성이 높은 곳에 try와 catch의 사용이 의무적이다. 참고 위의 경우에 설명을 위해서 사용자가 파일의 유무를 확인하는 에러처리 기법을 소개하고 있지만, 자바에서는 파일을 다룰 때 try, catch를 의무적으로 사용해야 한다.

66 7.1.4 에러 처리의 예 FileReader는 의무적으로 FileNotFoundException을 처리해주어야 하지만 예외처리를 하지 않은 경우 import java.io.*; public class ErrorMain{ public static void main(String[] args) { FileReader fr = new FileReader("ErrorMain.java"); } try, catch를 이용해서 FileNotFoundException을 처리한 경우 public class ErrorMain2{ public static void main(String[] args){ try{ //fr을 이용해서 작업 }catch(FileNotFoundException e){ System.out.println(e); 컴파일 타임 에러 에러가 자주 발생하는 곳에는 컴파일러 차원에서 에러처리 루틴을 요구하기 때문에 의무적으로 에러처리 루틴을 넣어야 한다. 컴파일 OK

67 7.1.5 try-catch-finally 다중 catch를 이용한 에러처리 과정 try catch의 원리 try {
String s = null; System.out.println(s.length()); } catch(NullPointerException e1) { //에러 처리 } catch(Exception e2) { //그외의 모든 에러대한 처리 } finally{ // 최종적으로 무조건적으로 처리해야 하는 작업 } error 1 NullPointerException x 발생 2 매개변수가 일치하는 catch 검색 3 이벤트 할당 후 catch 호출 x를 e1에 할당한 후 catch 호출 4 작업처리 finally 작업처리 5 6 try catch의 원리 try 구문 내에서 에러가 발생하면 에러 이벤트가 생성된다. 이 에러 이벤트를 매개변수로 해서 catch 메서드를 호출하는 방식이다. catch 메서드는 내부에서 에러가 발생했을 때 자동으로 호출된다.

68 7.1.6 try-catch-finally의 예 에러처리 루틴이 삽입된 예(실행 시에 에러처리 루틴에 의해 에러가 처리된다.)
public class TryCatchMain{ public static void main(String[] args) { try{ String str = null; System.out.println(str.length()); }catch(NullPointerException e){ System.out.println(e.toString() + " 에러가 발생했습니다"); System.out.println("에러처리 루틴 실행"); } System.out.println("프로그램의 종료"); 에러처리 루틴(try, catch, finally)이 삽입된 예 public class TryCatchFinallyMain{ }finally{ //에러가 나든 나지 않든 무조건 실행되는 블록 System.out.println("finally 구문 실행"); 실행 시에 NullPointerException 에러가 발생하는 예 public class NullErrorMain { public static void main(String[] args) { String str = null; System.out.println(str.length()); //에러발생 System.out.println("프로그램의 종료"); }

69 7.2 예외 처리 실례

70 7.2.1 사용자 필요에 의한 에러처리 사용자가 필요하다고 생각해서 에러처리 구문을 사용하는 경우
public class BasicException { public static void main(String args[]) { try{ int[] ar = new int[]{0, 100, 200, 300}; for(int i=0; i<ar.length+1; i++){ System.out.println("ar["+i+"]=" + ar[i]); } }catch(ArrayIndexOutOfBoundsException e) { System.out.println("e.getMessage(): " + e.getMessage()); System.out.println("e.toString(): " + e.toString()); e.printStackTrace(); return; }finally{ System.out.println("finally: 결국이리로 오는군요"); 고위로 에러유발 : 배열의 범위를 벗어나도록 한다.

71 7.2.2 throw 수동으로 사용자가 직접 에러 이벤트 발생시키기
throw new Exception(); 사용자가 에러 이벤트를 직접 발생시키는 경우를 테스트하는 예 public class UseThrowMain { public static void main(String args[]) { try { throw new Exception("이것이 에러 메시지"); } catch(Exception e) { System.out.println("--Exception 발생구문--"); System.out.println("정보:e.getMessage(): " + e.getMessage()); System.out.println("정보:e.toString(): " + e.toString()); e.printStackTrace(); return; } finally{ System.out.println("finally: 결국이리로 오는군요"); } 1 2

72 NullPointerException 발생 NullPointerException 발생
7.2.3 다단계 catch catch 블록으로 처리하지 못한 경우 import java.io.*; public class LevelErrorMain{ public static void main(String[] args){ try{ FileReader f = new FileReader("LevelErrorMain.java"); String s = null; System.out.println(s.toString()); //NullPointerException 발생 }catch(FileNotFoundException e1){ System.out.println("FileNotFoundException:" + e1); }catch(ArrayIndexOutOfBoundsException e2){ System.out.println("ArrayIndexOutOfBoundsException:" + e2); } Exception으로 모든 에러 처리 public class LevelCatchMain{ FileReader f = new FileReader("LevelCatchMain.java"); }catch(Exception e3){ System.out.println("Exception:" + e3); NullPointerException 발생 catch에 NullPointerException이 없다. NullPointerException 발생 예외의 최상위 클래스인 Excpeiton을 이용해서 NullPointerException 처리

73 FileNotFoundException MalformedURLException
7.2.4 의무적인 에러처리 파일 입출력을 위해 에러처리 루틴을 삽입한 예 public class NeedCatchMain { public static void main(String args[]) { System.out.println("프로그램 시작"); try{ FileReader f = new FileReader("NeedCatchMain.java"); //...파일 입출력 작업 f.close();//파일 닫기 }catch(FileNotFoundException e1){ e1.printStackTrace(); }catch(IOException e2){ e2.printStackTrace(); } System.out.println("프로그램 종료"); URL 객체 생성에 필요한 에러 루틴을 추가한 예 public class NeedNetCatchMain { URL url = new URL(" System.out.println("URL:" + url.toString()); } catch(MalformedURLException e) { e.printStackTrace(); } finally{ System.out.println("finally: 결국이리로 오는군요"); FileNotFoundException IOException IOException을 상속해서 FileNotFoundException이 되기 때문에 IOException으로 모두 처리할 수 있다. 하나의 try문 내에서 여러 개의 catch를 사용할 때 catch의 매개변수명을 다르게 지정해야 한다. MalformedURLException

74 7.2.5 에러처리 미루기 2 1 3 4 에러 처리 미루기의 예(에러 발생)-makeURL()을 사용할 때 에러처리 필요
import java.net.*; public class ShiftError { //throws를 이용해서 에러 처리를 미무는 메서드 public URL makeURL(String urlstr) throws MalformedURLException{ return new URL(urlstr); } public static void main(String args[]) { ShiftError s = new ShiftError(); //에러처리 루틴 필요 URL url = s.makeURL(" 에러 처리 미루기의 예(에러처리 미루기를 직접 구현하는 예) public class ShiftCatch { ShiftCatch p = new ShiftCatch(); try{ //정확한 URL을 입력하지 않았기 때문에 에러발생 URL url = p.makeURL("htttttp:// } catch(MalformedURLException e) { e.printStackTrace(); } finally{ System.out.println("finally: 결국이리로 오는군요"); MalformedURLException 처리를 미룬다. 2 1 의무적으로 MalformedURLException을 처리해야 함 3 makeURL()을 호출할 때 미룬 예외처리를 해주어야 한다. 에러 처리 루틴을 추가한다. 4

75 process()를 호출할 때 무조건 에러 발생
7.2.6 try, catch의 문제점 폭발물 처리 컴퓨터 public class BombComputer { boolean power = false; public void powerOn() { power = true; System.out.println("폭발물 처리 컴퓨터 전원 ON!"); } public void powerOff() { power = false; System.out.println("폭발물 처리 컴퓨터 전원 OFF!"); public void process() throws Exception{ System.out.println("작업처리 1"); System.out.println("작업처리 2"); //무조건 에러가 발생하도록 디자인 throw new Exception("작업처리 3 오류발생 곧 BombComputer를 동작시키는 프로그램(try, catch만 사용한 경우) public class BombComputerErrorMain { public static void main(String args[]) { BombComputer bc = new BombComputer(); try{ bc.powerOn(); bc.process(); bc.powerOff(); }catch(Exception e) { e.printStackTrace(); 폭발 process()를 호출할 때 무조건 에러 발생 문제는 powerOff()를 호출하지 못하고 catch문으로 제어권이 넘어간다는데 있다.

76 7.2.7 try, catch의 해결책 finally를 추가한 예 public class BombComputerMain {
public static void main(String args[]) { BombComputer bc = new BombComputer(); try{ bc.powerOn(); bc.process(); }catch(Exception e) { e.printStackTrace(); }finally { bc.powerOff(); } 폭발 1 처리 2 3 전원차단

77 7.3 문자열

78 7.3.1 문자열 문자열 문자열을 생성하는 방법 I 문자열 생성하는 방법 II 문자열 결합하기
"Hello World!" 문자열 문자열은 문자상수의 집합이다. 자바에서 문자열은 String 클래스의 객체이다. 문자열을 생성하는 방법 I String str1 = "Hello World!"; String str2 = "Hello World!"; 문자열 생성하는 방법 II String ntr1 = new String("Hello World!"); String ntr2 = new String("Hello World!"); 문자열 결합하기 String ntr3 = "Hello" + " " + "World!"; 문자열 내에 에스케이프(Escape) 문자의 사용 String myString = "c:\\javasrc\\chap07"; 상수 풀 영역 str1 str2 ntr1 ntr2 new String("Hello World!"); "Hello World!" new String("Hello World!"); "Hello World!" Heap 영역의 메모리 공간

79 7.3.2 문자열의 주요 메서드 문자열의 길이 문자열 결합 문자열 비교 문자열 검색 문자열의 잘라내기
문자열의 length() 메서드를 이용한다. 문자열 결합 concat() 메서드나 + 연산자를 이용해서 문자열을 결합시킨다. 문자열 비교 equals() 또는 compareTo() 메서드 문자열 비교를 할 수 있다. 문자열 검색 indexOf()는 문자열을 첫 부분부터 검색하여 입력한 문자열을 제일 먼저 만나는 위치를 리턴 lastIndexOf()는 문자열을 마지막 부분부터 검색하여 입력한 문자열을 제일 먼저 만나는 위치를 리턴 문자열의 잘라내기 substring()는 시작 위치와 끝위치를 매개변수로 주면 해단 구간을 추출해서 문자열로 리턴 문자열 교체(자바 5.0) replace()는 문자열 내에 특정 문자열을 모두 교체한다.

80 7.3.3 문자열 메서드 예제(자바 5.0) import static java.lang.System.out;
public class StringMethodMain{ public static void main(String[] args){ String str1 = new String(" String str2 = new String(" System.out.println("str1의 길이:" + str1.length()); System.out.println("str2의 길이:" + str1.length()); System.out.println("str1.equals(str2):" + str1.equals(str2)); System.out.println("str1.compareTo(str2):" + str1.compareTo(str2)); out.println( "str1.concat(str2):" + str1.concat(str2)); out.println( "str1+str2:" + str1+str2); out.println( "str1.indexOf(\"jabook\"):" + str1.indexOf("jabook")); out.println( "str1.indexOf(\"jabook\"):" + str1.lastIndexOf("o")); out.println( "str1.substring(4,10):" + str1.substring(4,10)); out.println( "str1.replace(\"o\", \"t\"):" + str1.replace("o", "t")); } 자바 5.0 static import 기능 사용

81 7.3.4 StringBuffer 클래스 String 클래스는 수정이 불가능한(Immutable) 클래스이다.
String str1 = " String str2 = "jabook."; String str3 = "org"; String str4 = str1 + str2 + str3; //새로운 문자열을 만들어서 리턴한다. StringBuffer 클래스 문자열의 수정이 가능한 클래스 StringBuffer 클래스를 이용해 생성한 객체는 문자열의 추가, 삭제, 수정, 검색 등의 기능을 가지고 있다. StringBuffer 클래스는 수정이 가능한 클래스이다. StringBuffer sb = new StringBuffer(); sb.append(" sb.append("jabook."); sb.append("org"); sb.replace(11, 14, "net"); String str = sb.toString(); System.out.println(str);

82 7.3.5 StringBuffer의 속도 속도 측정 변수 String으로 문자열 만들기의 속도 측정
long startTime = 0L; long elapsedTime = 0L; String으로 문자열 만들기의 속도 측정 String str1 = ""; startTime = System.currentTimeMillis(); for(int i=0; i<50000; i++){ str1 += "H"; //새로운 문자열 생성하기 } elapsedTime = System.currentTimeMillis() - startTime; StringBuffer로 문자열 만들기의 속도 측정 StringBuffer sb = new StringBuffer(); sb.append("H"); //새로운 문자열 추가하기 String의 속도측정 StringBuffer의 속도측정

83 7.3.6 StringBuilder 클래스(자바 5.0)
속도 측정 변수 long startTime = 0L; long elapsedTime = 0L; 동기화가 지원되는 StringBuffer의 속도측정 String str1 = ""; StringBuffer sb = new StringBuffer(); startTime = System.currentTimeMillis(); for(int i=0; i<500000; i++){ sb.append("H"); //새로운 문자열 추가하기 } elapsedTime = System.currentTimeMillis() - startTime; 동기화가 지원되지 않는 StringBuilder의 속도 측정 StringBuilder sbr = new StringBuilder(); sbr.append("H"); //새로운 문자열 추가하기 StringBuffer의 속도 측정 StringBuilder의 속도 측정

84 7.3.7 Formatting 클래스(자바 5.0) 포멧팅(Formatting) 기능 포멧팅의 예 숫자 포멧팅의 예
자바 5.0 이전에는 Formatter 클래스를 이용해서 포멧된 문자열을 생성했지만, 자바 5.0부터는 String.format() 메서드를 이용해서 포멧된 문자열을 만들 수 있다. 포멧팅의 예 String s1 = String.format("%s %d %f %o %h", "Hello", 100, 3.14F, 100, 100); 숫자 포멧팅의 예 String s2 = String.format("%,d", ); 콤마(,)가 포함된 숫자 String s3 = String.format("%.3f", ); 소수점 3째 자리까지 표현 String s4 = String.format("%,.2f ", ); 콤마가 포함되며, 소수점 2째 자리까지 표현

85 7.4 자바 5.0(enum, Varargs)

86 7.4.1 자바의 상수 자바에서 상수를 만드는 방법 클래스에서의 상수 선언 ` 상수의 사용 인터페이스에서의 상수 선언 `
class Top{ public static final double PI = 3.14D; } 클래스에서의 상수 선언 final 키워드를 상수를 선언한다. 선언할 때 단 한번 초기화를 한다. static final로 선언하면 전역적인 상수가 된다. 상수의 사용 double d = 5.0D * Top.PI; 인터페이스에서의 상수 선언 interface ITop{ double PI = 3.14D; //public static final PI = 3.14D; //동일한 표현 인터페이스에서는 멤버변수는 상수만 가능하다. 멤버변수를 선언하면 자동으로 public static final이 된다. ` 자바 5.0 이전에는 final 상수를 이용했다. ` 자바 5.0부터 열거형 상수(enum)를 지원한다.

87 7.4.2 enum(자바 5.0) 열거형 일반적인 데이터 타입의 경우 열거형(enum)의 경우 열거형으로 데이터 타입 만들기
데이터 타입 생성기 열거형 독특한 형태의 데이터 타입 생성기 일반적인 데이터 타입의 경우 데이터 타입을 이용해서 변수를 만든 후 형에 맞는 값을 넣을 수 있다. 열거형(enum)의 경우 열거형으로 만든 데이터 타입을 이용해서 변수를 만드는 것은 일반 데이터 타입과 동일하다. 열거형으로 변수를 만들었다면 이 변수에는 열거형을 선언할 때 명시한 값을 넣을 수 있다. 열거형으로 데이터 타입 만들기 enum SignFlag {black, yellow, green, blue, red}; 열거형을 선언할 때 사용할 값들을 함께 지정할 수 있다. black, yellow, green, blue, red는 열거형 변수에 할당될 수 있는 상수들이다. black, yellow, green, blue, red에는 0,1,2,3,4가 순서대로 자동 할당된다. SignFlag s1; s1 = SignFlag.black; 데이터 타입 SignFlag형 변수를 선언한 후 할당할 수 있는 상수

88 7.4.3 enum(자바 5.0)의 사용 //Type Safe Enumerations
enum PaintStyle{ DASH, DB_DASH, DOT, DB_DOT}; public class EnumSampleMain{ public static void main(String[] args){ PaintStyle ps = PaintStyle.DB_DASH; switch( ps ){ case DASH: System.out.println(" "); break; case DB_DASH: System.out.println("================"); case DOT: System.out.println(" "); case DB_DOT: System.out.println("::::::::::::::::::::"); default: }

89 7.4.4 enum(자바 5.0)의 실체 enum PaintStyle{ DASH, DB_DASH, DOT, DB_DOT};
컴파일러가 다음과 같이 변환한다. final class PaintStyle extends Enum{ public static PaintStyle[] values() { return (PaintStyle[])$VALUES.clone(); } public static PaintStyle valueOf(String s) { return (PaintStyle)Enum.valueOf(PaintStyle, s); private PaintStyle(String s, int i) { super(s, i); public static final PaintStyle DASH; public static final PaintStyle DB_DASH; public static final PaintStyle DOT; public static final PaintStyle DB_DOT; private static final PaintStyle $VALUES[]; static { DASH = new PaintStyle("DASH", 0); DB_DASH = new PaintStyle("DB_DASH", 1); DOT = new PaintStyle("DOT", 2); DB_DOT = new PaintStyle("DB_DOT", 3); $VALUES = (new PaintStyle[] { DASH, DB_DASH, DOT, DB_DOT }); enum도 결국에는 클래스가 된다. .class파일을 .java 파일로 변환하는 방법 c:\javasrc\chap07>jad.exe -s .java PaintStyle.class [참고]역컴파일러 jad.exe는 다운로드 받을 수 있다.

90 7.4.5 Varargs(자바 5.0) public class VarArgsMain {
public static void display(Vector v) { for (Object s : v) { System.out.println("컬렉션형태:" + s); } public static void display(String... strs) { for (String s : strs) { System.out.println("가변인수형태:" + s); public static void main(String[] args) { Vector vec = new Vector (); vec.add("Hello"); vec.add("World"); vec.add("Korea"); VarArgsMain.display(vec); VarArgsMain.display("Hello" , "World", "Korea"); 자바 5.0 이전의 매개변수 가변인수가 없는 자바 5.0 이전에는 메서드의 인수를 컬렉션이나 배열로 처리하였다. 자바 5.0부터는 가변인수(VarArgs)를 갖는 메서드를 작성할때는 "…"를 사용한다. 컴파일러는 가변인수를 다음과 같이 해석한다. public static void display(String as[]) VarArgsMain.display(new String[] {"Hello", "World", "Korea" }); 자바 5.0부터 인수를 가변적으로 조정할 수 있다.

91 8 8 ███████████

92 Powered by http://www.jabook.org
최 영 관 Powered by 3rd Edition 소설같은 자바 since 2001 8장 자바 Thread

93 8.1 스레드 기본

94 8.1.1 프로세스와 스레드 프로세스(Process) 멀티 태스킹(Multi-Tasking)
하나의 프로그램(Program)은 하나의 프로세스(Process)에 해당한다. 멀티 태스킹(Multi-Tasking) 프로세스(Process)의 경우 운영체제에서 자동으로 관리해준다. 운영체제 차원의 프로세스(Process) 관리를 멀티 태스킹(Multitasking)이라고 한다. 프로세스(Process)와 스레드(Thread) 하나의 프로세스(Process) 내에는 여러 개의 스레드(Thread)가 존재할 수 있다. 스레드(Thread)란? 하나의 프로그램 내에서 실행되는 메서드 같은 순간에 두 개의 메서드가 동시에 실행되면 두 개의 스레드가 동작하는 것이다.

95 8.1.2 스레드(Thread)란 시퀀셜(Sequential)하게 동작한다. 스레드의 기본 스레드란? 스레드에서의 중요 사항
한 순간에 하나의 메서드가 동작하는 것을 '시퀀셜하게 동작한다'라고 한다. 스레드의 기본 한 순간에 두 개의 메서드가 동시에 실행되었을 때, 실행된 메서드들을 스레드(Thread)라고 한다. 스레드란? 프로그램에서 독립적으로 실행되는 메서드 스레드에서의 중요 사항 스레드가 어떻게 만드는가? 왜 스레드를 메서드라고 하는가?

96 8.1.3 Runnable로 스레드 만들기 스레드의 실행 순서 Runnable 인터페이스의 구현
Top 클래스 내에 run() 메서드 작성 public class Top{ public void run(){ //스레드의 세부 내용 } 스레드의 메서드를 구현하기 위한 인터페이스 public interface Runnable{ void run(); Runnable 인터페이스의 구현 public class Top implements Runnable{ public void run(){ //...작업 내용 } 진짜 스레드에 Runnable 장착 Top t = new Top(); Thread thd = new Thread(t); 스레드 동작시키기 Topt t = new Top(); //가짜 스레드 Thread thd = new Thread(t); //진짜 스레드 thd.start(); //스레드 동작시키기 main() public void run(){ for(int i=0; i<50; i++) System.out.print(i+"\t"); } System.out.println("프로그램 시작"); Top t = new Top(); Thread thd = new Thread(t); thd.start(); System.out.println("프로그램 종료"); 동시에 작업 진행 스레드의 실행 순서 Runnable run() 스레드 실행 start() start()는 run() 호출

97 8.1.4 Runnable로 두 개의 스레드 만들기 두 개의 스레드 실행 순서 2개의 스레드를 동시에 실행 main()
System.out.println("프로그램 시작"); Top t = new Top(); Thread thd1 = new Thread(t); Thread thd2 = new Thread(t); thd1.start(); thd2.start(); System.out.println("프로그램 종료"); Thread thd2 Thread thd1 Runnable run() Runnable run() public void run(){ for(int i=0; i<50; i++) System.out.print(i+"\t"); } public void run(){ for(int i=0; i<50; i++) System.out.print(i+"\t"); } 동시에 작업 진행 2개의 스레드를 동시에 실행 1. Runnable을 구현하는 객체 만들기 Top t = new Top(); 2. Runnable을 장착한 후 진짜 스레드 만들기 Thread thd1 = new Thread(t); Thread thd2 = new Thread(t); 3. 스레드 동작 시키기 thd1.start(); thd2.start();

98 8.1.5 Thread 상속으로 스레드 만들기 Thread를 상속받는 방법(상속을 통해서 스레드를 만드는 방법)
public class DerivedThread extends Thread{ public void run(){ //...스레드 내의 작업 } 스레드 생성 및 동작시키기 DerivedThread d = new DerivedThread(); d.start(); Thread를 상속하는 두 개의 스레드를 생성한 후 실행시키기(Thread 상속) class DerivedThread extends Thread{ for(int i=0; i<50; i++) System.out.print(i+"\t"); public class DerivedThreadMain2{ public static void main(String[] args){ System.out.println("프로그램 시작"); DerivedThread d1 = new DerivedThread(); DerivedThread d2 = new DerivedThread(); d1.start(); d2.start(); System.out.println("프로그램 종료");

99 8.1.6 Runnable을 사용하는 이유 Frame을 상속했기 때문에 Thread를 상속할 수 없는 경우
class RunFrame extends Frame{ //...작업 } Frame은 상속을 하고 Runnable은 구현을 한 상태 class RunFrame extends Frame implements Runnable{ public void run(){ //...스레드 내의 작업 Runnable을 사용하는 이유 Thread를 상속하기 이전에 다른 클래스를 상속한 경우 Runnable을 이용해서 스레드를 만든다. 창 띄우기와 스레드 동작 시키기 RunFrame r = new RunFrame(); r.setSize(300, 100); r.setVisible(true); Thread t = new Thread(r); t.start();

100 Frame을 상속하면서 Runnable을 구현
import java.awt.*; class RunnableFrame extends Frame implements Runnable { public RunnableFrame() { new Thread(this).start(); } public void run() { int i = 0; System.out.println("스레드 시작!"); while(i<20) { System.out.print(i + "\t"); this.setTitle("스레드 동작중" + i++); try{ Thread.sleep(300); }catch(InterruptedException e){System.out.println(e);} System.out.println("스레드 종료!"); public class RunnableFrameMain{ public static void main(String args[]){ RunnableFrame r = new RunnableFrame(); r.setSize(300, 100); r.setVisible(true); Frame을 상속하면서 Runnable을 구현 생성과 동시에 스레드 시작 Runnable의 run() 메서드 구현 프레임 생성 및 띄우기

101 8.1.8 Frame과 Thread 분리시켜서 구현 class SoloFrame extends Frame{
public SoloFrame(){ SoloThread t = new SoloThread(this); t.start(); } class SoloThread extends Thread{ private Frame f = null; public SoloThread(Frame f){ this.f = f;//SoloFrame의 참조값 챙겨두기 public void run() { int i = 0; System.out.println("스레드 시작!"); while(i<20) { System.out.print(i + "\t"); f.setTitle("스레드 동작중" + i++); try{ this.sleep(300); }catch(InterruptedException e){System.out.println(e);} System.out.println("스레드 종료!");

102 8.2 스레드의 상태와 제어

103 8.2.1 스레드의 상태 스레드(Thread)의 상태 구조도 NotRunnable 상태를 만드는 방법
sleep(시간) -> 시간지나면 wait() -> notify() sleep(시간), wait() Thread 스레드(Thread)의 상태 구조도 Dead NotRunnable Start Runnable Run 스레드의 우선권에 따라서 Run을 차지할 권한이 달라진다. run()의 종료는 스레드의 종료 start()를 호출했을 때 자동진입 wait() wait()하면 NotRunnable 상태가 되지만 notify() 해주어야만 Runnable 상태로 되돌아 올 수 있다. sleep(시간) 일정시간 동안만 NotRunanble 상태가 된다. 시간이 지나면 자동으로 Runnable 상태가 된다. NotRunnable 상태를 만드는 방법 sleep()은 일정 시간 동안만 NotRunnable 상태로 만든다. wait()와 notify()는 수동으로 NotRunnable 상태로 들어가고 나오는 것을 제어할 수 있다.

104 8.2.2 스레드의 우선권 스레드의 우선권 설정 class PriorityThread extends Thread {
public void run() { int i = 0; System.out.print(this.getName()); //스레드의 이름 출력 System.out.println("[우선권:" + this.getPriority() + "] 시작\t"); while(i < 10000) { i = i + 1; try{ this.sleep(1); }catch(Exception e){System.out.println(e);} } System.out.println("[우선권:" + this.getPriority() + "] 종료\t"); public class PriorityThreadMain { public static void main(String[] args) { System.out.println("Main메서드 시작"); for(int i=1; i<=10; i++){ //for(int i=Thread.MIN_PRIORITY; i<=Thread.MAX_PRIORITY; i++){ PriorityThread s = new PriorityThread(); s.setPriority(i); s.start(); System.out.println("Main메서드종료"); Thread 클래스의 스태틱 우선권 상수 public static final int MIN_PRIORITY = 1; public static final int NORM_PRIORITY = 5; public static final int MAX_PRIORITY = 10; 스레드의 우선권 설정

105 8.2.3 NotRunnable 상태 만들기 I 스레드를 NotRunnable 상태로 만드는 방법 sleep()의 사용
wait()와 notify()를 이용해서 대기와 복귀를 제어하는 방법(수동) sleep()의 사용 try{ Thread.sleep(1000); //시간의 단위는 1/1000초 }catch(InterruptedException e){e.printStackTrace();} sleep()을 이용한 작업의 일시 중단 - main()에서의 Thread.sleep() public class NotRunnableMain{ public static void main(String[] args){ long current = System.currentTimeMillis(); System.out.println("프로그램 시작"); Thread.sleep(5000); System.out.println("프로그램 종료"); System.out.println("시간: " + (System.currentTimeMillis()-current)); } NotRunnable 상태 만들기

106 8.2.4 NotRunnable 상태 만들기 II import java.util.*;
class NotRunnableThread extends Thread { public void run() { int i = 0; while(i < 10) { System.out.println(i + "회:" + System.currentTimeMillis() + "\t"); i = i + 1; try{ this.sleep(1000); }catch(Exception e){System.out.println(e);} } public class NotRunnableThreadMain { public static void main(String args[] ) { NotRunnableThread s = new NotRunnableThread(); s.start(); NotRunnable 상태 만들기

107 8.2.5 스레드 죽이기 I while문의 조건을 이용한 스레드의 종료를 테스트하는 예 스레드 테스트하기
class TerminateThread extends Thread { //스레드의 종료를 제어하는 플래그 private boolean flag = false; public void run() { int count = 0; System.out.println(this.getName() +"시작"); while(!flag) { try { //작업 this.sleep(100); } catch(InterruptedException e) { } } System.out.println(this.getName() +"종료"); public void setFlag(boolean flag){ this.flag = flag; 스레드 테스트하기 TerminateThread a = new TerminateThread(); TerminateThread b = new TerminateThread(); TerminateThread c = new TerminateThread(); a.start(); b.start(); c.start(); int i; System.out.print("종료할 스레드를 입력! A, B, C, M?\n"); while(true){ i = System.in.read(); if(i == 'A'){ a.setFlag(true); }else if(i == 'B'){ b.setFlag(true); }else if(i == 'C'){ c.setFlag(true); }else if(i == 'M'){ System.out.println("main종료"); break; } NotRunnable 상태 만들기

108 8.2.6 스레드 죽이기 II 두개의 조건을 이용한 스레드의 종료 두개의 조건을 이용한 스레드의 종료 테스트
class ControlThread extends Thread { //모든 스레드의 종료를 제어하는 플래그 public static boolean all_exit = false; //스레드의 종료를 제어하는 플래그 private boolean flag = false; public void run() { int count = 0; System.out.println(this.getName() +"시작"); while(!flag && !all_exit) { try { //작업 this.sleep(100); } catch(InterruptedException e) { } } System.out.println(this.getName() +"종료"); public void setFlag(boolean flag){ this.flag = flag; 두개의 조건을 이용한 스레드의 종료 테스트 ControlThread a = new ControlThread(); ControlThread b = new ControlThread(); ControlThread c = new ControlThread(); a.start(); b.start(); c.start(); Thread.sleep(100); int i; System.out.print("종료할 스레드를 입력! A, B, C, M?\n"); while(true){ i = System.in.read(); if(i == 'A'){ a.setFlag(true); }else if(i == 'B'){ b.setFlag(true); }else if(i == 'C'){ c.setFlag(true); }else if(i == 'M'){ //모든 스레드를 종료시킨다. ControlThread.all_exit = true; System.out.println("main종료"); break; }

109 8.2.7 스레드의 Resume, Suspend public final void suspend() Deprecated
스레드의 작업을 대기시킨다. public final void resume() Deprecated 스레드의 대기 상태를 해제하고 작업을 재개한다. 스레드의 제어를 위한 도구 setPriority() 스레드가 Run 상태에 들어갈 수 있는 우선권을 결정하게 된다. sleep() 일정 시간 동안 작업을 멈추게 하는 기능이 있다. wait() 스레드를 대기상태(NotRunnable)로 보내게 된다. notify() 대기상태에 있는 스레드를 Runnable 상태로 복귀시켜서 작업을 재개하게 한다.

110 8.3 동기화

111 8.3.1 멀티 스레드와 문제점 스레드의 문제점 동기화 문제가 발생하는 상황 화장실의 동기화 기법(Lock)
스레드들이 여러 개 동시에 작업을 진행하기 때문에 공유자원의 문제가 발생한다. 동기화 문제가 발생하는 상황 A, B, C라는 세 사람이 화장실을 사용하려고 한다. 화장실이 하나밖에 없다. 세사람이 동시에 화장실을 사용하려 한다. 화장실의 동기화 기법(Lock) A가 사용하고 있을 때 문을 잠그고(Lock), 그리고 다 사용하고 나면 다른 사람이 사용하면서 문을 잠그는 기법을 이용하면 된다. 동기화(Synchronization)의 정의 줄서기(번갈아 가면서 순서대로 공유자원 사용하기) 동기화(Synchronization)의 기법 synchronized 블록(자원을 사용할 때 자원에 락(Lock)을 거는 방식) wait()와 notify()

112 8.3.2 동기화가 보장되지 않는 예제 공유자원으로 사용할 클래스 class Data{ public int i = 0; }
class Tom extends Thread{ public void run(){ for (int i=0;i<100000; i++){ NotSyncDataMain.data.i++; } System.out.println("Tom :" + NotSyncDataMain.data.i); class Jane extends Thread{ System.out.println("Jane:" + NotSyncDataMain.data.i); class NotSyncDataMain{ public static Data data = new Data(); public static void main(String[] args){ System.out.println("main 시작"); Tom t = new Tom(); Jane j = new Jane(); t.start(); j.start(); System.out.println("main 종료"); Tom이 번 증가시킨다. 동기화 보장 Jane이 번 증가시킨다. 동기화 보장 공유자원으로 사용할 클래스 class Data{ public int i = 0; } Tom과 Jane이 동시에 수를 증가시킨다. 예상 결과는 , 하지만 동기화가 보장되지 않기 때문에 어느 순간에는 동시에 수를 증가시킨다.

113 8.3.3 동기화 보장 예제 class Tom extends Thread{ public void run(){
for (int i=0;i<100000; i++){ synchronized(SyncDataMain.data){ SyncDataMain.data.i++; } System.out.println("Tom :" + SyncDataMain.data.i); class Jane extends Thread{ System.out.println("Jane:" + SyncDataMain.data.i); class SyncDataMain{ public static Data data = new Data(); public static void main(String[] args){ System.out.println("동기화 보장 예제 시작"); Tom t = new Tom(); Jane j = new Jane(); t.start(); j.start(); System.out.println("동기화 보장 예제 종료"); Tom이 번 증가시킨다. 동기화 보장 Tom이 번 증가시킨다. 동기화 보장 공유자원으로 사용할 클래스 class Data{ public int i = 0; } Tom과 Jane이 동시에 수를 센다. Tom과 Jane은 동기화가 보장된 상태에서 수를 증가시킨다.

114 8.3.4 공유자원의 접근 실전 예제 class Park extends Thread{ public void run(){
NotSyncMain.myBank.saveMoney(3000); System.out.println("saveMoney(3000):" + NotSyncMain.myBank.getMoney()); } class ParkWife extends Thread{ NotSyncMain.myBank.minusMoney(1000); System.out.println("minusMoney(1000):" + public class NotSyncMain{ public static Bank myBank = new Bank(); public static void main(String[] args) throws Exception{ System.out.println("원금:" + myBank.getMoney()); Park p = new Park(); ParkWife w = new ParkWife(); p.start(); try{ Thread.sleep(200); }catch(InterruptedException e){e.printStackTrace();} w.start(); class Bank{ private int money = 10000; //예금 잔액 public int getMoney(){ return this.money; } public void setMoney(int money){ this.money = money; public void saveMoney(int save){ int m = this.getMoney(); try{ Thread.sleep(3000); }catch(InterruptedException e){e.printStackTrace();} this.setMoney(m + save); public void minusMoney(int minus){ int m = this.money; Thread.sleep(200); this.setMoney(m - minus);

115 8.3.5 synchronized class Bank{ private int money = 10000; //예금 잔액
public int getMoney(){ return this.money; } public void setMoney(int money){ this.money = money; public synchronized void saveMoney(int save){ int m = this.getMoney(); try{ Thread.sleep(3000); }catch(InterruptedException e){e.printStackTrace();} this.setMoney(m + save); public void minusMoney(int minus){ synchronized(this){ int m = this.money; Thread.sleep(200); this.setMoney(m - minus); synchronized 메서드 synchronized 블록

116 8.3.6 synchronized의 활용 synchronized 블록 synchronized 블록 class Bank{
//....중간 생략 public void saveMoney(int save){ int m = this.getMoney(); try{ Thread.sleep(3000); }catch(InterruptedException e){e.printStackTrace();} this.setMoney(m + save); } public void minusMoney(int minus){ int m = this.money; Thread.sleep(200); this.setMoney(m - minus); class Park extends Thread{ public void run(){ synchronized(SyncMain2.myBank){ SyncMain2.myBank.saveMoney(3000); System.out.println("saveMoney(3000):" + SyncMain2.myBank.getMoney()); class ParkWife extends Thread{ SyncMain2.myBank.minusMoney(1000); System.out.println("minusMoney(3000):" + SyncMain2.myBank.getMoney()); synchronized 블록 synchronized 블록

117 8.3.7 synchronized의 한계 불필요한 동기화 class VideoShop{
private Vector buffer = new Vector(); public VideoShop(){ buffer.addElement("은하철도999-0"); buffer.addElement("은하철도999-1"); buffer.addElement("은하철도999-2"); buffer.addElement("은하철도999-3"); } public String lendVideo(){ String v = (String)this.buffer.remove(buffer.size()-1); return v; public void returnVideo(String video){ this.buffer.addElement(video); class Person extends Thread{ public void run(){ synchronized(VideoShopMain.vShop){ //5초동안 VideoShopMain.vShop은 락(Lock)에 걸리게 된다. try{ String v = VideoShopMain.vShop.lendVideo(); System.out.println(this.getName() + ":" + v + " 대여"); System.out.println(this.getName() + ":" + v + " 보는중"); this.sleep(5000); System.out.println(this.getName() + ":" + v + " 반납"); VideoShopMain.vShop.returnVideo(v); }catch(InterruptedException e){e.printStackTrace();} System.out.println("프로그램 시작"); Person p1 = new Person(); Person p2 = new Person(); Person p3 = new Person(); Person p4 = new Person(); p1.start(); p2.start(); p3.start(); p4.start(); 불필요한 동기화

118 8.3.8 synchronized의 개선 필요한 곳에 동기화 보장 class VideoShop{
private Vector buffer = new Vector(); public VideoShop(){ buffer.addElement("은하철도999-0"); buffer.addElement("은하철도999-1"); buffer.addElement("은하철도999-2"); buffer.addElement("은하철도999-3"); } public synchronized String lendVideo(){ String v = (String)this.buffer.remove(buffer.size()-1); return v; public synchronized void returnVideo(String video){ this.buffer.addElement(video); class Person extends Thread{ public void run(){ try{ String v = VideoShopMain2.vShop.lendVideo(); System.out.println(this.getName() + ":" + v + " 대여"); System.out.println(this.getName() + ":" + v + " 보는중"); this.sleep(5000); System.out.println(this.getName() + ":" + v + " 반납"); VideoShopMain2.vShop.returnVideo(v); }catch(InterruptedException e){e.printStackTrace();} System.out.println("프로그램 시작"); Person p1 = new Person(); Person p2 = new Person(); Person p3 = new Person(); Person p4 = new Person(); p1.start(); p2.start(); p3.start(); p4.start(); System.out.println("프로그램 종료"); 필요한 곳에 동기화 보장

119 데이터가 없으면 스레드가 요청작업을 포기하고 스레를 끝낸다.
8.3.9 synchronized의 개선의 한계 class VideoShop{ private Vector buffer = new Vector(); public VideoShop(){ buffer.addElement("은하철도999-0"); buffer.addElement("은하철도999-1"); buffer.addElement("은하철도999-2"); buffer.addElement("은하철도999-3"); } public synchronized String lendVideo(){ if(buffer.size()>0){ String v = (String)this.buffer.remove(buffer.size()-1); return v; }else{ return null; public synchronized void returnVideo(String video){ this.buffer.addElement(video); class Person extends Thread{ public void run(){ String v = VideoShopMain3.vShop.lendVideo(); if( v == null){ return; try{ this.sleep(5000); VideoShopMain3.vShop.returnVideo(v); }catch(InterruptedException e){e.printStackTrace();} System.out.println("프로그램 시작"); Person p1 = new Person(); Person p2 = new Person(); Person p3 = new Person(); Person p4 = new Person(); Person p5 = new Person(); p1.start(); p2.start(); p3.start(); p4.start(); p5.start(); System.out.println("프로그램 종료"); 데이터가 없으면 스레드가 요청작업을 포기하고 스레를 끝낸다.

120 9 9 ███████████

121 Powered by http://www.jabook.org
최 영 관 Powered by 3rd Edition 소설같은 자바 since 2001 9장 자바 Stream

122 9.1 스트림

123 9.1.1 스트림의 개요 입출력을 위한 공통된 방법 입출력을 위한 공통된 방법이 없다면? 스트림(Stream)의 정의
다양한 장소에 존재하는 데이터들을 핸들하기 위해서는 입출력 데이터를 처리하는 공통된 방법이 있어야 한다. 입출력을 위한 공통된 방법이 없다면? 각각의 하드웨어 장치를 잘 알고 있다는 가정하에, 각각의 하드웨어 장치에 직접 접근해야 한다. 스트림(Stream)의 정의 자료의 입출력을 도와주는 중간 매개체 입출력 장치 파일 디스크(파일) 키보드, 모니터, 마우스 메모리 네트워크

124 9.1.2 스트림이란? 입출력 장치의 일반적인 특징 스트림의 역할 장치(Device)와 스트림(Stream)
일반적인 입출력 장치는 대부분 데이터를 읽고 기록한다는 특징이 있다. 스트림의 역할 스트림은 데이터를 읽고 쓰기 위한 공통된 방법을 제공 장치(Device)와 스트림(Stream) 장치마다 연결할 수 있는 각각의 스트림이 존재 File 입력 스트림의 연결과 작업 FileInputStream fis = new FileInputStream(파일); //fis.read()를 이용해서 데이터 읽기 File 출력 스트림의 연결과 작업 FileOutputStream fos = new FileOutputStream(파일); //fos.write()를 이용해서 데이터 쓰기 스트림의 내부 동작원리는 몰라도 된다. 사용할 줄만 알면 된다. 사용자는 스트림이 어떻게 장치와 연결되고 작업이 되는지 몰라도 된다. 단지 스트림을 어떻게 생성하며 어떻게 데이터를 읽고 쓰는지만 알면 된다.

125 9.1.3 스트림의 원리 입력 스트림 출력 스트림 스트림의 기본적인 종류 스트림이란? 스트림으로부터 데이터 읽기
스트림이란 빨대다. 스트림으로부터 데이터 읽기 목표지점에 적절한 입력용 스트림을 생성한다. 스트림으로부터 데이터를 읽는다. 스트림으로부터 필요한 만큼 계속해서 데이터를 읽는다. 스트림을 닫는다. 빨대로부터 음료수 마시기 적절한 빨대를 음료수에 꽂는다. 빨대로부터 음료수를 흡입한다. 빨대로부터 마시고 싶은 만큼 계속해서 음료수를 흡입한다. 빨대를 제거한다. 스트림에 데이터 기록하기 목표지점에 적절한 출력용 스트림을 생성한다. 스트림에 데이터를 기록한다. 스트림에 필요한 만큼 계속해서 데이터를 기록한다. 빨대로 음료수 내뱉기 적절한 빨대를 컵에 꽂는다. 빨대로 입안에 있는 음료수를 내뱉는다. 빨대로 내뱉고 싶은 만큼 음료수를 내뱉는다. 입력 스트림 출력 스트림 스트림의 기본적인 종류 입력용 스트림과 출력용 스트림이 있다. 음료수를 내뱉고 다시 마시려면 빨대가 2개 필요하다.

126 9.1.4 스트림의 종류 기본적인 분류 문자 스트림의 패턴 바이트 스트림의 패턴 스트림의 종류 I 스트림의 종류 II
바이트 단위의 read() 메서드 int read() int read(byte cbuf[]) int read(byte cbuf[], int offset, int length) 문자 단위의 read() 메서드 int read(char cbuf[]) int read(char cbuf[], int offset, int length) 바이트 단위의 write() 메서드 int write(int c) int write(byte cbuf[]) int write(byte cbuf[], int offset, int length) 문자 단위의 write() 메서드 int write(char cbuf[]) int write(char int offset, int length) 기본적인 분류 입력 스트림(예: FileInputStream, ObjectInputStream) 출력 스트림(예: FileOutputStream, ObjectOutputStream) 문자 스트림의 패턴 Reader는 입력용 문자 스트림이다. Writer는 출력용 문자 스트림이다. Reader나 Writer가 붙는다면 문자 스트림이다. 바이트 스트림의 패턴 InputStream는 입력용 바이트 스트림이다. OutputStream는 출력용 바이트 스트림이다. 'InputStream'나 'OutputStream'이라는 단어가 붙어 있다면 바이트 스트림이다. PrintStream은 출력용만 존재하기 때문에 약간 특이하다. 스트림의 종류 I 문자 스트림: Reader, Writer(문자 단위로 처리) 바이트 스트림 : InputStream, OutputStream(바이트 단위로 처리) 스트림의 종류 II 입력 스트림 : Reader나 InputStream 출력 스트림 : Writer나 OutputStream 스트림의 규칙 InputStream과 Reader는 읽어 들이는 메서드를 포함하고 있어야 한다. OutputStream과 Writer는 기록하는 메서드를 포함하고 있어야 한다.

127

128 9.1.5 문자 스트림과 바이트 스트림 스트림의 종류와 방향성 나 입력 스트림의 방향
나를 기준으로 데이터가 들어온다면 무조건 입력 스트림 바이트스트림 바이트 그 자체를 핸들하는 스트림 바이트 문자스트림 문자 인코딩 바이트를 문자로 인코딩하여 핸들한다. 인코딩은 기본적으로 스트림이 자동으로 판단한다. 바이트 저장소 문자 출력 스트림의 방향 스트림이 빨대랬지! 나를 기준으로 데이터가 밖으로 나간다면 무조건 출력 스트림

129 9.2 표준 스트림과 File 클래스

130 9.2.1 표준 입출력 System 클래스의 표준 입출력 스트림 멤버 System.out System.in System.err
package java.lang; public class System{ public static PrintStream out; public static InputStream in; public static PrintStream err; //중간 생략 } System.out 표준 출력(모니터) 스트림 System.out.println("에러메시지"); System.in 표준 입력(키보드) 스트림 int d = System.in.read(); //한 바이트 읽어내기 System.err 표준 에러 출력(모니터) 스트림 System.err.println("데이터"); 모니터(표준출력) 키보드(표준입력) 모니터(표준에러출력)

131 9.2.2 System.in import java.io.*; public class SystemInMain3{
public static void main(String[] args) throws IOException{ System.out.print("문자를 입력한 후 엔터를 누르세요? "); int i; while( (i = System.in.read()) != '\n' ){ System.out.println((char)i +":" + i); } 실행결과 c:\javasrc\chap09>javac SystemInMain3.java c:\javasrc\chap09>java SystemInMain3 문자를 입력한 후 엔터를 누르세요? Hello H:72 e:101 l:108 o:111 :13 엔터

132 9.2.3 System.out과 System.err의 차이
Standard Out과 Standard Error의 차이 public class SystemOutErrMain{ public static void main(String[] args){ System.out.println("out : Hello "); System.out.println("out : World"); System.err.println("err : It's eror stream"); System.out.println("out : World!"); } 실행결과 c:\javasrc\chap09>javac SystemOutErrMain.java c:\javasrc\chap09>java SystemOutErrMain out : Hello out : World err : It's eror stream out : World! 리다이렉트시 실행 결과 c:\javasrc\chap09>java SystemOutErrMain > a.txt System.out과 System.err의 일반적 차이 1. out과 err는 별개의 스트림이며, 독립적으로 리다이렉트된다. 2. out은 버퍼링 지원, err는 버퍼링 지원하지 않음(자바는 모두 버퍼링지원) out의 결과는 a.txt로 리다이렉트 되었다. err의 결과는 실행 콘솔창에 바로 출력된다.

133 9.2.4 File 클래스 File f = new File("FileMain.java");
PrintStream out = System.out; out.println("isFile(): " + f.isFile()); //파일인지 아닌지 out.println("isDirectory(): " + f.isDirectory()); //디렉터리인지 아닌지 out.println("isHidden(): " + f.isHidden()); //숨김파일인지 out.println("lastModified(): " + f.lastModified()); //마지막에 수정된 날짜 out.println("canRead(): " + f.canRead()); //읽기 속성을 가진 파일인지 out.println("canWrite(): " + f.canWrite()); //쓰기 속성을 가진 파일인지 out.println("getPath(): " + f.getPath()); //상대 경로 out.println("getAbsolutePath(): "+ f.getAbsolutePath()); //절대 경로 out.println("getName(): " + f.getName()); //디렉터리 또는 파일의 이름 out.println("toURL(): " + f.toURL()); //URL형식의 경로 out.println("exists(): " + f.exists()); //파일이 존재하는지 out.println("length(): " + f.length()); //파일의 길이

134 9.2.5 파일 목록 출력하기 현재 디렉터리와 상위 디렉터리의 경로 출력
File dir1 = new File("."); File dir2 = new File(".."); System.out.println("AbsolutePath");//AbsolutePath System.out.println ("Current dir-> " + dir1.getAbsolutePath()); System.out.println ("Parent dir-> " + dir2.getAbsolutePath()); System.out.println("CanonicalPath");//CanonicalPath System.out.println ("Current dir-> " + dir1.getCanonicalPath()); System.out.println ("Parent dir-> " + dir2.getCanonicalPath()); File dir3 = new File("c:\\");//절대경로지정 System.out.println ("c:\\ -> " + dir3.getAbsolutePath()); File 클래스의 listFiles() - 디렉터리 목록 보기 File f = new File("c:\\"); File[] fs = f.listFiles(); for(int i=0; i<fs.length; i++){ System.out.println(fs[i].getName());

135 9.2.6 디렉터리 생성, 삭제, 파일이름 변경 디렉터리의 생성 디렉터리를 삭제하는 예 파일을 삭제하는 예
File f = new File("디렉터리명"); if(!f.exist()){ f.mkdir(); } 디렉터리를 삭제하는 예 File f = new File("NewFolder"); //디렉터리의 경우 비어 있어야 한다. if(f.exists()){ //디렉터리가 존재하는지 확인 f.delete(); //디렉터리 삭제 파일을 삭제하는 예 File f = new File("파일명"); if(f.exists()){ f.delete(); 파일의 이름을 변경하는 예 File f = new File("원본파일명"); File t = new File("변경할파일명"); f.renameTo(t);

136 9.3 File 스트림

137 9.3.1 파일 입출력의 종류 파일 입출력을 위한 스트림 바이트와 문자 스트림 입력과 출력 스트림 바이트 단위 문자 단위
FileInputStream FileOutputStream 문자 단위 FileReader FileWriter 바이트와 문자 스트림 바이트 단위의 파일을 핸들할 때에는 FileInputStream과 FileOutputStream을 사용한다. 문자 단위의 파일을 핸들하고자 할 때에는 FileReader와 FileWriter를 사용한다. 입력과 출력 스트림 FileInputStream을 생성하는 이유는 파일을 읽기 위해서이다. FileOutputStream을 생성하는 이유는 파일을 기록하기 위해서이다. FileWriter와 FileReader에서도 이것은 마찬가지이다.

138 9.3.2 바이트 단위의 출력 파일 스트림 I 바이트 단위의 File 출력 스트림의 생성
FileOutputStream fos = new FileOutputStream("a.dat"); //fos로 쓰기 작업 fos.close(); //스트림 닫기 바이트 단위의 File 입력 스트림의 생성 FileInputStream fis = new FileInputStream("b.dat"); //fis로 읽기 작업 fis.close(); //스트림 닫기 파일 기록하기 fos.write(72); fos.write(101); fos.write(108); fos.write(111); fos.close(); System.out.println("a.dat 파일 기록완료");

139 9.3.3 바이트 단위의 출력 파일 스트림 II FileOutputStream으로 데이터 기록하기 II
FileOutputStream fos = new FileOutputStream("a1.dat"); byte[] b = new byte[]{72, 101, 108, 108, 111}; fos.write(b); fos.close(); System.out.println("a1.dat 파일 기록완료"); 존재하는 파일의 끝에 덧붙여쓰기 File f = new File("a.dat"); if(f.exists()){ FileOutputStream fos = new FileOutputStream("a.dat", true); System.out.println("a.dat 파일의 끝부분에 데이터 추가하기 완료"); }

140 9.3.4 바이트 단위의 입력 파일 스트림 I FileInputStream을 이용해서 파일 읽기
FileInputStream fis = new FileInputStream("a.dat"); int i; while( (i=fis.read()) != -1 ){ System.out.print((char)i); } fis.close(); FileInputStream의 read(byte[] b) - FileInputStream을 이용한 여러 바이트 읽기 FileInputStream fis = new FileInputStream("FileStreamMain5.java"); int count; byte[] b = new byte[10]; while( (count=fis.read(b)) != -1 ){ for(int i=0; i<count; i++){ System.out.print((char)b[i]);

141 9.3.5 바이트 단위의 입력 파일 스트림 II 1. 파일 사이즈 알아내기 2. 파일 사이즈에 해당하는 배열 만들기
File f = new File("FileStreamMain6.java"); int fileSize = (int)f.length(); System.out.println("파일의 사이즈:" + fileSize); 2. 파일 사이즈에 해당하는 배열 만들기 byte[] b = new byte[fileSize]; 3. 스트림을 이용해서 배열에 데이터 채우기 FileInputStream fis = new FileInputStream("FileStreamMain6.java"); int pos = 0; int size = 10; int temp; while( (size=fis.read(b, pos, size)) > 0 ){ pos += size; temp = b.length - pos; if(temp < 10){ size = temp; } fis.close(); System.out.println("읽은 바이트수:" + pos); 4. 배열을 통째로 파일에 기록하기 FileOutputStream fos = new FileOutputStream("test.txt"); fos.write(b); fos.close();

142 9.3.6 문자 단위의 출력 파일 스트림 FileWriter로 문자 기록하기 FileWriter에 문자열과 문자배열 기록하기
FileWriter fos = new FileWriter("writer.dat"); fos.write(72); fos.write(101); fos.write(108); fos.write(111); fos.close(); FileWriter에 문자열과 문자배열 기록하기 char[] content = new char[]{72, 101, 108, 108, 111}; String str = new String("Hello World!"); FileWriter fos = new FileWriter("writer2.dat"); fos.write(content); //문자배열의 기록 fos.write(str); //문자열의 기록 파일의 마지막 부분에 덧붙여넣기 String str = new String("New Hello World!"); FileWriter fos = new FileWriter("writer2.dat", true); fos.write(str);

143 9.3.7 문자 단위의 입력 파일 스트림 FileReader를 생성하는 방법 FileReader의 read() 계열의 메서드
FileReader fr = new FileReader("파일명"); //fr을 이용해서 문자 읽기 fr.close(); //스트림 닫기 FileReader의 read() 계열의 메서드 int read() int read(char[] cbuf, int offset, int length) FileReader를 이용해서 파일 읽기 import java.io.*; public class FileReaderMain{ public static void main(String[] args) throws IOException{ FileReader fr = new FileReader("writer.dat"); int i; while( (i=fr.read()) != -1 ){ System.out.print((char)i); } fr.close();

144 9.3.8 파일복사 File 스트림 변환 Buffered 스트림 File 스트림을 이용한 파일 복사 예제(한 바이트 단위)
int i, len=0; FileInputStream fis = new FileInputStream(args[0]); FileOutputStream fos = new FileOutputStream(args[1]); long psecond = System.currentTimeMillis(); while((i=fis.read()) != -1) { fos.write(i); len++; } fis.close(); fos.close(); psecond = System.currentTimeMillis() - psecond; Buffered 스트림을 이용한 파일 복사 예제(한 바이트 단위) BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos); while((i=bis.read()) != -1) { bos.write(i); bis.close(); bos.close(); File 스트림 버퍼링지원하지 않음 변환 Buffered 스트림 버퍼링지원

145 9.3.9 RandomAccessFile 임의의 접근(Random Access)
스트림을 사용할 때 순차적으로 read()를 호출하게 되며, reset()을 이용하면 처음부터 다시 읽을 수 있다. 하지만 사용자가 원하는 위치로 이동하거나 되돌릴 수는 없다. 그렇기 때문에 일반적인 스트림에서는 데이터를 랜덤하게 접근할 수 없다. 임의 접근방식으로 파일 접근-RandomAccessFile을 테스트하는 예제 public class RandomAccessFileMain{ public static void main(String[] args) throws IOException{ String s = "I love normal java"; String q = "jabook"; RandomAccessFile rf = new RandomAccessFile("raccess.txt", "rw"); rf.writeBytes(s); rf.close(); RandomAccessFile rf2 = new RandomAccessFile("raccess.txt", "rw"); rf2.seek(7); rf2.writeBytes(q); rf2.close(); RandomAccessFile rf3 = new RandomAccessFile("raccess.txt", "r"); rf3.seek(2); System.out.println(rf3.readLine()); rf3.close(); } 데이터 기록하기 특정 부분에 데이터 기록하기 특정 부분 읽어내기

146 9.4 Memory 스트림

147 ByteArrayInputStream ByteArrayOutputStream
9.4.1 메모리 스트림이란 장소에 따른 파일 스트림의 분류 목표지점에 직접 연결되는 스트림 File에 직접 연결되는 스트림 Memory에 직접 연결되는 스트림 Network에 직접 연결되는 스트림 File 스트림 Memory 스트림 Network 스트림 바이트 배열을 이용한 스트림 문자 배열을 이용한 스트림 문자열을 목표지점으로 하는 스트림 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter StringReader StringWriter

148 ByteArrayOutputStream으로부터 바이트 배열 얻기
바이트 배열을 스트림처럼 다룰 수 있게 도와주는 스트림 바이트 배열 스트림을 테스트하는 예 int i; byte[] arr = {'j', 'a', 'b', 'o', 'o', 'k'}; ByteArrayInputStream in = new ByteArrayInputStream(arr); ByteArrayOutputStream out = new ByteArrayOutputStream(); //ByteArrayInputStream에서 읽고 ByteArrayOutputStream에 기록 while((i = in.read()) != -1) { out.write(i); } byte[] result = out.toByteArray(); for(i=0; i<result.length; i++){ System.out.print((char)result[i]); in.close(); out.close(); ByteArray 스트림 생성 ByteArrayOutputStream으로부터 바이트 배열 얻기

149 9.4.3 CharArray 스트림 CharArray 스트림 CharArray 스트림을 이용한 문자 배열 다루기
문자 배열을 스트림처럼 다룰 수 있게 도와주는 스트림 CharArray 스트림을 이용한 문자 배열 다루기 int ch; char arr[] = {'j','a','b','o','o','k'}; CharArrayReader car = new CharArrayReader(arr); CharArrayWriter caw = new CharArrayWriter(); while((ch=car.read()) != -1) { caw.write(ch); } String str = caw.toString(); System.out.println(str); //jabook 출력 //결과출력 char[] result = caw.toCharArray(); for(int i=0; i<result.length; i++){ System.out.print(result[i]); //jabook 출력 car.close(); caw.close(); CharArray 스트림 생성

150 9.4.4 String 스트림 String 스트림 String 스트림을 사용하는 예
문자열을 스트림 형태로 다룰 수 있게 도와주는 스트림 String 스트림을 사용하는 예 int ch; String str = "Hello!"; StringReader sr = new StringReader(str); StringWriter sw = new StringWriter(); while((ch=sr.read()) != -1) { sw.write(ch); } String result = sw.toString(); System.out.println(result); StringBuffer sb = sw.getBuffer(); System.out.println(sb.toString()); String 스트림 생성

151 9.5 2차 스트림

152 9.5.1 2차 스트림이란 목표지점에 직접 연결되는 스트림
File 스트림 : File에 직접 연결되는 스트림 Memory 스트림 : Memory에 직접 연결되는 스트림 Network 스트림 : Network에 직접 연결되는 스트림 FileInputStream을 BufferedInputStream으로 변환 FileInputStream fis = new FileInputStream("파일명"); BufferedInputStream bis = new BufferedInputStream(fis); FileReader를 BufferedReader로 변환(1차 스트림을 2차 스트림으로 가공) FileReader fr = new FileReader("파일명"); BufferedReader br = new BufferedReader(fr); String str = br.readLine(); 대표적인 1차 스트림들 InputStream, OutputStream FileInputStream, FileOutputStream FileReader, FileWriter ByteArrayInputStream, ByteArrayOutputStream CharArrayReader, CharArrayWriter StringReader, StringWriter 대표적인 2차 스트림들 InputStreamReader, OutputStreamWriter DataInputStream, DataOutputStream BufferedInputStream, BufferedOutputStream BufferedReader, BufferedWriter ObjectInputStream, ObjectOutputStream 변환

153 9.5.2 스트림 변환법 스트림 변환 규칙 I 스트림 변환 규칙 II 문자 스트림끼리의 변환 바이트 스트림끼리의 변환
입력 스트림은 입력 스트림 계열로 변환 출력 스트림은 출력 스트림 계열로 변환 스트림 변환 규칙 II 바이트 스트림은 바이트 스트림 계열로 변환 문자 스트림은 문자 스트림 계열로 변환 문자 스트림끼리의 변환 FileReader -> BufferedReader FileWriter -> BufferedWriter 바이트 스트림끼리의 변환 FileInputStream -> BufferedInputStream FileOutputStream -> BufferedOutputStream 다른 계열끼리의 변환(특수한 경우) 바이트 트림 -> 문자 스트림 바이트 스트림에서 문자 스트림으로 변환 InputStream -> InputStreamReader OutputStream -> OutputStreamWriter

154 9.5.3 문자 스트림으로 변환 바이트스트림 해결책 문자스트림 바이트 스트림을 문자 스트림으로 변환하는 예제
FileInputStream fis = new FileInputStream (args[0]); FileOutputStream fos = new FileOutputStream (args[1]); InputStreamReader isr = new InputStreamReader (fis); OutputStreamWriter osw = new OutputStreamWriter (fos); int i; while((i = isr.read()) != -1){ osw.write (i); } osw.close(); isr.close(); 바이트 스트림으로 문자를 핸들할 때 발생하는 문제를 보여주는 예제 System.out.println("종료하기 위해서는 '끝'을 입력하시오"); System.out.println("출력할 데이터를 입력하시오? "); while((i = System.in.read()) != '끝') { System.out.print((char)i); 문자 스트림을 이용한 문제해결 InputStreamReader isr = new InputStreamReader(System.in); while((i = isr.read()) != '끝') { 문제발생 System.in.read()는 1바이트를 읽는 메서드이며 '끝'이라는 문자는 2바이트이다. 바이트스트림 변환 해결책 문자스트림

155 9.5.4 Buffered 바이트 스트림 File 스트림 변환 Buffered 스트림
int i, len=0; FileInputStream fis = new FileInputStream(args[0]); FileOutputStream fos = new FileOutputStream(args[1]); long psecond = System.currentTimeMillis(); while((i=fis.read()) != -1) { fos.write(i); len++; } fis.close(); fos.close(); psecond = System.currentTimeMillis() - psecond; Buffered 스트림을 이용한 파일 복사 예제(한 바이트 단위) BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos); while((i=bis.read()) != -1) { bos.write(i); bis.close(); bos.close(); 버퍼링지원하지 않음 File 스트림 변환 Buffered 스트림 버퍼링지원

156 9.5.5 Buffered 문자 스트림 Buffered 스트림을 이용한 문자 단위의 파일 복사의 예
int i, len=0; FileReader fr = new FileReader(args[0]); FileWriter fw = new FileWriter(args[1]); BufferedReader br = new BufferedReader(fr); BufferedWriter bw = new BufferedWriter(fw); long psecond = System.currentTimeMillis(); while((i=br.read()) != -1) { bw.write(i); len++; } br.close(); bw.close(); psecond = System.currentTimeMillis() - psecond; BufferedReader를 이용해서 줄 단위로 표준 입력 읽어내기 InputStream in = System.in; InputStreamReader isr = new InputStreamReader(in); BufferedReader br = new BufferedReader(isr); String temp; if((temp=br.readLine())!= null ){ System.out.println(temp); BufferedReader로 파일읽기 FileReader fr = new FileReader(args[0]); BufferedReader br = new BufferedReader(fr); String temp; while((temp=br.readLine())!= null ){ System.out.println(temp); } br.close();

157 9.5.6 Data 스트림 public class DataInputOutputMain{
public static void main(String[] args) throws IOException{ //DataOutputStream을 이용해서 데이터 타입 단위로 데이터 기록하기 FileOutputStream fos = new FileOutputStream("data.dat"); DataOutputStream dos = new DataOutputStream(fos); dos.write(100); //byte형으로 기록하기(1바이트) dos.writeInt(100); //int형으로 기록하기(4바이트) dos.writeFloat(3.14f); //float형으로 기록하기(4바이트) dos.writeChar('A'); //char형으로 기록하기(2바이트) dos.close(); //DataInputStream을 이용해서 데이터 타입 단위로 데이터 읽어오기 FileInputStream fis = new FileInputStream("data.dat"); DataInputStream dis = new DataInputStream(fis); int i = dis.read(); //1바이트 읽기 int i2 = dis.readInt(); //4바이트 읽기 float f = dis.readFloat(); //4바이트를 float형식으로 읽기 char c = dis.readChar(); //2바이트 읽기 dis.close(); System.out.println( i + "," + i2 + "," + f + "," + c); } File 스트림 변환 Data 스트림 데이터 타입 단위로 읽기 및 저장 버퍼링 지원

158 9.5.7 수작업 직렬화 객체의 정보를 파일에 저장한 후 다시 복원하기 MemData 저장을 위한 메서드
public class MemData{ private int id; private long type; private float weight; public void setMemData(int id, long type, float weight){ this.id = id; this.type = type; this.weight = weight; } public String getMemData(){ return id + ", " + type + ", " + weight; public void saveMemData(String filename) throws IOException{ FileWriter fw = new FileWriter(filename); BufferedWriter bw = new BufferedWriter(fw); bw.write("MemData\n"); bw.write(id + "\n"); bw.write(type + "\n"); bw.write(weight + "\n"); bw.close(); public static MemData restoreMemData(String filename) throws IOException{ FileReader fr = new FileReader(filename); BufferedReader br = new BufferedReader(fr); String temp = br.readLine(); MemData memObj = new MemData(); if(temp.equals("MemData")){ int i = Integer.parseInt(br.readLine()); long t = Long.parseLong(br.readLine()); float w = Float.parseFloat(br.readLine()); memObj.setMemData(i, t, w); br.close(); return memObj; 객체의 정보를 파일에 저장한 후 다시 복원하기 MemData m = new MemData(); m.setMemData(100, , F); System.out.println(m.toString() + " : " + m.getMemData()); m.saveMemData("memdata.dat"); //파일에 객체 저장 MemData r = MemData.restoreMemData("memdata.dat"); System.out.println(r.toString() + " : " + r.getMemData()); MemData 저장을 위한 메서드 MemData를 읽어내기 위한 메서드

159 9.5.8 Object 스트림 직렬화(Serialization) 역직렬화(Deserialization)
FileOutputStream fos = new FileOutputStream("serial.dat"); ObjectOutputStream oos = new ObjectOutputStream(fos); SampleData s1 = new SampleData("홍길동", 1004); SampleData s2 = new SampleData("김삿갓", 1005); oos.writeObject(s1); oos.writeObject(s2); oos.close(); System.out.println(s1 + ":" + s1.getSampleData()); System.out.println(s2 + ":" + s2.getSampleData()); 역직렬화(Deserialization) FileInputStream fis = new FileInputStream("serial.dat"); ObjectInputStream ois = new ObjectInputStream(fis); SampleData sd1 = (SampleData)ois.readObject(); SampleData sd2 = (SampleData)ois.readObject(); ois.close(); System.out.println(sd1 + ":" + sd1.getSampleData()); System.out.println(sd2 + ":" + sd2.getSampleData()); 직렬화를 위한 클래스 class SampleData implements Serializable { public String str; public int id; public SampleData(String str, int id) { this.str = str; this.id = id; } public String getSampleData(){ return id + "=" + str; 객체 저장 객체 복원

160 End End ███████████


Download ppt "6 6 ███████████."

Similar presentations


Ads by Google