유용한 클래스

양성빈·2022년 7월 16일
post-thumbnail

참고
자바의 정석

유용한 클래스

java.util.Objects 클래스

Objects 클래스는 Object 클래스의 보조 클래스이며, Math 클래스처럼 모든 메서드가 static이다. 객체의 비교나 널체크가 유용하다.

대표적으로 isNull()과 nonNull() 메서드가 존재하는데, isNull() 메서드는 해당 객체가 null인지 아닌지 boolean형으로 반환을 하고 nonNull() 메서드는 그 반대의 일을 한다.

static boolean isNull(Object obj)
static boolean nonNull(Object obj)

또한 requireNonNull() 메서드를 많이 사용하는데 이 메서드는 해당 객체가 null이 아니어야 하는 경우에 사용한다. 만일 해당 객체가 null일 경우면 NullPointerException 예외를 발생시킨다.

또한 Object 클래스에는 객체의 등가비교를 위한 equals()만 있고 비교 연산은 할 수가 없었다. 그래서 Objects 클래스에서는 compare() 메서드가 추가가 되었다.

static int compare(Object a, Object b, Comparator c)

compare 메서드는 두 객체를 비교하는데 비교대상이 같으면 0 크면 양수 작으면 음수를 반환한다. 또한 두 객체를 비교하는데 비교기준이 필요하는데 바로 그 역할이 3번째 파라미터 Comparator가 한다.

또한 equals() 메서드와 deepEquals() 메서드가 존재한다.

static boolean equals(Object a, Object b)
static boolean deepEquals(Object a, Object b)

equals() 메서드는 Object 클래스에도 있는데 왜 또 존재하는지 궁금할 것이다. Objects 클래스의 equals() 메서드는 null 체크를 따로 하지 않아도 된다. 왜냐하면 내부적으로 null 체크를 따로 하기 때문이다.
deepEquals() 메서드는 객체를 재귀적으로 비교를 하여 다차원 배열도 비교가 가능하다.

다차원 배열을 쓸려면 equals() 메서드로는 반복문을 통하여 비교를 하여야 하지만 deepEquals() 메서드를 쓰면 따로 반복문 없이 간단히 처리가 가능하다.

static String toString(Object o)
static String toString(Object o, String nullDefault);

toString() 메서드도 equals() 메서드처럼 null 체크를 한다는 것 말고는 Object 클래스의 메서드와 기능적으로 동일하다.

static int hashCode(Object o)
static int hashCode(Object... values)

hashCode() 메서드도 내부적으로 null 체크를 하고난 후, Object 클래스의 hashCode() 메서드를 호출한다. 단, null일 경우 0을 반환한다.

java.util.Random 클래스

난수를 얻고 싶다면 Math.random()을 사용하면 쉽게 얻을 수 있다. 이 외에도 또 다른 방법으로 Random 클래스를 이용하면 난수를 얻을 수 있다. 사실 Math.random()은 내부적으로 Random 클래스를 사용하는것이므로 2가지 방법중에서 편한 방법을 선택하자.

double randNum = Math.random();
double randNum = new Random().nextDouble(); // 위와 동일한 방법

Math.random()과 Random 클래스의 차이점은 종자값을 설정할 수 있다. 종자값이 같은 Random 인스턴스들은 항상 같은 난수를 같은 순서대로 반환한다.

Random클래스의 생성자와 메서드

생성자 Random()은 아래의 코드와 같이 종자값을 System.currentTimeMillis()로 하기 때문에 실행할 때마다 얻는 난수가 달라진다.

public Random() {
	this(System.currentTimeMillis());
}

또하 아래의 표는 Random 클래스의 메서드 목록인데 가볍게 살펴보자.

메서드설명
Random()System.currentTimeMillis()을 종자값으로
이용하는 Random 인스턴스를 생성한다.
Random(long seed)매개변수 seed를 종자값으로 하는 Random 인스턴스를 생성한다.
boolean nextBoolean()boolean 타입의 난수를 반환한다.
void nextBytes(byte[] bytes)bytes 배열에 byte타입의 난수를 채워서 반환한다.
BigInteger 클래스와 같이 사용하면 효과적이다.
double nextDouble()double 타입의 난수를 반환한다. (0.0 <= x < 1.0)
float nextFloat()float 타입의 난수를 반환한다. (0.0 <= x < 1.0)
double nextGaussian()평균은 0.0이고 표준편차는 1.0인 가우시안 분포에 따른
double형의 난수를 반환한다.
int nextInt()int 타입의 난수를 반환한다. (int의 범위)
int nextInt(int n)0 ~ n의 범위에 있는 int값을 반환한다. (n은 범위에 포함하지 않음)
long nextLong()long 타입의 난수를 반환한다. (long의 범위)
void setSeed(long seed)종자값을 주어진 값 (seed)으로 변경한다.

정규식 - java.util.regex 패키지

정규식이란 텍스트 데이터 중에서 원하는 조건과 일치하는 문자열을 찾아내기 위해 사용하는 것으로 미리 정의된 기호와 문자를 이용해서 작성한 문자열을 말한다.
정규식을 이용하면 많은 양의 텍스트 파일중에서 원하는 데이터를 손쉽게 뽑아낼 수도 있고 입력된 데이터가 형식에 맞는지 체크할 수 있다.

정규식에서 Pattern 클래스는 정규식을 정의하는데 사용하고, Matcher는 정규식(패턴)을 데이터와 비교하는 역할을 한다.

정규식 패턴을 표로 정의해두었으니 한번 확인해보자.

정규식 패턴설명
c[a-z]*c로 시작하는 영단어
c[a-z]c로 시작하는 두자리 영단어
c[a-zA-Z]c로 시작하는 두자리 영단어 (a~z 또는 A~Z, 즉 대소문자 구분 안함)
c[a-zA-Z0-9]
c\w
c로 시작하고 숫자와 영어로 조합된 두 글자
.*모든 문자열
c.c로 시작하는 두자리 문자열
c.*c로 시작하는 모든 문자열 (기호포함)
c\.c.와 일치하는 문자열'.'은 패턴작성에 사용되는
문자이므로 escape문자인 \를 사용해야한다.
c\d
c[0-9]
와 숫자로 구성된 모든 문자열
c.*tc로 시작하고 t로 끝나는 모든 문자열
[b|c].*
[bc].*
[^b-c].*
b또는c로 시작하는 문자열
[^b|c].*
[^bc].*
[^b-c].*
b또는c로 시작하지 않는 문자열
.*a.*a를 포함하는 모든 문자열
*: 0또는 그 이상의 문자
.*a.+a를 포함하는 모든 문자열
+: 1또는 그 이상의 문자. '+'는 '*'과 달리 반드시 하나 이상의 문자가 있어야 하므로 a로 끝나는 단어는 포함되지 않는다.
[b|c].{2}b또는c로 시작하는 세자리 문자열. (b또는c 다음에 두자리이므로 모두 세자리)

또한 정규식 패턴중에 그룹을 지을 수 있다. 그룹을 짓는 패턴은 아래와 같다.

정규식 패턴설명
0\\d{1,2}0으로 시작하는 최소 2자리 최대 3자리 숫자 (0포함)
\\d{3,4}최소 3자리 최대 4자리 숫자
\\d{4}4자리 숫자

위의 표대로 패턴을 만들어 그룹핑을 한 뒤, group()을 사용하여 그룹별로 출력 할 수 있다. group() 메서드에 매개변수 없이 호출하면 그룹핑되지 않은 채 분리되고, 매개변수로 1이상의 정수를 작성하면 그룹핑된 순서의 그룹을 출력한다. 단, 실제 그룹수보다 매개변수가 많으면 IndexOutOfBoundException을 호출한다.

java.util.Scanner 클래스

Scanner는 화면, 파일, 문자열과 같은 입력소스로부터 문자데이터를 읽어오는데 도움을 준다. Scanner의 생성자부분은 다음과 같다.

Scanner(String source)
Scanner(File source)
Scanner(InputStream source)
Scanner(Readable source)
Scanner(ReadableByteChannel source)
Scanner(Path source)

이렇게 다양한 생성자가 존재하여 입력 값으로 여러 타입을 받을 수 있다.

또한 Scanner는 정규식 표현을 이용한 라인단위 검색을 지원하며 구분자에도 정규식 표현을 사용할 수 있어서 복잡한 형태의 구분자도 처리 가능하다.

그리고 JDK1.6이후부터 Console 클래스가 추가가 되었는데 이 클래스는 특정 IDE에서 잘 작동되지 않는다는 이슈가 있다.

// 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();

// JDK1.6이후
Console console = System.console();
String input = console.readLine();

java.util.StringTokenizer 클래스

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

StringTokenizer 클래스 외에도 String의 split() 메서드를 사용하거나, Scanner의 useDelimiter()를 사용할 수 있지만, 이 2가지 방법은 정규식을 사용해야 함으로 정규식이 어렵다면, StringTokenizer을 이용하여 간단하게 사용하는 법도 있다.

⚠️ 주의
StringTokenizer는 구분자로 단 하나의 문자밖에 사용하지 못하기 때문에 복잡한 형태라면 정규식 표현을 이용하는것이 좋다.

StringTokenizer의 생성자와 메서드

생성자 / 메서드설명
StringTokenizer(String str, String delim)문자열 str을 지정된 구분자 delim로 나누는 StringTokenizer를 생성한다. (구분자는 토큰으로 간주하지 않는다.)
StringTokenizer(String str, String delim, boolean returnDelims)문자열 str을 지정된 구분자 delim로 나누는 StringTokenizer를 생성한다. returnDelims의 값을 true로 하면 구분자도 토큰으로 간주한다.
int countTokens()전체 토큰의 수를 반환한다.
boolean hasMoreTokens()토큰이 남아 있는지 알려준다.
String nextToken()다음 토큰을 반환한다.

java.math.BigInteger 클래스

정수형으로 표현할 수 있는 값의 한계가 있다. 가장 큰 정수형의 타입인 long으로도 표현 못하는 엄청 큰 정수형은 BigInteger 클래스를 이용한다.

BigInteger 클래스는 내부적으로 int 배열을 사용해서 값을 다룬다. 그래서 long형보다 더 큰 범위를 다룰 수 있지만 성능상 떨어진다. 그럼 BigInteger 클래스의 멤버변수를 살펴보자.

final int signum; // 부호. 1(양수), 0, -1(음수)
final int[] mag; // 값

위의 코드를 보면 BigInteger 역시 String처럼 불변 클래스이고, 모든 정수형이 그렇듯이 2의 보수형태로 표현한다.

BigInteger의 생성

BigInteger를 생성하는 방법은 여러가지가 있는데 문자열로 숫자를 표현하는 것이 일반적이다. 정수형 리터럴로는 표현할 수 있는 값의 한계가 있기 때문이다. 그럼 예시를 살펴보자.

BigInteger val;
val = new BigInteger("12345678901234567890"); // 문자열로 생성
val = new BigInteger("FFFF", 16); // n진수의 문자열로 생성
val = BigInteger.valueOf(1234567890L); // 숫자로 생성

다른 타입으로의 변환

BigInteger를 문자열, 또는 byte 배열로 변환하는 메서드는 다음과 같다.

String toString(); // 문자열로 변환
String toString(int radix); // 지정된 진법의 문자열로 변환
byte[] toByteArray() // byte배열로 변환

BigInteger도 Number 클래스로부터 상속받은 기본형으로 변환하는 메서들을 가지고 있다.

int intValue()
long longValue()
float floatValue()
double doubleValue()

정수형으로 변환하는 메서드 중에서 이름끝에 'Exact'가 붙은 것들은 변환한 결과가 변환한 타입의 범위에 속하지 않으면 ArithmeticException을 발생시킨다.

byte byteValueExact()
int intValueExact()
long longValueExact()

BigInteger의 연산

BigInteger에는 정수형에 사용할 수 있는 모든 연산자와 메서드가 제공한다.

BigInteger add(BigInteger val) // 덧셈
BigInteger substract(BigInteger val) // 뺄셈
BigInteger multiply(BigInteger val) // 곱셈
BigInteger divide(BigInteger val) // 나눗셈
BigInteger remainder(BigInteger val) // 나머지

비트 연산 메서드

워낙 큰 숫자를 다루기 위한 클래스이므로, 성능을 향상시키기 위해 비트단위로 연산을 수행하는 메서드들을 제공한다. and, or, xor, not 비트연산자도 물론 제공한다.

int bitCount() // 2진수로 표현할 때, 1의 개수를 반환
int bitLength() // 2진수로 표현할 때, 값을 표현하는데 필요한 bit 수
boolean testBit(int n) // 우측에서 n+1번째 비트가 1이면 true, 0이면 false
BigInteger setBit(int n) // 우측에서 n+1번째 비트를 1로 변경
BigInteger clearBit(int n) // 우측에서 n+1번째 비트를 0으로 변경
BigInteger flipBit(int n) // 우측에서 n+1번째 비트를 전환 (1 -> 0, 0 -> 1)

java.math.BigDecimal 클래스

double 타입으로 표현할 수 있는 값은 상당히 넓지만 정밀도가 최대 13자리 밖에 되지 않고 실수형의 특성상 오차를 피할 수 없다. BigDecimal은 실수형과 달리 정수를 이용해서 실수를 표현한다.

그리고 BigDecimal은 정수를 저장하는데 BigInteger를 사용한다.

💡 참고
BigInteger처럼 BigDecimal도 불변이다.

private final BigInteger intVal; // 정수 (unscaled value)
private final int scale; // 지수 (scale)
private transient int precision; // 정밀도 - 정수의 자릿수 

BigDecimal의 생성

BigDecimal를 생성하는 방법은 여러가지가 있는데, 문자열로 숫자를 표현하는 것이 일반적이다. 기본형 리터럴로는 표현할 수 있는 값의 한계가 있기 때문이다.

⚠️ 주의
한가지 주의할 점은 double타입의 값을 매개변수로 갖는 생성자를 사용하면 오차가 발생할 수 있다.

다른 타입으로의 변환

BigDecimal을 문자열로 변환하는 메서드는 다음과 같다.

String toPlainString() // 어떤 경우에도 다른 기호없이 숫자로만 표현
String toString() // 필요하면 지수형태로 표현할 수 있음

BigDecimal도 Number 클래스로부터 상속받은 기본형으로 변환하는 메서들을 가지고 있다.

int intValue()
long longValue()
float floatValue()
double doubleValue()

BigDecimal을 정수형으로 변환하는 메서드중에서 이름끝에 'Exact'가 붙은 것들은 변환한 결과가 변환한 타입의 범위에 속하지 않으면 ArithmeticException을 발생시킨다.

byte byteValueExact()
short shortValueExact()
int intValueExact()
long longValueExact()
BigInteger toBigIntegerExact()

BigDecimal의 연산

BigDecimal에는 실수형에 사용할 수 있는 모든 연산자와 수학적인 계산을 쉽게 해주는 메서드들이 정의되어 있다.

BigDecimal add(BigDecimal val) // 덧셈
BigDecimal substract(BigDecimal val) // 뺄셈
BigDecimal multiply(BigDecimal val) // 곱셈
BigDecimal divide(BigDecimal val) // 나눗셈
BigDecimal remainder(BigDecimal val) // 나머지

한 가지 참고할 사항은 연산결과에 따라 연산결과의 정수, 지수, 정밀도가 달라진다.
곱셈에서는 두 피연산자의 scale을 더하고, 나눗셈에서는 뺀다. 덧셈과 뺄셈에서는 둘 중에서 자리수가 높은 쪽으로 맞추기 위해서 두 scale중에서 큰 쪽이 결과가 된다.

반올림 모드 - divide()와 setScale()

다른 연산과 달리 나눗셈을 처리하기 위한 메서드는 다양한 버전이 존재한다. 나눗셈의 결과를 어떻게 반올림 처리할 것인가와 몇 번째 자리에서 반올림할 것인지를 지정할 수 있다. 또한, 나눗셈에서는 오차가 어쩔수 없이 발생한다.

또한 roundingMode가 존재하는데 roundingMode는 반올림 처리방법에 대한 것으로 BigDecimal에 정의된 'ROUND_'로 시작하는 상수들 중에서 선택해서 사용하면 된다. RoundingMode는 이 상수들을 열겨형으로 정의하는것으로 나중에 추가가 되었다.

상수설명
CELING올림
FLOOR내림
UP양수일 때 올림, 음수일 때 내림
DOWN양수일 때 내림, 음수일 때 올림
HALF_UP반올림
HALF_EVEN반올림 (반올림의 자리의 값이 짝수면 HALF_DOWN, 홀수면 HALF_UP)
HALF_DOWN반올림 (6이상 올림, 6미만 버림)
UNNECESSARY나눗셈의 결과가 딱 떨어지는 수가 아니면 ArithmeticException 예외 발생

java.math.MathContext

이 클래스는 반올림 모드와 정밀도를 하나로 묶어 놓은 것일 뿐 별 다른 것은 없다.

⚠️ 주의
divide()에서는 scale이 소수점 이사의 자리수를 의미하는데, MathContext에서는 precision이 정수와 소수점 이하를 모두 포함한 자리수를 의미한다.

scale의 변경

BigDecimal을 10으로 곱하거나 나누는 대신에 scale의 값을 변경함으로 같은 결과를 낼 수 있다.
scale의 값을 변경하려면 setScale()을 사용하면 된다.

profile
모든 것을 즐길줄 아는 개발자입니다!

0개의 댓글