이것이 자바다 정리 #9 기본 API 클래스 3
[...]
: ...
중 들어간 하나의 문자를 일치시킨다.[abc]
: a, b, c
중 하나의 문자를 일치시킨다.[^abc]
: a, b, c
를 제외한 하나의 문자를 일치시킨다.[a-zA-Z]
: a~z
, A-Z
중 하나의 문자를 일치시킨다.\d
: 한 개의 숫자, [0-9]
와 동일하다.\s
: 공백\w
: 한개의 알파벳 또는 한 개의 숫자, [a-zA-Z_0-9]
와 동일하다.?
: 없거나 또는 한 개*
: 없거나 또는 한 개 이상+
: 한 개 이상{n}
: 정확히 n개{n,}
: 최소한 n개{n, m}
: n개부터 m개까지()
: 그룹핑'하나의' 문자를 일치시킨다는 말은 정규표현식을 사용하다보면 생각보다 중요한 말이란 것을 알게 된다.
문자열 대치 등을 수행할 때, 각각에 대해 대치하는가, 전체 블록에 대해 대치하는가는 많이 다르게 적용되기 때문에 주의해야 한다.
regexr.com에서 테스트를 해볼 수 있다.
(02|010)-\d{3,4}-\d{4}
(02|010)
: 02
혹은 010
으로 시작하는 문자열이다.-
: -
로 연결된다.\d{3,4}
: 숫자가 3~4
자리 나온다.-
: -
로 연결된다.\d{4}
: 숫자가 4
자리 나온다.\w+@\w+\.\w+(\.\w+)?
\w+
: 문자가 1글자 이상 나온다.@
: @
로 연결된다.\w+
: 문자가 1글자 이상 나온다.\.
: .
으로 연결된다.\w+
: 문자가 1글자 이상 나온다.(\.\w+)?
: 이후에 .
과 1글자 이상의 문자
로 구성되는 내용이 더 있을 수도 있고, 없을 수도 있다.
.
과 같이 원래 정규표현식에서 쓰이는 기호들은\
를 이용해\.
과 같이 작성해주면 escape를 할 수 있다. escape란 정규표현식 기호로서 쓰이는 것이 아님을 알려주는 것이다.
이 외에도 정규표현식에는 flag
라는 개념이 존재한다.
i
: 대소문자를 구분하지 않을 때 사용g
: 놓치지 않고 모든 내용에 대해 매칭시킨다는 의미로 사용m
: 각각의 줄마다 정규표현식을 적용s
: dotall
모드란 것을 활성화하는데, .
이 \n
까지 매칭시키는 모드이다.u
: 모든 유니코드 지원 모드를 활성화한다. 서로게이트 쌍의 올바른 처리를 활성화한다. y
: "sticky" 모드를 활성화한다. 텍스트에서 정확한 위치에서만 검색을 한다. 해당 위치를 자바스크립트에서 lastIndex
라는 프로퍼티로 사용한다. 보통 .matches()
메소드를 통해 문자열이 정규표현식에 맞는지 검증한다.
@Test
public void isEmail() {
String emailValidationRegex = "\\w+@\\w+\\.\\w+(\\.\\w+)?";
boolean matches1 = Pattern.matches(emailValidationRegex, "abc@google.com");
System.out.println("matches1 = " + matches1); // true
boolean matches2 = Pattern.matches(emailValidationRegex, "abc@googlecom");
System.out.println("matches2 = " + matches2); // false
}
위와 같이 사용할 수 있다. 1번째는 올바른 이메일 주소이기 때문에 true
가 나오고, 2번째는 틀린 이메일 주소이기 때문에 false
가 나온다.
실제 자바 코드에서 정규표현식 문자열 내부에 \
를 넣을 때는 기본적으로 단순 이스케이프 문자로 인식하기 때문에 \\
로 넣어야 한다.
배열 조작 기능을 가진 클래스이다. Arrays
클래스는 System
클래스처럼 정적인 메소드만 가지고 있다.
int binarySearch(배열, 찾는 값)
: 전체 배열 항목에서 찾는 값이 있는 인덱스를 반환한다.T copyOf (원본배열, 복사할 길이)
: 원본 배열의 0번 인덱스에서 복사할 길이만큼 복사한 배열을 반환한다. 복사할 길이는 원본 배열의 길이보다 커도 무방하다.T copyOfRange(원본배열, 시작인덱스, 끝인덱스)
: 원본 배열의 시작 인덱스에서 끝 인덱스까지 복사한 배열 리턴.boolean deepEquals(배열, 배열)
: 두 배열의 깊은 비교(중첩 배열의 항목까지 비교)boolean equals(배열, 배열)
: 두 배열의 얕은 비교(중첩 배열 항목은 비교 안함)void fill(배열, 값)
: 전체 배열 항목에 동일한 값을 저장void fill(배열, 시작인덱스, 끝인덱스, 값)
: 시작 인덱스부터 끝 인덱스까지 항목에만 동일한 값을 저장void sort(배열)
: 배열의 전체 항목을 오름차순으로 정렬String toString(배열)
: "[값1, 값2, ...]"
와 같은 문자열 반환public class ArrayTest {
@Test
public void toStringAndSortTest() {
Student student1 = new Student();
student1.setName("김일번");
student1.setNumber(1);
Student student2 = new Student();
student2.setName("김이번");
student2.setNumber(2);
Student student3 = new Student();
student3.setName("김삼번");
student3.setNumber(3);
Student[] students = {student2, student3, student1};
System.out.println("students = " + Arrays.toString(students));
}
}
위와 같이 코드를 짜면 Arrays.toString()
시에 단순히 메모리 주소 값이 나오지 않고, 내용이 나온다.
sort 메소드를 사용하려면, Comparable<T>
인터페이스를 상속하고, .compareTo()
메소드를 구현해야 한다.
@Override
public int compareTo(Student student) {
return this.number < student.number ? -1 : 0;
// Integer.compare(this.number, student.number); 와 같다
// 반대로 정렬하고 싶다면 부호만 반대로 바꾸어주면 된다.
}
위는 직접 작성한 .compareTo()
메소드이다. 단순히 primitive 값을 비교할 거면 래퍼 클래스에서 compare()
메소드를 가져오는 방법도 좋다. Integer.compare()
와 같은 메소드가 있다.
-1
일 때 값이 바뀐다.compareTo()
메소드의 부등호를 반대로 바꾸면 정렬 순서도 반대가 된다.-1
만 반환하면, 순서가 거꾸로 된다.자바의 primitive 타입들 (byte, char, short, int, long, float, double, boolean) 을 감싸는 클래스를 말한다. 이러한 클래스로 만든 객체를 Wrapper 객체라고 한다.
Wrapper 객체라고 불리는 이유는 기본 타입 값을 내부에 두고 포장하기 때문이다. 포장 객체 내부에 있는 기본 타입의 값은 외부에서 변경할 수 없다. 내부의 값을 변경하고 싶다면 새로운 포장 객체를 만들어야 한다. (불변성)
각 primitive 타입의 이름 앞글자를 대문자로 바꾸면 Wrapper 클래스를 볼 수 있다.
.valueOf()
메소드를 이용하는 방법도 있다..타입Value()
메소드를 호출하면 된다.Integer a = 100;
.add()
로 리터럴 값을 추가하면 자동으로 박싱된다.List<Integer> numbers = new ArrayList<Integer>();
numbers.add(100);
Integer a = new Integer(100);
int b = a;
자동 박싱, 자동 언박싱은 자바 5부터 추가되었기 때문에, 그 이하의 버전을 쓸 때는 직접 박싱과 언박싱을 해주어야 한다.
.parse타입명()
형태의 메소드를 이용하면, 문자열을 primitive 타입으로 변환시킬 수 있다.int number = Integer.parseInt("100");
==
비교를 하여 동등한지 알 수 없다. .equals()
를 이용하자.Math 클래스는 System 클래스와 비슷하게 모두 정적 메소드만 갖고 있다. Math 클래스는 이름처럼 유용한 수학 메소드를 갖고 있다.
T abs(T)
: 절대값을 반환한다.ceil()
: 올림값을 반환한다.floor()
: 버림값을 반환한다.max()
: 최대값을 반환한다.min()
: 최소값을 반환한다.random()
: 0~1사이 랜덤값을 반환한다.rint()
: 가까운 정수의 실수값을 반환한다.5.3
이면 5.0
이 나오고, 5.7
이면 6.0
이 나온다.round()
: 반올림 값을 반환한다.Random(long seed)
를 이용하면 된다.nextBoolean()
: boolean
타입의 난수를 반환한다.nextDouble()
: double
타입의 난수를 반환한다.nextInt()
: int
타입의 난수를 반환한다.nextInt(int n)
: 0~n
까지 범위의 정수 난수를 반환한다.java.util
패키지에 포함되어 있다.Date now = new Date()
SimpleDateFormat
클래스를 이용하여 원하는 형식의 문자열 날짜를 얻을 수 있다.Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String stringifiedDate = sdf.format(now); // 2020-05-06 19:46
Calendar.getInstance()
의 정적 메소드를 이용하여 운영체제에 설정되어 있는 시간대를 기준으로 한 Calendar
의 하위 객체를 얻는다.java.util.TimeZone
객체를 얻어서 Calendar.getInstance()
메소드의 매개값으로 넘기면 된다.TimeZone.getAvailableIDs()
메소드로 이용 가능한 시간대의 문자열을 얻을 수 있다.TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
Calendar now = Calendar.getInstance(timeZone);
java.text
패키지에 포함되어 있다.DecimalFormat
을 제공한다.SimpleDateFormat
을 제공한다.MessageFormat
을 제공한다.DecimalFormat df = new DecimalFormat("#,###.0");
String result = df.format(1234567.89);
0
: 10진수 (빈자리는 0으로 채운다.)00.0
-> 01.5
#
: 10진수 (빈자리는 채우지 않는다.)###.###
-> 1.5
.
: 소수점-
: 음수 기호+#.0
-> +123.1
-#.0
-> -123.1
,
: 단위 구분#,###.0
-> 1,234,567.8
E
: 지수 문자0.0E0
-> 1.2E6
;
: 양수와 음수의 패턴을 모두 기술할 경우 패턴 구분자+#,### ; -#,###
-> +1,234,568
(양수), -1,234,568
(음수)안에서 패턴 문자가 특수한 의미를 가지는데, 그 의미만 알면 자신이 원하는대로 날짜에 대한 .toString()
을 작성할 수 있다고 생각하면 된다.
y
: 년M
: 월d
: 일D
: 월 구분이 없는 일(1~365)E
: 요일a
: 오전/오후w
: 년의 몇 번째 주W
: 월의 몇 번째 주H
: 시(0~23)h
: 시(1~12)K
: 시(0~11)k
: 시(1~24)m
: 분s
: 초S
: 밀리세컨드import java.text.MessageFormat;
public class Main {
public static void main(String[] args) {
String id = "kim ddol ddol";
String name = "kim ddol";
String tel = "010-1111-1111";
String message = "회원 ID: {0} \n회원 이름: {1} \n회원 전화: {2}";
String result = MessageFormat.format(message, id, name, tel);
System.out.println("result = " + result);
}
}
위와 같은 코드를 입력하면 순서에 맞게 들어간다.
들어갈 인자를 배열로 입력해도 무관하다.
{ id, name, tel }
궁금해서 자료조사를 해봤는데
MessageFormat.format()
의 퍼포먼스는 매우 저조하다.
보기엔 아름다울 수 있으나String
타입을+
로concat
하는 것보다 느리다.
StringBuilder
가 가장 빠르다.String
이 그 다음
Date
와 Calendar
클래스를 이용해서 날짜와 시간 정보를 얻었다.java.util
패키지에 없고, 별도로 java.time
패키지에 하위 패키지로 제공된다.날짜와 시간을 나타내는 핵심 API인 LocalDate
, LocalTime
, LocalDateTime
, ZonedDateTime
을 포함한다. 이 클래스들은 ISO-8601
에 정의된 달력 시스템에 기초한다.
ISO-8601에 정의된 달력 시스템 이외에 다른 달력 시스템이 필요할 때 사용할 수 있는 API들이 포함되어 있다.
날짜와 시간을 파싱하고 포맷하는 API들이 포함되어 있다.
날짜와 시간을 연산하기 위한 보조 API들이 포함되어 있다.
타임존을 지원하는 API들이 포함되어 있다.
로컬 날짜 클래스로 날짜 정보만 저장할 수 있다.
LocalDate currDate = LocalDate.now();
LocalDate targetDate = LocalDate.of(int year, int month, int dayOfMonth);
.get...()
메소드로 년, 월, 이번 년의 몇번째 일인지, 요일, 윤년 여부 등을 가져올 수 있다..minusYear()
, .plusYear()
등의 메소드로 년월일을 더하거나 뺄 수도 있다..with()
메소드로 이번 해의 첫번째, 마지막 번째 일 등을 알 수도 있다..isAfter()
와 같은 메소드로 이후, 이전 날짜 인지도 알 수 있다..until()
과 같은 메소드로 시간, 날짜 차이 등도 알 수 있다..between()
과 같은 메소드로 시작 시점과 끝 시점의 날짜 차이 등도 알 수 있다.로컬 시간 클래스로 시간 정보만 저장할 수 있다.
LocalTime currTime = LocalTime.now();
LocalTime targetTime = LocalTime.of(int hour, int minute, int second, int nanoOfSecond);
마찬가지로
.get...()
메소드로 시, 분, 초 등을 가져올 수 있다.
로컬 날짜 및 시간 클래스(LocalDate + LocalTime)
LocalDateTime currDateTime = LocalDateTime.now();
LocalDateTime targetDateTime = LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond);
ISO-8601 달력 시스템에서 정의하는 특정 타임존(TimeZone)의 날짜와 시간 클래스
ZonedDateTime seoulDateTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
ZoneId는
java.util.TimeZone.getAvailableIds()
메소드로 얻을 수 있다.
.getOffset()
메소드 등으로 시차도 알 수 있다.
특정 시점의 Time-Stamp 클래스로 누가 빠르고 누가 느리고 차이는 얼마나 나고 이런 것들을 알 수 있다.
public class InstantTest {
public static void main(String[] args) throws InterruptedException {
Instant instant1 = Instant.now();
Thread.sleep(10);
Instant instant2 = Instant.now();
if(instant1.isBefore(instant2)) {
System.out.println("instant1이 빠르다.");
} else if (instant1.isAfter(instant2)) {
System.out.println("instant2가 빠르다");
} else {
System.out.println("동일한 시간이다.");
}
System.out.println("차이(nanos): " + instant1.until(instant2, ChronoUnit.NANOS));
}
}
날짜 문자열을 받아서 파싱하는 것도 가능하다.
LocalDate localDate = LocalDate.parse("2024-05-21");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd");
LocalDate localDate = LocalDate.parse("2024.05.21", formatter);
ISO 표준을 잘 알면 ISO 기준으로 미리 만들어둔 formatter
를 이용할 수도 있다.
LocalDate localdate = LocalDate.parse("2024-05-21", DateTimeFormatter.ISO_LOCAL_DATE);
// ISO_LOCAL_DATE: "yyyy-MM-dd"
foramtter
와 다른 문자열을 파싱하게 되면DateTimeParseException
이 발생한다.
public class Main {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일 HH시 mm분 ss초");
String format = now.format(dateTimeFormatter);
System.out.println("format = " + format); // format = 2021년 05월 06일 23시 31분 55초
}
}
LocalDateTime
이 제공하는 .format()
메소드에 DateTimeFormatter
객체를 넣으면 된다.