java.util
패키지에 포함된 클래스들 중 유용한 것 위주
Object
클래스의 보조 클래스로, 객체의 비교나 null-check에 사용.
모든 메서드가 static
임
매개 변수: Object
obj
반환 타입: boolean
객체가 null
이면 true
, 아니면 false
반환
매개 변수: Object
obj
반환 타입: boolean
isNull
과 정반대
static <T> T requireNonNull(T obj) {
if (obj == null) {
throw new NullPointerException();
}
return obj;
}
객체가 null
이 아니어야하는 경우에 사용. null
이면 NullPointerException
을 던짐.
static <T> T requireNonNull(T obj, String msg) { ... }
static <T> T requireNonNull(T obj, Supplier<String> msgSupplier) { ... }
두번째 매개변수로
String
을 받아 예외메시지를 설정할 수 있게끔 오버로드 되어있음
명시적으로 참조 객체가 null
이면 안된다는 것을 표현할 수 있고, 바로 예외를 던지므로 장애 파악을 빠르게 할 수 있음.
class A {
String name;
}
class B {
A a;
B(A a) {
this.a = Objects.requireNonNull(a);
}
}
장애 파악을 빠르게 할 수 있다는 건 아래 예시로 확인 가능
A a = null;
B b = new B(a); // 인스턴스를 생성하려는 시점에 바로 예외 발생
만약 requireNonNull
을 사용하지 않았다면
class C {
A a;
C(A a) {
this.a = a;
}
getA() {
...
}
}
A a = null;
C c = new C(a); // 인스턴스 생성 시점에 예외 발생이 안됨
c.getA(); // 인스턴스를 활용할 때 예외 발생 (뒤늦은 타이밍)
매개 변수: Object
a, Object
b, Comparator
c
반환 타입: int
두 객체를 대소 비교하여 같으면 0, 크면 양수, 작으면 음수 반환.
매개 변수: Object
a, Object
b
반환 타입: boolean
내부적으로 null
checking을 한 후에 Object
클래스의 equals
호출.
메서드를 사용할 때 따로 비교 대상 객체들의 null
checking을 안해줘도 된다는 장점이 있음.
if (a != null a.equals(b)) {
...
}
// 대신에
if (Objects.equals(a, b)) {
...
}
매개 변수: Object
a, Object
b
반환 타입: boolean
객체를 재귀적으로 비교하여 다차원 배열의 비교에 유용함.
다차원 배열 간 비교에서 equals
에 반복문을 함께 사용하는 대신 Objects.deepEquals
로 한방에 가능.
매개 변수: Object
obj
반환 타입: String
내부적으로 null
checking을 한 후에 Object
클래스의 toString
호출.
두번째 인자로 문자열을 넘기면 객체가 null
인 경우 대신 사용할 수 있음.
매개 변수: Object
obj
반환 타입: int
내부적으로 null
checking을 한 후에 Object
클래스의 hashCode
호출.
Math.random()
과 다르게 종자값(seed)을 설정할 수 있는데, 이는 난수 생성 로직에 영향을 주는 값.
호출되는 메서드의 종자값이 같으면 동일한 난수를 반환함.
종자값은 생성자에 인자로 넘겨서 지정할 수 있고, 이후에는 setSeed
메서드로 바꿀 수 있음
Random r = new Random(); // 기본 생성자는 현재 시간 관련 값을 종자값으로 가짐
Random r = new Random(1); // 1을 종자값으로 하는 Random 인스턴스 생성
nextBytes
, nextInt
, nextLong
, nextFloat
, nextDouble
은 Math.random()
처럼 난수를 생성해줌.
아래 두 문장은 동일함
double random1 = Math.random();
double random2 = new Random().nextDouble();
nextInt
의 경우는 인자로 정수 n을 넘기면 0 ~ n 사이의 난수를 얻을 수 있음
int randomInt = new Random().nextInt(7); // 0 ~ 7 사이의 정수 반환
📌 [참고] Math.random() 으로 min ~ max 범위의 난수 생성하기
Math.random() * (max - min + 1) + min
식 전체를 묶어 int형으로 형변환시켜주면 정수만 뽑힘
활용 예시) 0~9 사이의 난수를 100번 뽑아서 그래프로 나타내기
class RandomExample {
public static void main(String[] args) {
Random r = new Random(); // 새 random 인스턴스 생성
int[] randomNums = new int[100];
int[] counter = new int[10];
for (int i = 0; i < randomNums.length; i++) {
randomNums[i] = r.nextInt(10); // 0 ~ 9 범위의 정수 난수 생성하여 원소로 넣음
}
for (int i = 0; i < randomNums.length; i++) {
counter[randomNums[i]]++; // 100개의 난수의 누적 숫자를 셈
}
for (int i = 0; i < counter.length; i++) {
System.out.println(i + ": " + getGraph('#', counter[i]) + " " + counter[i] + "개"); // getGraph로 각 숫자마다의 누적 개수만큼 그래프를 그림
}
}
public static String getGraph(char c, int length) {
char[] bar = new char[length];
for (int i = 0; i < length; i++) {
bar[i] = c;
}
return new String(bar);
}
}
실행 결과)
0: ###### 6개
1: ############ 12개
2: ############## 14개
3: ####### 7개
4: ########## 10개
5: ######## 8개
6: ######### 9개
7: ############ 12개
8: ############ 12개
9: ########## 10개
정규식: 텍스트 데이터 안에서 원하는 패턴과 일치하는 문자열을 찾아내는 용도
Pattern
: 정규식 패턴을 정의하는 역할
Matcher
: 정의된 패턴을 텍스트 데이터와 비교하는 역할
진행 단계
Pattern
클래스의 static
메서드인 compile
을 호출해 Pattern
인스턴스를 생성
Pattern p = Pattern.compile(패턴);
Pattern
클래스의 matcher
메서드를 호출해 Matcher
인스턴스를 생성
Matcher m = p.matcher(비교할 대상);
Matcher
인스턴스에 matches
메서드를 호출해 정규식 패턴에 부합하는지 검사 (boolean
값 반환)
if (m.matches()) {
...
}
조건식에 자주 쓰이므로 예시를 if문 형식으로 넣었음
정규식 패턴들은 교재 p.507 참고
class RegexExample {
public static void main(String[] args) {
String[] data = {"apple", "banana", "orange", "pineapple", "kiwi", "pear", "grape"};
Vector<String> matchResult = new Vector<String>();
Pattern p = Pattern.compile("p[a-z]*"); // "p로 시작하는 모든 영단어"를 의미하는 패턴
for (String fruit : data) {
Matcher m = p.matcher(fruit);
if (m.matches()) {
matchResult.add(fruit); // 패턴에 부합하는 원소들을 matchResult 배열에 추가
}
}
System.out.println(matchResult); // [pineapple, pear]
}
}
정규식을 괄호로 묶어 grouping을 할 수 있음.
그리고 나서 Matcher
의 메서드인 group()
을 통해 매칭된 문자열을 group 단위로 쪼개서 발췌할 수 있음.
group()
과group(0)
은 매칭된 문자열 전체를 반환하고,group(n)
은 n번째 그룹을 반환함.
class RegexExample2 {
public static void main(String[] args) {
String source = "172-008-295-346";
String pattern = "(0\\d{1,2})-(2\\d{1,2})"; // 0으로 시작하는 2~3자리 숫자, 2로 시작하는 2~3자리 숫자
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(source);
while(m.find()) {
System.out.println(m.group(0)); // (매칭된 문자열 전체) 008-295
System.out.println(m.group(1)); // (매칭된 문자열 중 첫번째 그룹) 008
System.out.println(m.group(2)); // (매칭된 문자열 중 두번째 그룹) 295
System.out.println(m.start() + " ~ " + m.end()); // 3 ~ 9
}
}
}
Matcher
의 메서드인 find()
는 패턴과 일치하는 부분을 찾아내면 true
, 못 찾으면 false
를 반환함.
find()
를 반복적으로 호출하면 이전에 매칭된 부분의 다음부터 매칭을 시작함
start()
이나 end()
로 매칭되는 문자열의 시작 인덱스 또는 (마지막 인덱스 + 1)을 얻을 수 있음
Scanner
는 입력소스(화면, 파일, 문자열)로부터 문자 데이터를 읽어오는 것을 도와주는 역할 (JDK
1.5 부터)
Scanner s = new Scanner(System.in);
String input = s.nextLine();
위 예시는 입력받는 값이 String
타입인 케이스지만, 숫자인 경우엔 nextInt()
, nextFloat()
과 같은 메서드를 사용함
이외에도
java.io
패키지의Console
클래스가 있는데, 화면 입출력만을 전문적으로 담당. (JDK
1.6 부터)Console c = System.console(); String input = c.readLine();
파일로부터 데이터를 읽어오는 경우에는
Scanner s = new Scanner(new File("파일명"));
이렇게 Scanner 생성자에 새 파일 인스턴스를 넘겨주고, 파일이 같은 디렉토리에 있는게 아니라면 파일명 부분에 경로까지 포함해서 입력.
구분자 단위로 끊어서 데이터를 읽을 때는 useDelimiter()
메서드를 사용
Scanner s = new Scanner("123,456,789").useDelimiter(",");
int data1 = s.nextInt();
int data2 = s.nextInt();
int data3 = s.nextInt();
System.out.println(data1); // 123
System.out.println(data2); // 456
System.out.println(data3); // 789
긴 문자열을 지정된 구분자(delimiter)를 기준으로 끊어서 token이라 부르는 문자열 토막을 만드는 역할
String
의 split()
메서드나 Scanner
의 useDelimiter()
메서드와 효과는 같지만, 이 둘은 정규식을 받아서 쓰기 때문에 정규식 없이 단일문자로된 구분자를 사용할 때는 StringTokenizer
를 사용할 수 있음.
생성자의 매개변수(필수)로 String
str, String
delimiter 을 받아오고,
3번째 매개변수(선택)로 boolean
값을 넣을 수 있음 (true
면 구분자도 하나의 토큰으로 간주)
int countTokens
()
전체 토큰의 수를 반환함
boolean hasMoreTokens
()
토큰이 더 남아있는지 알려줌
String nextToken
()
다음 토큰을 반환함
예시)
String source = "1111,2222,3333,4444";
StringTokenizer st = new StringTokenizer(source, ",");
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
실행 결과)
1111
2222
3333
4444
정수형 타입 중 가장 큰 범위를 가진 long
타입은 10진수로 19자리의 수를 표현할 수 있는데, 이보다 더 큰 값을 다뤄야한다면 BigInteger
를 사용함
BigInteger
는 내부적으로 int
배열을 사용하여 값을 다룸.
final int signnum; // 부호를 나타냄. 양수는 1, 음수는 -1
final int[] magnitude; // 값
내부적으로 값을 상수로 저장하므로, String
처럼 한번 값을 정하면 불변임.
일반적으로 문자열로 표현함 (정수형 리터럴은 표현할 수 있는 값의 한계가 있어서)
BigInteger b1 = new BigInteger("2345073244857230480"); // 10진수 문자열로 생성
BigInteger b2 = new BigInteger("FFFFFF", 16); // 16진수 문자열로 생성
BigInteger b3 = BigInteger.valueOf(81949281447L); // valueOf를 통해 정수형 리터럴로 생성
문자열, byte배열로 변환
String toString
()
문자열로 변환
String toString
(int radix)
지정된 진법(radix)의 문자열로 변환
byte toByteArray
()
byte 배열로 변환
기본형 정수, 실수로 변환
int intValue
()
long longValue
()
float floatValue
()
double doubleValue
()
BigInteger
의 값은 불변이므로, 연산 메서드를 통해 반환되는 BigInteger
는 연산 결과값을 담은 새로운 인스턴스임.
BigInteger add
(BigInteger value)
BigInteger subtract
(BigInteger value)
BigInteger multiply
(BigInteger value)
BigInteger divide
(BigInteger value)
BigInteger remainder
(BigInteger value)
value로 나눈 나머지 반환
큰 숫자를 다루다보니 성능 향상을 위해 비트 단위 연산을 수행하는 메서드를 가지고 있음.
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로)
double
타입의 범위를 초과하는 실수형을 다룸.
10진 실수를 2진 실수로 정확히 변환할 수 없는데서 오는 오차를 극복하기 위해, BigDecimal
은 실수를 애초에 2진 정수로 변환하여 다룸.
정수 * 10-scale
정수는 BigInteger
를 사용하여 저장
scale은 0 ~ Integer.MAX_VALUE 사이의 값을 가질 수 있음
private final BigInteger intVal; // 정수
private final int scale; // 지수
private transient int precision; // 정밀도 (정수의 자리수)
BigInteger
와 마찬가지의 이유로, 문자열로 표현함
BigDecimal b1 = new BigDecimal("123.4567890"); // 문자열로 생성
BigDecimal b2 = new BigDecimal(123.456); // double형 리터럴로 생성
BigDecimal b3 = new BigDecimal(123); // int형 리터럴로 생성 (long도 가능)
BigDecimal b4 = BigDecimal.valueOf(123.456); // valueOf(double)로 생성
BigDecimal b5 = BigDecimal.valueOf(123.456); // valueOf(int)로 생성 (long도 가능)
📌 [주의] double형 리터럴로 생성하면, 오차가 발생할 수 있음
String toPlainString
()
기호 없이 무조건 숫자로만 표현
String toString
()
필요에 따라 지수형태로 표현할 수도 있음
BigDecimal value = new BigDecimal("1.0e-10");
System.out.println(value.toPlainString()); // 0.00000000010
System.out.println(value.toString()); // 1.0E-10
기본형 정수, 실수로 변환
int intValue
()
long longValue
()
float floatValue
()
double doubleValue
()
BigDecimal
의 값은 불변이므로, 연산 메서드를 통해 반환되는 BigDecimal
는 연산 결과값을 담은 새로운 인스턴스임.
BigDecimal add
(BigDecimal value)
BigDecimal subtract
(BigDecimal value)
BigDecimal multiply
(BigDecimal value)
BigDecimal divide
(BigDecimal value)
BigDecimal remainder
(BigDecimal value)
value로 나눈 나머지 반환
다른 연산과는 달리 나눗셈에 대해서는 여러 메서드가 오버로드 되어있음.
BigDecimal divide
(BigDecimal value)
BigDecimal divide
(BigDecimal value, int roundingMode)
BigDecimal divide
(BigDecimal value, RoundingMode roundingMode)
BigDecimal divide
(BigDecimal value, int scale, int roundingMode)
BigDecimal divide
(BigDecimal value, int scale, RoundingMode roundingMode)
BigDecimal divide
(BigDecimal value, MathContext mc)
roundingMode
는 BigDecimal
에 정의된 ROUND_
로 시작하는 이름을 가진 멤버 변수(상수)들 중 택 1
RoundingMode
는 연산 결과 처리 방식을 정의한 enum
(아래 표 참고)내의 상수들 중 택 1
enum 값 사용이 권장됨
상수 | 의미 |
---|---|
CEILING | 올림 |
FLOOR | 내림 |
UP | 양수면 올림. 음수면 내림 |
DOWN | 양수면 내림. 음수면 올림 |
HALF_UP | 반올림 (5 이상부터 올림) |
HALF_EVEN | 반올림 (반올림 자리값이 짝수면 HALF_DOWN, 홀수면 HALF_UP) |
HALF_DOWN | 반올림 (6 이상부터 올림) |
UNNECESSARY | 나누어 떨어지므로 반올림 모드 지정이 필요 없다는 의미 |
📌 [주의] 나누어떨어지지 않는 경우(ex. 무한소수)는 반올림모드 지정이 없을 시
ArithmeticException
을 던짐
정밀도와 반올림모드를 하나로 묶어놓은 것
MathContext mc = new MathContext(int precision, RoundingMode roundingMode);
📌 [주의]
divide()
에서의scale
= 소수점 이하의 자리수
MathContext
에서의 정밀도(precision) = 정수와 소수점 이하 모두 포함한 자리수
BigDecimal
값은 10n으로 곱하거나 나누는 대신, scale 값을 변경하면 됨
setScale()
메서드 사용
BigDecimal setScale
(int newScale)
BigDecimal setScale
(int newScale, int roundingMode)
BigDecimal setScale
(int newScale, RoundingMode roundingMode)