[java] 22. util classes


유용한 클래스 : java.util



이번 시간에는 java.util 패키지에서 자주 쓰이는 클래스에 대해서 알아보겠습니다.

자세히 설명하기보다는 예제 위주로 포스팅을 하겠습니다.



java.util.Objects 클래스



Objects 클래스는 Object 클래스의 보조클래스로 모든 메서드가 static입니다.

객체의 비교나 널 체크에 유용한 클래스입니다.

다음은 객체가 널인지 아닌지 확인해주는 메서드입니다.


static boolean isNull(Object obj) //널이면 true, 아니면 false

static boolean nonNull(Object obj) //널이 아니면 true, 맞으면 false



메서드 requireNonNull()은 해당 객체가 널이 아니어야 하는 경우에 사용합니다.

만약 객체가 널이면, NullPointerException을 발생시킵니다.


//requireNonNull() 사용 전

void setName(String name){
	if(name==null)
		throw new NullPointerException("name must not be null")'
	this.name=name;
}




//requireNonNull() 사용 후

void setName(String name){
	this.name=Objects.requireNonNull(name,"name must not be null");
}



Object 클래스에 정의된 equals()와 toString()이 Objects 클래스에도 정의되어 있는데

다른 점은 내부적으로 널검사를 한다는 것입니다~!


//Object 클래스의 equals()

if(a!=null&&a.equals(b)){ //a가 null인지 반드시 확인
	...
}



//Objects 클래스의 equals()

if(Objects.equals(a,b)){ //매개변수의 값이 null인지 확인할 필요 x
	...
}



또한 다음과 같이 2차원 문자열 배열을 비교할 때 사용되는 deepEquals() 메서드도 존재합니다.


String[][] strarr=new String[][]{ {"aaa","bbb"},{"AAA","BBB"} };

String[][] strarr2=new String[][]{ {"aaa","bbb"},{"AAA","BBB"} };


System.out.println(Objects.equals(strarr,strarr2)); //false(2차원 비교 불가)

System.out.println(Objects.deepEquals(strarr,strarr2)); //true



또 객체의 대소비교를 하는 compare() 메서드도 제공하는데

두 객체를 비교하는데 기준을 제공해주는 Comparator(다음에 배웁니다)에 대한 이해가 필요하므로

일단 이런 메서드가 존재한다는 것만 알아두시길 바랍니다.

다음은 Objects에 대한 예제입니다.


image



java.util.Random 클래스



난수를 얻는 방법을 생각하면 Math.random()이 떠오를 것입니다.

이 외에도 Random 클래스를 사용하면 난수를 얻을 수 있습니다.

사실 Math.random()은 내부적으로 Random클래스의 인스턴스를 생성해서 사용하는 것이므로

둘 중 하나 편한 것을 사용하면 됩니다.

아래의 두 문장은 동등합니다.


double randNum=Math.random();

double randNum=new Random().nextDouble();



예를 들어 1~6 사이의 정수를 난수로 얻고자 할 때는 다음과 같습니다.


int num=(int)(Math.random()*6)+1;

int num2=new Random().nextInt*6+1



Math.random()과 Random의 가장 큰 차이점이라면, 종자값(seed)을 설정할 수 있다는 것입니다.

종자값이 같은 Random 인스턴스들은 항상 같은 난수를 같은 순서대로 반환합니다.

종자값은 난수를 만드는 공식에 사용되는 값으로 같은 공식에 같은 값을 넣으면

같은 결과를 얻는 것처럼 같은 종자값을 넣으면 같은 난수를 얻게됩니다.


<Random 생성자>

Random() : System.currentTimeMillis()(현재 시간)을 seed로 하여 실행할 때마다 얻는 난수가 달라짐

Random(long seed) : 매개변수 seed를 종자값으로 하는 Random 인스턴스를 생성



다음은 Random 클래스에 대한 예제들입니다.


image



image



image



정규식(Regular Expression)-java.util.regex 패키지



정규식이란 텍스트 데이터 중에서 원하는 조건과 일치하는 문자열을 찾아 내기 위해 사용하는 것으로

미리 정의된 기호와 문자를 이용해서 작성한 문자열을 말합니다.

정규식을 이용하면 많은 양의 텍스트 파일 중에서 원하는 데이터를 손쉽게 뽑아낼 수도 있고,

입력된 데이터가 형식에 맞는지 체크할 수도 있습니다.

예를 들면 html 문서에서 전화번호나 이메일 주소만을 따로 추출한다던가,

입력한 비밀번호가 숫자와 영문자의 조합으로 되어 있는지 확인할 수도 있습니다.

자세하게 다루기보다는 자주 쓰이는 예제만 알고 넘어가겠습니다.


image



위의 예제는 data라는 문자열배열에 담긴 문자열 중에서 지정한 정규식과 일치하는 문자열을 출력하는 예제입니다.

Pattern은 정규식을 정의하는데 사용되고 Matcher는 정규식(패턴)을 데이터와 비교하는 역할을 합니다.


1.정규식을 매개변수로 Pattern 클래스의 static 메서드인 Pattern compile(String regex)을 호출하여
Pattern 인스턴스를 얻는다.

Pattern p=Pattern.compile("c[a-z]*");


2.정규식으로 비교할 대상을 매개변수로 Pattern 클래스의 Matcher matcher(CharSequence input)를 호출해서
Matcher 인스턴스를 얻는다.

Matcher m=p.matcher(data[i]);


3.Matcher 인스턴스에 boolean matches()를 호출해서 정규식에 부합하는지 확인한다.

if(m.matches())



자주 쓰일 만한 패턴을 만들어서 테스트하고 그 결과를 정리한 예제입니다.


image



패턴에 대한 설명입니다.


image



다음 예제를 보시죠~!


image



위의 예제처럼 정규식의 일부를 괄호로 나누어 묶어서 그룹화할 수 있습니다.

그룹화된 부분은 하나의 단위로 묶이는 셈이 되어서 한 번 또는 그 이상의 반복을 의미하는 ‘+’ 나 ‘*‘가 뒤에 오면

그룹화된 부분이 적용대상이 됩니다.

그리고 그룹화된 부분은 group(int i)를 이용해서 나누어 얻을 수 있습니다.

위의 예제에서 ‘(0\d{1,2})-(\d{3,4})-(\d{4})’ 은 괄호를 이용해서 정규식을 세 부분으로 나누었는데

예제와 결과에서 알 수 있듯이 매칭되는 문자열에서 첫 번째 그룹은 group(1),

두 번째 그룹은 group(2)와 같이 호출함으로써 얻을 수 있습니다.

group() 또는 group(0)은 그룹으로 매칭된 문자열을 전체를 나누어지지 않은 채로 반환합니다.


0\\d{1,2} : 0으로 시작하는 최소 2자리 최대 3자리 숫자(0포함)

\\d{3,4} : 최소 3자리 최대 4자리의 숫자

\\d{4} : 4자리의 숫자



find()는 주어진 소스 내에서 패턴과 일치하는 부분을 찾아내면 true를 반환하고

찾지 못하면 false를 반환합니다.

find()를 호출해서 패턴과 일치하는 부분을 찾아낸 다음,

다시 find()를 호출하면 이전에 발견한 패턴과 일치하는 부분의 다음부터 다시 패턴매칭을 시작합니다.


Matcher m=p.matcher(source);

while(m.find()){ //find()는 일치하는 패턴이 없으면 false를 반환한다.
	System.out.println(m.group());
}




image



Matcher의 find()로 정규식과 일치하는 부분을 찾으면, 그 위치를 start()와 end()로 알아 낼 수 있고

appendReplacement(StringBuffer sb,String replacement)를 이용해서

원하는 문자열로 치환할 수 있습니다.

치환된 결과는 StringBuffer인 sb에 저장되는데, sb에 저장되는 내용은 다음과 같습니다.


1.문자열 source에서 "broken"을 m.find()로 찾은 후 처음으로 m.appendReplacement(sb,"drunken");가 호출되면
source의 시작부터 "broken"을 찾은 위치까지의 내용에 "drunken"으로 변경해서 저장한다.

-sb에 저장된 내용: "A drunken"


2.m.find()는 첫 번째로 발견된 위치의 끝에서부터 다시 검색을 시작하여
두 번째 "broken"을 찾게 된다.
다시 m.appendReplacement(sb,"drunken"); 가 호출

-sb에 저장된 내용: "A drunken hand works, but not a drunken


3.m.appendTail(sb);이 호출되면 마지막으로 치환된 이후의 부분을 sb에 덧붙인다.

-sb에 저장된 내용: "A drunken hand works, but not a drunken heart."



java.util.Scanner 클래스



Scanner는 화면, 파일, 문자열과 같은 입력소스로부터 문자데이터를 읽어오는데 도움을 줄 목적으로

JDK1.5부터 추가되었습니다.

Scanner가 없던 JDK 1.5 이전에는 자바는 화면으로부터 입력받는 것이 왜 이렇게 불편하냐는

개발자들의 문의가 많았습니다.


//JDK1.5 이전

BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

String input=br.readLine();



//JDK1.5 이후

Scanner s=new Scanner(System.in);
String input=s.nextLine();



다음은 Scanner 클래스를 이용한 예제입니다.


image



위의 예제에서 입력받은 내용을 공백을 구분자로 나눠서 출력할 때

입력받은 라인의 단어는 공백이 여러 개일 수 있으므로 정규식을 “ +”을 사용했습니다.

이 정규식의 의미는 하나 이상의 공백을 의미합니다.


argArr=input.split(" +");



문자열을 구분자로 구분해서 저장하려면 String 클래스의 split 메서드를 이용했는데요~

Scanner 클래스의 useDelimiter 메서드를 사용할 수도 있습니다.


image



java.util.StringTokenizer 클래스



StringTokenizer는 긴 문자열을 지정된 구분자를 기준으로 토큰이라는 여러 개의 문자열로 잘라내는 데 사용됩니다.

예를 들어 “100,200,300,400” 이라는 문자열이 있을 때, ‘,’를 구분자로 잘라내면 “100”,”200”,”300”,”400”이라는

4개의 문자열(토큰)을 얻을 수 있습니다.

StringTokenizer를 이용하는 방법 이외에도 아래와 같이 String의 split(String regex)이나

Scanner의 useDelimiter(String pattern)을 사용할 수 있지만,


String[] result="100,200,300,400".split(",");

Scanner sc2=new Scanner("100,200,300,400").useDelimiter(",");



이 두 가지 방법은 정규식 표현을 사용해야하므로 정규식 표현에 익숙하지 않은 경우

StringTokenizer를 사용하는 것이 간단하면서도 명확한 결과를 얻을 수 있을 것입니다.

정규식 표현이란, 앞서 패턴에서 사용한 .*, [a-zA-Z] 등을 말합니다.

다음은 StringTokenizer의 생성자와 메서드입니다.


image



다음은 StringTokenizer 클래스에 대한 예제입니다.


image



다음은 구분자도 token에 포함시킨 것입니다.


image



위의 예제에서 구분자로 여러 문자를 지정한 것을 볼 수 있는데요~

+-*/=()이 하나의 구분자가 아닌 각각의 문자가 모두 구분자라는 것을 주의해야합니다.

다음은 StringTokren과 이중 반복문을 이용한 예제입니다.


image



다음은 응용 예제입니다.


image



출력결과 입니다.

image




image



java.math.BigInteger 클래스



정수형으로 표현할 수 있는 값의 한계가 있습니다.

가장 큰 정수형 타입인 long으로 표현할 수 있는 값은 10진수로 19자리 정도인데,

더 큰 값을 다뤄야할 때가 있습니다.

이 때 사용되는 클래스가 BigInteger 입니다.

BigInteger는 내부적으로 int 배열을 사용해서 값을 다루기 때문에,

long 타입보다 훨씬 큰 값을 다룰 수 있습니다.

다음은 BigInteger를 이용하여 99!를 출력하는 예제입니다.

long 타입은 20!까지 밖에 계산할 수 없습니다.


image



정수의 큰 값을 다루기에 위해 BigInteger 클래스가 있듯이,

double보다 훨씬 정밀한 실수를 다루기 위해 사용하는 BigDecimal 클래스도 있습니다.

BigDecimal 클래스는 실수형과 달리 정수를 이용해서 실수를 표현합니다.

자세한 설명은 생략하겠습니다~!(자바의 정석 책을 참고하시길 바랍니다~!)