DecimalFormat 클래스

우리의 일상에서 가장 많이 쓰이는 진수, 10진수를 형식화하는 역할을 하는 클래스가 JAVA에서 DecimalFormat이라는 클래스입니다. 이 클래스는 NumberFormat을 상속하고 있는 클래스이죠. 10진수를 다양한 형식에 맞게 출력해줄 수 있습니다. C언어에서는 이미 fprintf 등이 그 역할을 담당하고 있죠. 이제부터 어떻게 사용되는지 배워보도록 하겠습니다.

 

Decimal Pattern 적용

DecimalFormat은 java.text 패키지안에 존재하므로 따로 import를 해야합니다.  DecimalFormat은 문자 '#'과 '0'이 숫자를 나타내는데 쓰이며 쉼표(,), 마침표(.), 대시(-) 등으로 숫자 형식을 나타낼 수 있습니다. 많이 사용패턴은 아래의 표에 정리해놓았습니다.

 

 

Format 설명
0 10진수, 값이 없는 자리는 0으로 채움
# 10진수, 값이 없는 자리는 나타나지 않음
. 소수점을 이하 나타냄
- 음수 부호를 나타냄
, 단위 구분자를 나타냄
E 지수 기호를 나타냄, E 이후 0를 써서 표현(ex E0)
% 퍼센트 기호
' escape문자, 만약 #을 문자로 나타내고 싶다면 '#' 으로 표현
그외 문자 문자로 취급

 

 

DecimalFormat을 사용하는 방법은 생성자를 통해서 형식을 지정해주는 방법이 있습니다. 아래처럼 말이죠.

DecimalFormat format=new DecimalFormat("###,###.#######");

 

또는 applyPattern을 사용하여 패턴을 적용할 수 있습니다.

format.applyPattern("###,###.#######");

 

 

 

중요한것은 우리가 패턴을 적용하고 난 후 형식에 맞는 문자열을 뽑아와야합니다. 이때 format이라는 메소드를 사용하지요. 아래와 같이 사용합니다.

double n = 11223344.5678;
String formattedStr = format.format(n);

 

패턴과 사용예

DecimalFormat의 사용법은 어렵지 않습니다. 주로 사용하는 방식은 패턴을 지정하고 난 후 format으로 지정된 형식을 가진 숫자 형식 문자열을 가져오는 용도가 대부분입니다. 아래의 코드를 통해서 어떻게 출력되는지 확인해보세요.

public static void main(String[] ar){
		
	DecimalFormat format=new DecimalFormat();
		
	String patterns[]= {
			"0",
			"#",
			"0.0",
			"000.000",				//소수점
			"000,000,000.0",
			"000,000,000.000",
			"000,000,000.000000",	//숫자가 나타나지 않는 경우 나머지 빈자리를 0으로 채워줌
			"#,#,#,#.###",			//한글자씩 ,이 붙어서 나옴
			"###,###,###.#",
			"###,###,###.###",
			"###,###,###.######",
			"-###,###,###.######",	//숫자가 나타나지 않는 경우 출력하지 않음
			"###.##E0",				//지수 형식으로 출력
			"my number: ###.##%",	//my number라는 문자열이 합쳐짐
			"'#' ###,###.####",		//escape로 #을 문자화
			"'0' 000,000.00000000",	//escape로 0을 문자화
			"###,###.000000000"	//섞어서도 쓸 수 있음
	};
		
	double number=1234123123.1234;
		
	for(int i=0;i<patterns.length;i++) {
		format.applyPattern(patterns[i]);
		System.out.println("[pattern "+patterns[i]+"] "+format.format(number));
	}
		
}

 

결과

 

 

 

[pattern 0] 1234123123
[pattern #] 1234123123
[pattern 0.0] 1234123123.1
[pattern 000.000] 1234123123.123
[pattern 000,000,000.0] 1,234,123,123.1
[pattern 000,000,000.000] 1,234,123,123.123
[pattern 000,000,000.000000] 1,234,123,123.123400
[pattern #,#,#,#.###] 1,2,3,4,1,2,3,1,2,3.123
[pattern ###,###,###.#] 1,234,123,123.1
[pattern ###,###,###.###] 1,234,123,123.123
[pattern ###,###,###.######] 1,234,123,123.1234
[pattern -###,###,###.######] -1,234,123,123.1234
[pattern ###.##E0] 1.2341E9
[pattern my number: ###.##%] my number: 123412312312.34%
[pattern '#' ###,###.####] # 1,234,123,123.1234
[pattern '0' 000,000.00000000] 0 1,234,123,123.12340000
[pattern ###,###.000000000] 1,234,123,123.123400000

 

이상으로 간단하게 DecimalFormat클래스를 소개했고 사용법을 알아보았습니다. 워낙 어렵지 않은 형식 클래스이고 편리하게 십진수를 표현할 수 있으므로 적어도 #과 0의 차이와 format() 메소드만 알고 있으면 무난히 사용할 수 있겠습니다.

 

 

반응형
블로그 이미지

REAKWON

와나진짜

,

예외(Exception)

프로그램을 실행하다가 보면 어떤 원인때문에 비정상적인 동작을 일으키며 프로그램이 종료되는 상황을 보신적 있으실 겁니다. 이때 우리는 프로그램이 오류가 발생했다고 합니다. 에러의 종류는 우리가 컴파일할때 발생할 수 있는 컴파일 오류와 실행 중 발생되는 런타임 오류 두 종류가 있지요. 컴파일 오류는 우리가 잡기가 쉽지만, 런타임 오류는 잡기가 까다롭습니다. 자바에서는 런타임 오류를 두 종류로 보고 있습니다. 바로 에러(Error)예외(Exception)으로 말이죠. 

에러는 프로그램이 코드로 복구될 수 없는 오류를 의미하고 예외는 프로그래머가 직접 예측하여 막을 수 있는 처리가능한 오류라고 보시면 됩니다. 예를 들어 메모리가 부족한 경우 프로그래머가 직접 제어할 수 없으므로 이런 경우는 메모리 부족(OutOfMemoryError) 에러가 발생하고 함수 호출이 많아 스택이 쌓일 경우에는 StackOverFlowError가 발생할 수 있습니다.

그런데 아래의 코드처럼 어떤 수를 0으로 나눈다면 어떤 상황이 발생할까요?

int a,b;
a=10;
b=0;
		
int c=a/b;
System.out.println(c);

어떤 수를 0으로 나눌수는 없기 때문에 오류를 내보내게 됩니다.

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at aa.Main.main(Main.java:11)

 

하지만 조건문을 통해서 우리는 0으로 못나누게 할 수 있죠. 이처럼 우리가 예측가능한 상황에서 오류를 제어할 수 있는것이 예외입니다.

예외는 Compile시에 발견할 수 있는 예외와 프로그램 실행시에 발생하는 예외 두 종류가 있습니다. Compile시에 발생할 수 있는 예외는 아래의 사진과 같이 Eclipse와 같은 IDE를 쓰신다면 빨간줄로 예외를 처리하라고 욕합니다.

하지만 위에서의 예처럼 Compile시에 발견하지 못하는 에러를 Runtime에러라고 하는데, 이때는 프로그래머가 예측하여 처리해주어야합니다. 

그리고 그런 예외가 발생했을때 어떤 동작을 처리해야하는지를 우리는 예외 처리라고 합니다.

예외 처리

1. try, catch

예외가 발생했을때 우리는 try ... catch ... finally 라는 키워드로 예외를 처리할 수 있거나 메소드를 호출한 곳으로 던질 수 있습니다. 한 가지 중요한 점은 자바에서 모든 예외는 Exception이라는 클래스를 상속받습니다. Exception의 상속 트리를 아래에 간략하게 나타내었습니다.

예외 처리하는 방식은 이렇습니다.

try{
	//예외가 발생될만한 코드
}catch(FileNotFoundException e){	//FileNotFoundException이 발생했다면

}catch(IOException e){ //IOException이 발생했다면

}catch(Exception e){	//Exception이 발생했다면

}finally{	
	///어떤 예외가 발생하던 말던 무조건 실행
}

 

try 블록 : 이 블록에서 예외가 발생할만한 코드가 쓰여집니다. 

catch (예외 종류) 블록 : 이 부분에서 예외가 발생되었을때 처리하는 동작을 명시합니다. catch블록은 여러 개가 있을 수 있습니다. 맨 처음 catch 블록에서 잡히지 않는 예외라면 다음 catch의 예외를 검사합니다. 이때 상속관계에 있는 예외 중 부모가 위의 catch, 그리고 그 자식 예외 클래스가 아래의 catch로 놓일 순 없습니다. 예를 들어 아래와 같이말이죠.

try{
	//.. 중략 ..//
} catch (Exception e){
	//컴파일 오류 발생
} catch (IOException e){

}

Exception 클래스는 모든 예외의 부모이기 때문에 Exception을 IOException보다 위에서 처리할 수는 없다는 뜻입니다. 왜냐면 IOException의 catch블록은 도달할 수 없는 코드이기 때문이죠.

finally 블록 : 여기서는 예외가 발생하건 발생하지 않건 공통으로 수행되어야할 코드가 쓰여집니다.  임시 파일의 삭제 등 뒷정리 코드가 쓰입니다.

이것을 이용해서 우리는 위의 코드를 예외처리할 수 있습니다.

public static void main(String[] ar){
	int a,b;
	a=10;
	b=0;
	try {
		int c=a/b;
		System.out.println(c);	//예외발생으로 실행 불가한 코드
	}catch(ArithmeticException e) {
		System.out.println("ArithmeticException 발생");
		System.out.println("0으로 나눌 수는 없습니다");
		e.printStackTrace();
	}finally {
		System.out.println("finally 실행");
	}
}

 

printStackTrace()라는 메소드는 어느 부분에서 예외가 발생했는지 알려주는 추적로그를 보여줍니다. Exception이 발생했을때 기본 동작이죠. 결과는 아래와 같은 것을 알 수 있습니다.

ArithmeticException 발생
java.lang.ArithmeticException: / by zero
	at aa.Main.main(Main.java:11)		//Main.java에서 11번째 줄에서 발생했다는 printStackTrace
finally 실행

 

2. throws

아까전에 예외를 그냥 던질 수 있다고 했죠? 그 의미가 어떤 의미냐면 예외를 여기서 처리하지 않을테니 나를 불러다가 쓰는 녀석에게 에러 처리를 전가하겠다는 의미이며 코드를 짜는 사람이 이 선언부를 보고 어떤 예외가 발생할 수 있는지도 알게 해줍니다. 어떤 뜻인지 모르겠다구요? 아래의 코드를 통해서 알아보도록 합니다. 

public static void divide(int a,int b) throws ArithmeticException {
	if(b==0) throw new ArithmeticException("0으로 나눌 수는 없다니까?");
	int c=a/b;
	System.out.println(c);
}
public static void main(String[] ar){
	int a=10;
	int b=0;
		
	divide(a,b);
}

 

divide()메소드는 a와 b를 나눈 후에 출력하는 역할을 하는데, 이 나누기 부분에서 우리는 예외가 발생할 수 있음을 알았습니다. 그래서 try, catch로 예외 처리를 해야하지만, divide()를 호출하는 부분에서 처리하기를 원합니다. 왜냐면 divide()를 호출한 곳에서 예외가 발생한 다음의 처리를 divide() 메소드가 정하지 않기 때문입니다. 예를 들어 main메소드에서는 예외가 발생하면 다시 divide()를 호출하거나, 프로그램을 끝내거나, b의 값을 다시 입력받거나 해야하기 때문이고, divide()메소드가 그 결정을 할 수 없다는 의미입니다. 그래서 throws ArithmeticException을 divide를 호출한 main에다가 던지는 것(throw)입니다. 여기서 예외를 던지는 방법은 아래와 같습니다.

(아, 참고로 Exception 생성자 중에서 메시지를 받는 생성자가 있는데, 메시지를 보려면 getMessage()메소드를 이용할 수 있습니다. 아래에서 그 메소드를 사용합니다.)

throw 예외객체
ex) throw new Exception("예외 발생!")

 

예외를 발생시키는 키워드는 throw입니다. 이때 main은 그 예외를 처리하기 위해 try, catch블록을 쓰면 됩니다. 아래처럼 말이죠.

try {
	divide(a,b);
}catch(ArithmeticException e) {
	e.getMessage();
	e.printStackTrace();
}

 

throws 키워드로 처리되어야할 예외가 여러개가 존재한다면 쉼표로 끊어서 예외를 넘겨줄 수 있습니다. 그 결과는 아래와 같습니다.

java.lang.ArithmeticException: 0으로 나눌 수는 없다니까?
	at aa.Main.divide(Main.java:8)
	at aa.Main.main(Main.java:17)

 

이상으로 자바 Exception에 대한 기본 개념과 예외 처리하는 방법을 마치도록 하겠습니다.

반응형
블로그 이미지

REAKWON

와나진짜

,

백준 BOJ(10815)

www.acmicpc.net/problem/10815

 

10815번: 숫자 카드

첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진다. 숫자 카드에 적혀있는 수는 -10,000,000보다 크거나 같고, 10,

www.acmicpc.net

 

숫자 카드중에 가지고 있는 카드가 있다면 1 아니면 0을 출력해주는 그런 문제입니다. 이진탐색만 알면 바로 풀 수 있는 그런 문제입니다.  이진탐색에 관한 내용은 아래를 참고하시기 바랍나다.

reakwon.tistory.com/60

 

[알고리즘] 그림을 통한 이진탐색(Binary Search) 개념과 C 코드구현

이진탐색 배열에서 어떤 원소를 찾을때 그 원소가 있는지 어떻게 찾을 수 있을까요?b가장 간단한 방법은 아무래도 for루프를 실행하면서 하나하씩 일치하는지 검색하는 방법이겠죠? 너무 쉽습니

reakwon.tistory.com

풀이

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std;

int n, m;
int mine[500001];
int binarySearch(int left, int right, int num) {
	if (left == right) return mine[left] == num;
	int mid = (left + right) / 2;
	if (mine[mid] == num) return 1;
	if (mine[mid] > num)
		return binarySearch(left, mid, num);
	return binarySearch(mid + 1, right, num);
}
int main() {
	scanf("%d",&n);
	for (int i = 0; i < n; i++)
		scanf("%d",&mine[i]);
	sort(mine, mine + n);
	scanf("%d",&m);
	for (int i = 0; i < m; i++) {
		int card;
		scanf("%d",&card);
		printf("%d ",binarySearch(0,n-1,card));
	}
	printf("\n");

	return 0;
}

 

탐색을 위해 문제의 입력을 갖고 있는 카드를 우선 정렬합니다. 위 코드가 해답인 코드입니다. 그리고 난 후 이진탐색으로 그 카드의 인덱스가 있는지 확인하는 방법으로 카드가 있는지 아닌지 확인할 수 있습니다.

반응형
블로그 이미지

REAKWON

와나진짜

,

벡터(Vector)

벡터는 ArrayList와 같이 선형적으로 자료를 담을 수 있는 List 컬렉션입니다. ArrayList와는 다르게 동기화 처리를 하기 때문에 ArrayList보다는 속도가 느리다는 단점이 있습니다. 하지만 여러 쓰레드에서 같은 List를 써야할 필요가 있다면 Vector를 사용하시는 것이 동기화 오류를 만들지 않는 방법이겠죠. 

동기화에 대한 예는 맨 아래에 설명하도록 하겠습니다. 지금부터 사용법에 대해서 알아보도록 합시다.

사용법

벡터는 Generic을 사용합니다. 꺽쇠 '<', '>' 에 자료 타입을 지정해주고 수행합니다. 꺽쇠 안에는 원소로 사용할 객체의 클래스를 명시해주면 됩니다. 아래는 Integer 형의 자료를 Vector에서 다룬다는 선언을 보여줍니다.

 

 

Vector<Integer> v=new Vector();

 

1 - 원소 추가와 삭제, 읽기(add, remove, get)

선형으로 자료를 담고 있습니다. 그래서 데이터를 넣으면 차례차례 뒤에 데이터들이 붙어서 쌓이게 됩니다. 특정 위치의 데이터도 삭제할 수 있습니다. 그리고 정수형 index로 원소를 가져올 수 있습니다. 아래가 그 예제를 보여줍니다. 

import java.util.Vector;	//클래스 import
public class Main {
	
	public static void main(String[] ar){
		Vector<Integer> v=new Vector();
		v.add(20);	//0
		v.add(50);	//1
		v.add(70);	//2
		v.add(100);	//3
		
		for(int i=0;i<v.size();i++) {
			System.out.println(i+"번째 원소:"+v.get(i));
		}
		
		System.out.println("\n index 1 원소 삭제");
		v.remove(1);
		
		for(int i=0;i<v.size();i++) {
			System.out.println(i+"번째 원소:"+v.get(i));
		}
	}
}

 

결과

0번째 원소:20
1번째 원소:50
2번째 원소:70
3번째 원소:100

 index 1 원소 삭제
0번째 원소:20
1번째 원소:70
2번째 원소:100

 

예제를 보면 차례차례 20, 50, 70, 100의 데이터를 넣어주고 있습니다. 그리고 for문을 돌면서 출력해주고 있습니다. 차례대로 출력이 되는 것을 확인할 수 있죠? 그런데 index가 1인 50을 삭제하게 되면 삭제된 뒤의 원소들이 전부 앞으로 당겨지게 됩니다.

 

 

remove

만약 size()보다 큰 index를 갖는 원소를 삭제하거나 get()으로 읽어온다면 ArrayIndexOutOfBoundsException이 발생하게 되므로 size() 체크를 항상 해주셔야합니다. 맨 아래 라인에 v.remove(10); 코드를 추가해서 확인해보도록 하세요.

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 10
	at java.base/java.util.Vector.remove(Vector.java:844)
	at aa.Main.main(Main.java:23)

 

원소를 모두 삭제하고 싶다면 clear(), removeAllElements()를 사용하면 모두 지워집니다.

 

2. Vector를 반복할 수 있는 여러 방법

위의 예제는 단순 for문으로 i를 인덱스 삼아서 get()으로 원소를 읽어왔습니다. 이밖에도 여러 방법이 있는데, 그 방법을 소개합니다. 

2-1 forEach 메소드 사용

	Vector<String> v=new Vector();
	v.add("korea");
	v.add("england");
	v.add("rusia");
		
	v.forEach((item)->{
		System.out.println(item);
	});

람다식을 이용해서 순회할 수 있습니다. 함수 안 괄호에는 원소가 들어갑니다. 그 변수명이 item이지요. 그리고 중괄호('{}')에는 동작부를 구현하면 됩니다. 람다식을 몰라도 사용하는 데에는 문제가 없습니다.

2-2 Iterator객체로 순회

	Iterator<String> it=v.iterator();
	while(it.hasNext()) {
		String item=it.next();
		System.out.println(item);
	}

 

사이즈를 체크하지 않으면서 순회하고 싶다면 Iterator클래스로 객체를 만들어 사용하는 방법이 있습니다. Iterator클래스는 Java.util 패키지에 존재하니 import하여 사용해보세요. 순회에 필요한 메소드는 hasNext()와 원소를 가져오는 next()메소드만 알고 있으면 됩니다.

메소드 설명
hasNext() 이 다음에 원소가 있는지 확인합니다. 있으면 true, 없으면 false를 반환하지요. 대체로 while안의 조건문에 사용합니다.
next() 다음 원소를 가져옵니다. 반환되는 객체는 Generic으로 넘겨준 원소의 자료형입니다.

위 코드의 결과는 그 이전의 결과와 같습니다.

 

3. Vector와 Vector를 합치기

 

 

public static void main(String[] ar){
		Vector<String> v1=new Vector();
		v1.add("r");
		v1.add("e");
		v1.add("a");
		v1.add("k");
		
		Vector<String> v2=new Vector();
		v2.add("w");
		v2.add("o");
		v2.add("n");
		
		v1.addAll(v2);
		v1.forEach((item)->{
			System.out.print(item);
		});
		System.out.println();
	}

 

결과

reakwon

 

addAll() 메소드로 벡터와 벡터를 합칠 수 있습니다. 단, 두 벡터는 같은 Generic 형식을 사용해야하고 합칠 벡터 뒤에 그 벡터가 붙습니다. 또는 생성자를 이용해서 객체 생성시에 벡터를 합칠 수 있습니다. 아래와 같은 형식으로 사용할 수 있습니다. 아래 예는 v2에 v1을 객체 생성시에 합칩니다.

Vector<String> v2=new Vector(v1);

 

4. 원소가 존재하는 지 확인

	public static void main(String[] ar){
		Vector<String> v=new Vector();
		v.add("r");	v.add("e");
		v.add("a"); v.add("kwon");
		
		System.out.println(v.contains("r"));
		System.out.println(v.contains("z"));
	}

 

결과

true
false

 

contains() 메소드로 Vector에 원소가 있는지 확인할 수 있습니다. 있으면 true, 없으면 false를 반환합니다.

 

5. Vector 정렬

public static void main(String[] ar){
	Vector<String> strV=new Vector();
	strV.add("reakwon");
	strV.add("hello");
	strV.add("world");
		
	//알파벳 순으로 정렬
	Collections.sort(strV);
	strV.forEach((item)->{
		System.out.println(item);
	});
		
	System.out.println();
		
	Vector<Integer> intV=new Vector();
	intV.add(5);
	intV.add(1);
	intV.add(3);
		
	//오름차순 정렬
	Collections.sort(intV);
	intV.forEach((item)->{
		System.out.println(item);
	});
}

Collections.sort() 메소드를 이용해서 Vector의 데이터를 정렬할 수 있습니다. 기본적으로 숫자는 오름차순, 문자열은 사전순으로 정렬됩니다.

결과

hello
reakwon
world

1
3
5

혹은 내가 만든 객체를 정렬하려면 어떻게할까요? 사람 객체를 키순으로 정렬하고 싶다면, 또는 이름 순으로 정렬, 나이순으로 정렬하고 싶다면 어떻게할까요? 우리가 직접 비교해서 Collections에게 알려줘야합니다. 그것에 대한 설명은 아래의 링크를 참고해주세요. 사용법은 동일합니다.

reakwon.tistory.com/91

 

[자바/JAVA] Collections와 ArrayList를 이용한 객체 정렬

정렬 우리는 정렬에 관해서 배우기도 하였고 구현도 해보았습니다. 그래서 어떻게 정렬이 되는지 알고 있죠. 하지만 실제 프로그래밍하는 상황에서 이 정렬을 직접구현해서 프로그램을 만들지

reakwon.tistory.com

6. Thread-Safe 예

아까 이야기했던 동기화에 대한 부분을 확인해보도록 합시다. 우선 ArrayList로 아래의 코드를 짜면서 관찰해보죠. 

 

 

 

public class Main {
	
	static ArrayList<String> list=new ArrayList();
	public static void main(String[] ar){
		list.add("reakwon");
		list.add("hello");
		list.add("world");
		
		Thread thread=new Thread(new Runnable() {
			@Override
			public void run() {
				list.forEach((item)->{
					//1초마다 원소를 출력
					try {
					Thread.sleep(1000);
					}catch(InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(item);
				});
			}
		});
		
		thread.start();	//thread 시작
		
		//thread가 forEach문을 먼저 수행할 여유를 주기 위해 1초 기다림
		try {
			Thread.sleep(1000);
		}catch(InterruptedException e) {
			e.printStackTrace();
		}
		//thread가 forEach() 하는 중에 원소추가
		list.add("thread-unsafe");
	}
}

 

결과

reakwon
Exception in thread "Thread-0" java.util.ConcurrentModificationException
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1513)
	at aa.Main$1.run(Main.java:19)
	at java.base/java.lang.Thread.run(Thread.java:831)

 

위의 코드는 아주 간단한 코드입니다. thread라는 쓰레드와 메인 스레드는 list라는 ArrayList객체를 공유합니다. thread는 그 list를 forEach()로 1초마다 그 원소를 출력하는 역할을 하고, 메인 스레드는 스레드 생성하고 1초가 지난 다음 list에 원소를 추가하는 상황입니다. 이때 메인스레드가 thread가 forEach()를 수행하는 중에 list에 원소를 집어넣는 접근을 하게 되는데, 이때 두 스레드 동시에 list에 접근하게 됩니다. 그렇게 되면 위처럼 ConcurrentModificationException이 발생하게 되는 상황이 되죠. 어떻게 고칠까요?

ArrayList를 Vector로만 바꿔주면 이 문제는 해결됩니다.

static Vector<String> list=new Vector();

MainThread는 thread가 forEach()를 종료할때까지 Vector객체에 접근할 수 없고, 반대로 메인스레드의 add()가 끝날때까지 thread는 Vector객체에 접근할 수 없습니다.

Vector는 동작마다 동기화를 걸어줍니다. 이런 일은 속도롤 떨어지게 만드는 작업이지만 멀티 스레드 환경에서는 안전한 작업이죠. 그래서 여러 스레드가 있는 환경에서 개발한다면 Vector를 사용하고 단일 스레드 환경에서는 ArrayList를 활용하시면 되겠습니다.

이상으로 Vector에 대한 포스팅을 마칩니다.

 

 

반응형
블로그 이미지

REAKWON

와나진짜

,