Object 클래스의 보조 클래스로 모든 메서드가 static이며, 객체 비교나 null 체크에 유용하다.
null 체크에 유용한 메서드로 해당 객체가 null인지 아닌지 검사하여 boolean을 반환하는 isNull(), 그 반대의 기능을 하는 nonNull(), 해당 객체가 null이 아니어야 하는 경우에 사용하는 requireNonNull()이 있다.
Object obj = null;
System.out.println(isNull(obj)); // 객체가 null 이면 true, 아니면 false 반환
System.out.println(nonNull(obj)); // 객체가 null 이면 false, 아니면 true 반환
System.out.println(requireNonNull(obj)); // 객체가 null 일 경우 NullPointerException 발생
이 requireNonNull()이 왜 유용하냐면 기존에 null 확인이 필요할 경우 유효성 검사를 해야했는데 이 메서드를 사용하면 그럴 필요가 없다.
class Identity{
String name;
int age;
public Identity(String name, int age) {
this.name = name;
this.age = age;
}
public Identity() {}
public void setName(String name) {
if(name == null) {
throw new NullPointerException("name is null");
}
this.name = name;
}
}
기존 방법으로는 객체가 null인지 유효성 검사가 필요하다.
class Identity{
String name;
int age;
public Identity(String name, int age) {
this.name = name;
this.age = age;
}
public Identity() {}
public void setName(String name) {
this.name = requireNonNull(name, "name is null");
}
}
requireNonNull()을 사용하면 유효성 검사가 필요없어진다.
- equals(Object a, Object b)
- deepEquals(Object a, Object b)
- compare(Object a, Object b, Comparator c)
- toString(Object obj)
- toString(Object obj, String nullDefault)
- hashCode(Object obj)
Object 클래스에서 등가(같은지 다른지)비교를 위한 equals()는 있지만, 대소(크고 작음)비교를 위한 메서드는 없다.
Objects 클래스에는 등가비교를 위한 equals(), 대소비교를 위한 compare()가 있다.
Objects 클래스의 equals()는 기능적으로는 동일하지만 Object 클래스의 equals()와 다르게 자체적으로 null 검사를 한다.
Identity i = new Identity();
Identity i2 = new Identity();
if(i != null && i.equals(i2)) {
// ....
}
if(Objects.equals(i, i2)) {
// ....
}
따라서 Objects.equals()는 유효성 검사가 필요 없다. 추가로, "Objects." 을 메서드 앞에 추가한 이유는 동일한 메서드명이기 때문에 Objects 클래스를 import 하여도 컴파일러가 구분하지 못하기 때문이다.
두 객체를 비교하여 비교대상보다 작으면 음수, 같으면 0, 크면 양수를 반환하는 compare() 메서드는 Comparator 타입의 매개변수가 필요한데 이 매개변수가 비교의 기준이 된다.
static int compare(Object a, Object b, Comparator c){
////
}
deepEquals()라는 메서드도 있는데 재귀적 비교가 가능해 2차원 배열 객체 간 비교도 가능하다.
equals()를 사용하면 반복문을 사용해서 비교해야 하지만 deepEquals()는 반복문이 필요없다.
int[][] array1 = {{1,2,3,4},{5,6,7,8}};
int[][] array2 = {{1,2,3,4},{5,6,7,8}};
System.out.println(deepEquals(array1,array2)); //true
Object 클래스와 마찬가지로 Objects 클래스에서 toString() 메서드가 있다. 기능은 동일하며 자체적인 null 검사가 가능하다는 차이만 있다.
오버로딩된 동일한 이름의 메서드로 toString(Object a, String nullDefault)가 있는데 기능은 동일하고 추가적으로 객체가 null일 경우 대신 사용한 값인 nullDefault를 지정 가능하다.
hashCode()도 기능은 동일하며 자체적인 null 검사가 가능하다는 차이만 있다.
Math.random()을 사용하여 0 ~ 1.0 사이의 난수를 얻을 수 있는 방법이 있지만 그 외에도 java.util.Random 클래스를 사용하는 방법도 있다.
int num = (int)(Math.random() * 6); //Math.random을 사용한 방법
int num2 = new Random().nextDouble(6); //java.util.Random을 사용한 방법
위의 예시는 0~6 사이의 정수를 난수로 얻으려 할 경우 사용할 수 있는 방법이다.
기능적으로는 동일하나 차이점은 Random 클래스를 사용한 방법은 종자값(seed)를 설정할 수 있다는 점이다.
종자값을 동일하게 입력한 Random 인스턴스들은 같은 순서대로 난수를 반환한다.
- Random() : 현재시간(System.currentTimeMillis())을 종자값으로 이용하는 Random 인스턴스 생성
- Random(long seed) : seed를 종자값으로 하는 Random 인스턴스 생성
다음 예시를 보자.
import java.util.Random;
public class Example {
public static void main(String[] args){
Random rind = new Random(4);
Random rind2 = new Random(4);
for(int i = 0; i < 5; i++) {
System.out.println("rind 의 " + i + " : " + rind.nextInt());
System.out.println("rind2 의 " + i + " : " + rind2.nextInt());
}
}
}
rind 의 0 : -1157023572
rind2 의 0 : -1157023572
rind 의 1 : -396984392
rind2 의 1 : -396984392
rind 의 2 : -349120689
rind2 의 2 : -349120689
rind 의 3 : -812936179
rind2 의 3 : -812936179
rind 의 4 : -349579761
rind2 의 4 : -349579761
난수의 생성 순서도 동일하게 출력된다. 동일한 종자값인 4를 입력하였기 때문에 같은 값을 같은 순서로 반환한 것이다.
매개변수가 없는 Random() 생성자를 사용할 경우 현재 시간을 종자값으로 사용하기 때문에 생성 시마다 다른 값을 반환한다.
Random 클래스의 메서드로 nextInt(), nextDouble(), nextLong() 등이 있는데 next 이후의 타입의 값으로 난수를 반환하는 기능을 한다.
정규식(Regular Expression)을 사용할 수 있는 패키지이다. 정규식은 텍스트 데이터 중에서 원하는 조건과 일치하는 문자열을 찾아내기 위해 사용하는 것으로, 다량의 데이터에서 원하는 데이터 추출에 사용된다.
정규식 자체가 책 한 권 분량이기 때문에 필요할 때마다 찾아서 사용하는 것이 효율적이다.
import java.util.regex.*;
public class Example {
public static void main(String[] args){
String[] data = {"bat","cat","car","circle","crime","america"};
Pattern p = Pattern.compile("c[a-z]*"); //Pattern 인스턴스에 정규식을 입력
for(int i = 0; i < data.length; i++) {
//정규식으로 비교할 대상을 Pattern 클래스의 Matcher matcher를 호출하여 Matcher 인스턴스 m을 얻는다
Matcher m = p.matcher(data[i]);
//Matcher 인스턴스 m과 정규식이 일치할 경우 해당 대상을 출력
if(m.matches()) {
System.out.print(data[i] + ",");
}
}
}
}
data는 추출할 데이터인 String 배열이고 Pattern 클래스의 정적 메서드 compile(String regex)를 사용하여 정규식을 입력한 인스턴스를 생성한다.
정규식과 비교 대상이 될 데이터를 Pattern 클래스의 matcher() 메서드를 사용하여 Matcher 인스턴스를 생성한다.
데이터가 입력된 Matcher 인스턴스 m이 정규식과 일치하는 데이터가 있을 경우 matches()가 true를 반환하여 if문이 실행된다.
가장 기본적인 사용법이고 이 외에도 정규식을 배열에 넣어두고 인덱스를 활용하여 사용하는 방법도 있다.
import java.util.regex.*;
public class Example {
public static void main(String[] args){
String[] data = {"bat","cat","car","circle","crime","america","cm","CP"};
String[] regex = {".*","c[a-z]","c.*","c.*t"};
for(int i = 0; i < regex.length; i++) {
Pattern p = Pattern.compile(regex[i]);
System.out.print(regex[i] + " : ");
for(int j = 0; j < data.length; j++) {
Matcher m = p.matcher(data[j]);
if(m.matches()) {
System.out.print(data[j] + " ");
}
}
System.out.println();
}
}
}
.* : bat cat car circle crime america cm CP
c[a-z] : cm
c.* : cat car circle crime cm
c.*t : cat