공공부하자개발 · 영어 학습 노트
자바
명령어자주 쓰는 API 참조0/8 완료
  • 01String · StringBuilder · 정규식
  • 02Collections · Arrays · Map
  • 03Stream · Collectors · 함수형 인터페이스
  • 04Files · Path · I/O
  • 05java.time · BigDecimal · 기타 유틸
  • 06Oracle SQL
  • 07예외 · 디버깅
  • 08Spring Boot 설정 키
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › 명령어 › 05 / 8

java.time · BigDecimal · 기타 유틸

섹션 13진행 0 / 8

java.time · BigDecimal · 기타 유틸 명령어

날짜/시간(java.time 전체), 수학과 금액 계산(Math, BigDecimal, BigInteger), 난수/UUID, System/Objects/Runtime/Thread 유틸, 정규식 치트표를 한 페이지에 모았다. Ctrl+F로 메서드명(예: TemporalAdjusters, withZoneSameInstant, setScale, requireNonNullElse)을 검색하면 된다. 예제의 기준 값은 d = LocalDate.of(2024, 3, 15)(금요일), dt = LocalDateTime.of(2024, 3, 15, 9, 30, 5), 시스템 존은 Asia/Seoul. 모든 결과는 JDK 21 실행값이다.

01한눈에 보기
메서드 설명 예제 결과
LocalDate.now() / of(y, m, d) 날짜 LocalDate.of(2024, 3, 15) 2024-03-15
LocalDateTime.now() / of(...) 날짜+시각 LocalDateTime.of(2024, 3, 15, 9, 30, 5) 2024-03-15T09:30:05
LocalDate.parse(s) ISO 파싱 LocalDate.parse("2024-03-15") 2024-03-15
format(DateTimeFormatter.ofPattern(p)) 포맷 dt.format(ofPattern("yyyy-MM-dd HH:mm:ss")) 2024-03-15 09:30:05
plusDays/Months/Years(n) 더하기 d.plusDays(20) 2024-04-04
with(TemporalAdjusters.lastDayOfMonth()) 월말 d.with(lastDayOfMonth()) 2024-03-31
getDayOfWeek() 요일 d.getDayOfWeek() FRIDAY
ChronoUnit.DAYS.between(a, b) 일수 차이 DAYS.between(d, LocalDate.of(2024, 12, 25)) 285
Period.between(a, b) 년월일 차이 Period.between(LocalDate.of(1990, 5, 20), d) P33Y9M24D
Duration.between(a, b) 시분초 차이 Duration.between(LocalTime.of(9, 0), LocalTime.of(17, 30)) PT8H30M
isBefore/isAfter/isEqual 비교 d.isBefore(LocalDate.of(2024, 4, 1)) true
atZone(ZoneId) / withZoneSameInstant 타임존 dt.atZone(seoul).withZoneSameInstant(ZoneOffset.UTC) 2024-03-15T00:30:05Z
Instant.now() / toEpochMilli() epoch Instant.parse("2024-03-15T00:30:05Z").toEpochMilli() 1710462605000
new BigDecimal("0.1") 정확한 소수 (문자열 생성자) new BigDecimal("0.1").add(new BigDecimal("0.2")) 0.3
setScale(2, RoundingMode.HALF_UP) 반올림 new BigDecimal("2.345").setScale(2, HALF_UP) 2.35
compareTo (BigDecimal) 값 비교 (equals는 scale 포함) new BigDecimal("1.0").compareTo(new BigDecimal("1.00")) 0
Math.round(x) 반올림 (long) Math.round(2.5) 3
UUID.randomUUID() 랜덤 UUID UUID.randomUUID().toString().length() 36
Objects.requireNonNull(x, msg) null 검사 Objects.requireNonNull(null, "name must not be null") NullPointerException: name must not be null
System.nanoTime() 경과 시간 측정 long s = System.nanoTime(); ...; System.nanoTime() - s ns
02java.time 생성·조회·계산
메서드/시그니처 설명 한 줄 예제 결과
LocalDate.of(y, m, d) 날짜 LocalDate.of(2024, 3, 15) 2024-03-15
LocalDate.parse("yyyy-MM-dd") ISO 파싱 LocalDate.parse("2024-03-15") 2024-03-15
LocalDate.ofYearDay(y, n) 연중 n일째 LocalDate.ofYearDay(2024, 75) 2024-03-15
LocalDate.ofEpochDay(n) epoch일 LocalDate.ofEpochDay(0) 1970-01-01
LocalDateTime.of(y, M, d, h, m, s) 날짜+시각 LocalDateTime.of(2024, 3, 15, 9, 30, 5) 2024-03-15T09:30:05
LocalDateTime.parse("...T...") ISO 파싱 LocalDateTime.parse("2024-03-15T09:30") 2024-03-15T09:30
LocalTime.of(h, m, s) / parse 시각 LocalTime.parse("09:30") 09:30
date.atTime(h, m) / atStartOfDay() 날짜 → 일시 d.atStartOfDay() 2024-03-15T00:00
dt.toLocalDate() / toLocalTime() 일시 → 분리 dt.toLocalDate() + " " + dt.toLocalTime() 2024-03-15 09:30:05
getYear/getMonthValue/getDayOfMonth 필드 d.getYear() + "/" + d.getMonthValue() + "/" + d.getDayOfMonth() 2024/3/15
getMonth() enum d.getMonth() + " " + d.getMonth().getValue() MARCH 3
getDayOfWeek() enum (월=1 … 일=7) d.getDayOfWeek() + " " + d.getDayOfWeek().getValue() FRIDAY 5
getDayOfYear() 연중 일수 d.getDayOfYear() 75
lengthOfMonth() / lengthOfYear() / isLeapYear() 길이·윤년 d.lengthOfMonth() + " " + d.lengthOfYear() + " " + d.isLeapYear() 31 366 true
getHour/getMinute/getSecond/getNano 시각 필드 dt.getHour() + ":" + dt.getMinute() 9:30
plusDays/Weeks/Months/Years(n) 더하기 d.plusDays(20) / d.minusWeeks(1) 2024-04-04 / 2024-03-08
plusMonths 월말 보정 넘치면 말일로 LocalDate.of(2024, 1, 31).plusMonths(1) 2024-02-29
plusYears 윤일 보정 2/29 → 2/28 LocalDate.of(2024, 2, 29).plusYears(1) 2025-02-28
plus(Period) / plus(n, ChronoUnit) 단위 지정 d.plus(Period.ofMonths(2)) / d.plus(3, ChronoUnit.DAYS) 2024-05-15 / 2024-03-18
plusHours/Minutes/Seconds 시각 더하기 (날짜 넘김) dt.plusHours(20) 2024-03-16T05:30:05
withDayOfMonth/withMonth/withYear(n) 필드 교체 d.withDayOfMonth(1) / d.withMonth(12) 2024-03-01 / 2024-12-15
withHour(0).withMinute(0).withSecond(0) 자정으로 dt.withHour(0).withMinute(0).withSecond(0) 2024-03-15T00:00
truncatedTo(ChronoUnit) 단위 이하 버림 dt.truncatedTo(ChronoUnit.HOURS) 2024-03-15T09:00
datesUntil(end) 날짜 스트림 [start, end) LocalDate.of(2024,3,1).datesUntil(LocalDate.of(2024,3,5)).toList() [2024-03-01, 2024-03-02, 2024-03-03, 2024-03-04]
datesUntil(end, Period) 간격 지정 아래 코드 1 [2024-01-01, 2024-02-01, 2024-03-01]
YearMonth.of(y, m) 연월 YearMonth.of(2024, 2).lengthOfMonth() 29
YearMonth.atEndOfMonth() / atDay(1) 월말/월초 YearMonth.parse("2024-02").atEndOfMonth() 2024-02-29
YearMonth.from(date) 날짜 → 연월 YearMonth.from(d) 2024-03
Year.of(y).isLeap() / Year.isLeap(y) 윤년 Year.isLeap(2023) false
MonthDay.of(m, d).atYear(y) 기념일 MonthDay.of(12, 25).atYear(2024) 2024-12-25
DayOfWeek.plus(n) / of(n) 요일 산술 DayOfWeek.FRIDAY.plus(3) / DayOfWeek.of(1) MONDAY / MONDAY
DayOfWeek.getDisplayName(style, locale) 요일 이름 DayOfWeek.MONDAY.getDisplayName(TextStyle.SHORT, Locale.KOREAN) 월
Month.getDisplayName / length(leap) 월 이름/길이 아래 코드 2 3월 / 29
Clock.fixed(instant, zone) 테스트용 고정 시계 아래 코드 3 2020-01-01
  • java.time 객체는 모두 불변이다. d.plusDays(1)의 반환값을 받아야 한다.
  • 월은 1부터(getMonthValue()), 요일은 월요일=1. 레거시 Calendar는 월이 0부터라 혼동하기 쉽다.

표 칸이 길어 아래로 옮긴 예제입니다.

java
// 아래 코드 1: 월 간격 날짜 스트림
LocalDate.of(2024, 1, 1)
    .datesUntil(LocalDate.of(2024, 4, 1), Period.ofMonths(1))
    .toList(); // [2024-01-01, 2024-02-01, 2024-03-01]

// 아래 코드 2: 월 이름/길이
Month.of(3).getDisplayName(TextStyle.FULL, Locale.KOREAN); // 3월
Month.FEBRUARY.length(true); // 29

// 아래 코드 3: 고정 시계로 테스트용 현재 날짜 만들기
LocalDate.now(Clock.fixed(
    Instant.parse("2020-01-01T00:00:00Z"), ZoneOffset.UTC)); // 2020-01-01
03TemporalAdjusters · 비교 · 기간 (Period / Duration / ChronoUnit)
메서드/시그니처 설명 한 줄 예제 결과
with(firstDayOfMonth()) 월초 d.with(TemporalAdjusters.firstDayOfMonth()) 2024-03-01
with(lastDayOfMonth()) 월말 d.with(TemporalAdjusters.lastDayOfMonth()) 2024-03-31
with(firstDayOfNextMonth()) 다음 달 1일 d.with(TemporalAdjusters.firstDayOfNextMonth()) 2024-04-01
with(firstDayOfYear()) / lastDayOfYear() 연초/연말 d.with(firstDayOfYear()) + " " + d.with(lastDayOfYear()) 2024-01-01 2024-12-31
with(next(DayOfWeek)) 다음 요일 (오늘 제외) d.with(TemporalAdjusters.next(DayOfWeek.MONDAY)) 2024-03-18
with(nextOrSame(DayOfWeek)) 다음 요일 (오늘 포함) d.with(nextOrSame(DayOfWeek.FRIDAY)) 2024-03-15
with(previous(DayOfWeek)) 이전 요일 d.with(previous(DayOfWeek.SUNDAY)) 2024-03-10
with(lastInMonth(DayOfWeek)) 이달 마지막 X요일 d.with(lastInMonth(DayOfWeek.FRIDAY)) 2024-03-29
with(dayOfWeekInMonth(n, DayOfWeek)) n번째 X요일 d.with(dayOfWeekInMonth(2, DayOfWeek.TUESDAY)) 2024-03-12
isBefore(o) / isAfter(o) / isEqual(o) 비교 d.isBefore(LocalDate.of(2024, 4, 1)) true
compareTo(o) 정렬용 d.compareTo(LocalDate.of(2024, 3, 10)) 5
equals(o) 동일 d.equals(LocalDate.of(2024, 3, 15)) true
ChronoUnit.DAYS.between(a, b) 일수 (b < a면 음수) DAYS.between(d, LocalDate.of(2024, 12, 25)) 285
ChronoUnit.MONTHS.between(a, b) 개월 (내림) MONTHS.between(d, LocalDate.of(2024, 12, 25)) 9
a.until(b) / a.until(b, unit) Period / 단위 d.until(LocalDate.of(2024,12,25))+" "+d.until(...,WEEKS) P9M10D 40
Period.between(a, b) 년월일 차이 Period.between(LocalDate.of(1990, 5, 20), d) P33Y9M24D
Period.getYears/getMonths/getDays 필드 p.getYears() + "y " + p.getMonths() + "m " + p.getDays() + "d" 33y 9m 24d
Period.toTotalMonths() 총 개월 p.toTotalMonths() 405
Period.of(y, m, d) / ofDays/ofWeeks/ofMonths 생성 Period.of(1, 2, 3) + " " + Period.ofWeeks(2) P1Y2M3D P14D
Period.parse("P1Y2M3D") ISO 파싱 Period.parse("P1Y2M3D") P1Y2M3D
Period.normalized() 12개월 → 1년 Period.ofMonths(14).normalized() P1Y2M
Period.getDays()는 총 일수가 아님 주의 Period.between(2024-01-01, 2024-03-01).getDays() 0 (P2M)
Duration.between(a, b) 시분초 차이 (LocalTime/LocalDateTime/Instant) Duration.between(LocalTime.of(9, 0), LocalTime.of(17, 30)) PT8H30M
Duration.between(LocalDate...) 불가 Duration.between(d, d.plusDays(1)) UnsupportedTemporalTypeException: Unsupported unit: Seconds
Duration.ofSeconds/Minutes/Hours/Days/Millis 생성 Duration.ofMinutes(90) + " " + Duration.ofMillis(1500) PT1H30M PT1.5S
Duration.of(n, ChronoUnit) 단위 지정 Duration.of(2, ChronoUnit.HOURS) PT2H
Duration.parse("PT1H30M") ISO 파싱 Duration.parse("PT1H30M").toMinutes() 90
toHours/toMinutes/toSeconds/toMillis 총량 Duration.ofSeconds(3725).toMinutes() 62
toHoursPart/toMinutesPart/toSecondsPart 자릿수 부분 (JDK 9+, 3725초 기준) du.toHours()+"h "+du.toMinutesPart()+"m "+du.toSecondsPart()+"s" 1h 2m 5s
getSeconds() / getNano() 내부 값 Duration.ofHours(1).plusMinutes(30).getSeconds() 5400
plus/minus/multipliedBy/dividedBy 산술 Duration.ofMinutes(10).multipliedBy(3).dividedBy(2) PT15M
isZero() / isNegative() / compareTo 비교 Duration.ofMinutes(1).compareTo(Duration.ofSeconds(59)) 1
Duration.toString() ISO 형식 Duration.ofSeconds(3725) PT1H2M5S
Duration with LocalDateTime 일 단위도 시간으로 Duration.between(dt, dt.plusDays(1).plusHours(2)) PT26H
  • 날짜 차이는 Period/ChronoUnit, 시간 차이는 Duration. Duration.between(LocalDate, LocalDate)는 예외.
  • 나이·근속연수는 Period.between(...).getYears(), 총 일수는 ChronoUnit.DAYS.between.
04DateTimeFormatter 패턴표 · 파싱
패턴/상수 의미 한 줄 예제 결과
ISO_LOCAL_DATE yyyy-MM-dd d.format(DateTimeFormatter.ISO_LOCAL_DATE) 2024-03-15
ISO_LOCAL_DATE_TIME yyyy-MM-ddTHH:mm:ss dt.format(ISO_LOCAL_DATE_TIME) 2024-03-15T09:30:05
BASIC_ISO_DATE yyyyMMdd d.format(BASIC_ISO_DATE) 20240315
ISO_DATE_TIME (zoned) 오프셋+존 ID z.format(ISO_DATE_TIME) 2024-03-15T09:30:05+09:00[Asia/Seoul]
ISO_OFFSET_DATE_TIME 오프셋 z.format(ISO_OFFSET_DATE_TIME) 2024-03-15T09:30:05+09:00
ISO_INSTANT UTC Z z.format(ISO_INSTANT) 2024-03-15T00:30:05Z
yyyy / uuuu 연도 (uuuu는 기원전 음수, STRICT 파싱 시 필요) LocalDate.of(-1,1,1).format(ofPattern("yyyy G / uuuu", ENGLISH)) 0002 BC / -0001
yy 두 자리 연도 d.format(ofPattern("yy/M/d")) 24/3/15
MM / M 월 2자리 / 최소 d.format(ofPattern("yyyy.MM.dd")) 2024.03.15
MMM / MMMM 월 이름 (로케일) d.format(ofPattern("MMM MMMM", ENGLISH)) / KOREAN Mar March / 3월 3월
dd / d 일 d.format(ofPattern("d")) 15
E / EEEE 요일 짧게/길게 아래 코드 1 금요일 Fri
HH / H 24시간 dt.format(ofPattern("HH:mm:ss")) 09:30:05
hh / a 12시간 / 오전·오후 아래 코드 2 09:30 AM / 오전 9시 30분
mm 분 (MM은 월!) dt.format(ofPattern("yyyy-mm-dd")) 2024-30-15 (버그)
ss / SSS 초 / 밀리초 dt.withNano(123_000_000).format(ofPattern("HH:mm:ss.SSS")) 09:30:05.123
D / w / W 연중 일 / 연중 주 / 월중 주 d.format(ofPattern("D w W")) 75 11 3
Q / QQQ 분기 d.format(ofPattern("Q QQQ", ENGLISH)) 1 Q1
XXX / x / z / VV 오프셋 +09:00 / +09 / 존 약어 / 존 ID z.format(ofPattern("XXX z VV x", ENGLISH)) +09:00 KST Asia/Seoul +09
'리터럴' 따옴표로 문자 삽입 dt.format(ofPattern("yyyy'년' MM'월' dd'일' 'at' HH:mm")) 2024년 03월 15일 at 09:30
ofPattern(p, Locale) 로케일 지정 (서버 로케일 의존 제거) ofPattern("yyyy년 M월 d일 (E)", Locale.KOREAN) 2024년 3월 15일 (금)
ofLocalizedDate(FormatStyle) 로케일 표준 형식 d.format(ofLocalizedDate(LONG).withLocale(KOREAN)) / MEDIUM, US 2024년 3월 15일 / Mar 15, 2024
LocalDate.parse(s, fmt) 패턴 파싱 LocalDate.parse("15/03/2024", ofPattern("dd/MM/yyyy")) 2024-03-15
LocalDateTime.parse(s, fmt) 일시 파싱 아래 코드 3 2024-03-15T09:30
parse 형식 불일치 예외 LocalDate.parse("2024-3-5") DateTimeParseException: ... could not be parsed at index 5
parse 존재하지 않는 날짜 예외 (ISO 기본 SMART) LocalDate.parse("2024-02-30") DateTimeParseException: ... Invalid date 'FEBRUARY 30'
ResolverStyle.LENIENT 넘치면 이월 아래 코드 4 2024-03-01
ResolverStyle.STRICT + uuuu 엄격 검증 아래 코드 5 DateTimeParseException
STRICT + yyyy 정상 날짜도 실패 (era 필요) 아래 코드 6 DateTimeParseException → uuuu 사용
날짜만 있는 문자열을 LocalDateTime으로 예외 LocalDateTime.parse("2024-03-15", ISO_LOCAL_DATE) DateTimeParseException: Unable to obtain LocalDateTime
DateTimeFormatter 스레드 안전 불변, static 공유 OK private static final DateTimeFormatter F = ofPattern(...) (SimpleDateFormat은 불가)
  • 패턴 대소문자: MM=월, mm=분, HH=24시, hh=12시, DD=연중일, dd=일, yyyy≈uuuu(STRICT에서는 uuuu).
  • 파싱 실패는 DateTimeParseException(unchecked). 외부 입력은 반드시 잡는다.

표 칸이 길어 아래로 옮긴 예제입니다.

java
// 아래 코드 1: 요일 짧게/길게
d.format(ofPattern("EEEE", KOREAN)) + " " + d.format(ofPattern("E", ENGLISH));
// → "금요일 Fri"

// 아래 코드 2: 12시간제 (영어/한국어)
dt.format(ofPattern("hh:mm a", ENGLISH)); // "09:30 AM"
dt.format(ofPattern("a h시 m분", KOREAN)); // "오전 9시 30분"

// 아래 코드 3: 일시 문자열을 패턴으로 파싱
LocalDateTime.parse("2024-03-15 09:30", ofPattern("yyyy-MM-dd HH:mm"));

// 아래 코드 4: LENIENT - 2월 30일을 3월 1일로 이월
parse("2024-02-30", ofPattern("yyyy-MM-dd").withResolverStyle(LENIENT));

// 아래 코드 5: STRICT + uuuu - 없는 날짜는 예외
parse("2024-02-30", ofPattern("uuuu-MM-dd").withResolverStyle(STRICT));

// 아래 코드 6: STRICT + yyyy - 정상 날짜도 예외(era 필요)
parse("2024-02-10", ofPattern("yyyy-MM-dd").withResolverStyle(STRICT));
05타임존 · Instant · epoch · 레거시 변환
메서드/시그니처 설명 한 줄 예제 결과
ZoneId.of("Asia/Seoul") 존 ID ZoneId.of("Asia/Seoul") Asia/Seoul
ZoneId.systemDefault() JVM 기본 존 ZoneId.systemDefault() Asia/Seoul
ZoneOffset.of("+09:00") / ofHours(-5) / UTC 고정 오프셋 ZoneOffset.ofHours(-5) + " " + ZoneOffset.UTC -05:00 Z
ZonedDateTime.of(ldt, zone) / ldt.atZone(zone) 존 붙이기 dt.atZone(seoul) 2024-03-15T09:30:05+09:00[Asia/Seoul]
ZonedDateTime.now(zone) 특정 존 현재 ZonedDateTime.now(ZoneId.of("UTC")) UTC 현재
withZoneSameInstant(zone) 같은 순간, 다른 존 표시 (변환) z.withZoneSameInstant(ZoneId.of("America/New_York")) 2024-03-14T20:30:05-04:00[America/New_York]
withZoneSameInstant(UTC) UTC로 z.withZoneSameInstant(ZoneOffset.UTC) 2024-03-15T00:30:05Z
withZoneSameLocal(zone) 같은 벽시계, 존만 교체 (순간 바뀜) z.withZoneSameLocal(ZoneId.of("Europe/London")) 2024-03-15T09:30:05Z[Europe/London]
getOffset() / getZone() 오프셋/존 z.getOffset() + " " + z.getZone() +09:00 Asia/Seoul
toInstant() 순간으로 z.toInstant() 2024-03-15T00:30:05Z
toOffsetDateTime() / toLocalDateTime() 변환 z.toOffsetDateTime() 2024-03-15T09:30:05+09:00
OffsetDateTime.of(ldt, offset) 오프셋 일시 (DB TIMESTAMPTZ) OffsetDateTime.of(dt, ZoneOffset.ofHours(9)) 2024-03-15T09:30:05+09:00
OffsetDateTime.parse(s) ISO 파싱 OffsetDateTime.parse("2024-03-15T09:30:05+09:00").toInstant() 2024-03-15T00:30:05Z
ZonedDateTime.parse(s) 존 포함 파싱 아래 코드 Asia/Seoul
DST 갭 (존재하지 않는 시각) 뒤로 밀림 LocalDateTime.of(2024,3,10,2,30).atZone(NY) 2024-03-10T03:30-04:00
DST 겹침 (두 번 있는 시각) 기본 이른 오프셋 / withLaterOffsetAtOverlap() LocalDateTime.of(2024,11,3,1,30).atZone(NY) 01:30-04:00 / 01:30-05:00
plusDays(1) vs plusHours(24) (DST) 날짜 산술은 벽시계 유지 NY 2024-03-09 12:00 + 1일 / + 24시간 03-10T12:00-04:00 / 03-10T13:00-04:00
zone.getRules().getOffset(instant) 특정 순간의 오프셋 seoul.getRules().getOffset(Instant.EPOCH) +09:00
Instant.now() 현재 UTC 순간 Instant.now() ...Z
Instant.parse(s) ISO-8601 Z Instant.parse("2024-03-15T00:30:05Z") 2024-03-15T00:30:05Z
Instant.ofEpochSecond(s) / ofEpochMilli(ms) epoch → Instant Instant.ofEpochMilli(1_710_462_605_000L) 2024-03-15T00:30:05Z
toEpochMilli() / getEpochSecond() Instant → epoch i.toEpochMilli() + " " + i.getEpochSecond() 1710462605000 1710462605
instant.atZone(zone) Instant → ZonedDateTime i.atZone(seoul) 2024-03-15T09:30:05+09:00[Asia/Seoul]
LocalDateTime.ofInstant(i, zone) Instant → LocalDateTime LocalDateTime.ofInstant(i, seoul) 2024-03-15T09:30:05
ldt.toEpochSecond(offset) LocalDateTime → epoch (오프셋 필요) dt.toEpochSecond(ZoneOffset.ofHours(9)) 1710462605
ldt.atZone(zone).toInstant() LocalDateTime → Instant dt.atZone(seoul).toInstant() 2024-03-15T00:30:05Z
date.toEpochDay() 1970-01-01 기준 일수 d.toEpochDay() 19797
Instant.ofEpochMilli(ms).atZone(zone).toLocalDate() epoch ms → 날짜 Instant.ofEpochMilli(0).atZone(seoul).toLocalDate() 1970-01-01
instant.plus(n, unit) / truncatedTo 산술 i.plus(1, ChronoUnit.DAYS) / i.truncatedTo(ChronoUnit.HOURS) 2024-03-16T00:30:05Z / 2024-03-15T00:00:00Z
Date.toInstant() 레거시 → 신 new Date(0).toInstant() 1970-01-01T00:00:00Z
Date → LocalDateTime 존 필요 date.toInstant().atZone(seoul).toLocalDateTime() 1970-01-01T09:00
Date.from(instant) 신 → 레거시 Date.from(Instant.EPOCH).getTime() 0
LocalDate → Date 자정 기준 Date.from(d.atStartOfDay(seoul).toInstant()).getTime() 1710428400000
java.sql.Date.valueOf(localDate) / toLocalDate() JDBC DATE java.sql.Date.valueOf(d) 2024-03-15
java.sql.Timestamp.valueOf(ldt) / toLocalDateTime() JDBC TIMESTAMP Timestamp.valueOf(dt) 2024-03-15 09:30:05.0
Calendar.get(Calendar.MONTH) 0부터 cal.get(Calendar.MONTH) (1월) 0
GregorianCalendar.toZonedDateTime() Calendar → 신 new GregorianCalendar(2024,2,15).toZonedDateTime().toLocalDate() 2024-03-15
Date.getYear() 1900 기준 (deprecated) new Date(0).getYear() 70
SimpleDateFormat 스레드 불안전, 신규 코드 금지 new SimpleDateFormat("yyyy-MM-dd").format(new Date(0)) 1970-01-01
  • 저장·전송은 Instant(UTC) 또는 OffsetDateTime, 화면 표시는 ZonedDateTime/LocalDateTime. LocalDateTime은 존 정보가 없어 서버 존이 바뀌면 의미가 달라진다.
  • JSON 표준은 z.toInstant().toString()(2024-03-15T00:30:05Z) 또는 ISO_OFFSET_DATE_TIME.

표 칸이 길어 아래로 옮긴 예제입니다.

java
// 존 포함 문자열을 파싱해 존 정보만 꺼내기
ZonedDateTime.parse("2024-03-15T09:30:05+09:00[Asia/Seoul]").getZone();
06Math · 숫자 기본
메서드/시그니처 설명 한 줄 예제 결과
Math.abs(x) 절댓값 (MIN_VALUE는 그대로!) Math.abs(-5) + " " + Math.abs(Integer.MIN_VALUE) 5 -2147483648
Math.absExact(x) 오버플로 시 예외 (JDK 15+) Math.absExact(-5) 5
Math.max/min(a, b) 최대/최소 Math.max(3, 7) + "/" + Math.min(3.5, 2) 7/2.0
Math.pow(a, b) 거듭제곱 (double) Math.pow(2, 10) + " " + (int) Math.pow(2, 10) 1024.0 1024
Math.sqrt/cbrt/hypot 제곱근/세제곱근/빗변 Math.sqrt(16) + " " + Math.cbrt(27) + " " + Math.hypot(3, 4) 4.0 3.0 5.0
Math.round(x) 반올림 → long (.5는 올림, 음수는 -2.5→-2) Math.round(2.5) + " " + Math.round(-2.5) + " " + Math.round(2.4f) 3 -2 2
Math.floor(x) / ceil(x) 내림/올림 (double) Math.floor(-2.5) + " " + Math.ceil(-2.5) -3.0 -2.0
Math.rint(x) 짝수 반올림 (banker's) Math.rint(2.5) + " " + Math.rint(3.5) 2.0 4.0
Math.floorDiv/floorMod(a, b) 음수 나눗셈 수학적 아래 코드 1 -4 1 vs -3 -1
Math.ceilDiv(a, b) 올림 나눗셈 (JDK 18+) Math.ceilDiv(7, 2) 4
Math.addExact/subtractExact/multiplyExact 오버플로 검사 Math.addExact(Integer.MAX_VALUE, 1) ArithmeticException: integer overflow
일반 산술 오버플로 조용히 회전 Integer.MAX_VALUE + 1 -2147483648
Math.toIntExact(long) long → int 검사 Math.toIntExact(3_000_000_000L) ArithmeticException: integer overflow
Math.clamp(v, min, max) 범위 제한 (JDK 21) Math.clamp(15, 0, 10) + " " + Math.clamp(-3, 0, 10) 10 0
Math.signum(x) / Integer.signum 부호 Math.signum(-3.2) + " " + Integer.signum(-5) -1.0 -1
Math.log/log10/exp 로그/지수 Math.log(Math.E) + " " + Math.log10(1000) + " " + Math.exp(0) 1.0 3.0 1.0
Math.PI / toRadians / toDegrees 각도 Math.toDegrees(Math.PI) 180.0
Math.sin/cos/tan/atan2 삼각 Math.sin(Math.PI / 2) 1.0
Math.random() [0, 1) double (int) (Math.random() * 6) + 1 1~6
정수 나눗셈 버림 7 / 2 + " " + 7 / 2.0 + " " + 7 % 3 + " " + (-7) % 3 3 3.5 1 -1
double 오차 이진 표현 한계 0.1 + 0.2 0.30000000000000004
double 비교 오차 허용 Math.abs((0.1 + 0.2) - 0.3) < 1e-9 true (==는 false)
Integer.MAX_VALUE / Long.MAX_VALUE / Double.MAX_VALUE 한계 왼쪽 2147483647 9223372036854775807 1.7976931348623157E308
NaN / Infinity 0으로 나눔 (double) 0.0 / 0 + " " + 1.0 / 0 + " " + (Double.NaN == Double.NaN) NaN Infinity false (isNaN 사용)
Integer.compare(a, b) / sum / max 정적 유틸 Integer.compare(3, 5) + " " + Integer.max(1, 2) -1 2
Integer.bitCount/highestOneBit/numberOfTrailingZeros 비트 Integer.bitCount(7) + " " + Integer.highestOneBit(100) 3 64
Integer.parseInt(s, radix) / toBinaryString 진법 Integer.parseInt("1010", 2) 10
Double.compare(a, b) / parseDouble / valueOf("1e3") double 유틸 Double.valueOf("1e3") 1000.0
DecimalFormat("#,##0.00") 숫자 포맷 아래 코드 2 1,234,567.89
NumberFormat.getCurrencyInstance(Locale.KOREA) 통화 NumberFormat.getCurrencyInstance(Locale.KOREA).format(1234567) ₩1,234,567
NumberFormat.getPercentInstance() 퍼센트 NumberFormat.getPercentInstance().format(0.256) 26%
String.format("%,.2f", x) 콤마+소수 String.format("%,.2f", new BigDecimal("1234567.891")) 1,234,567.89

표 칸이 길어 아래로 옮긴 예제입니다.

java
// 아래 코드 1: 음수 나눗셈 - 수학적(floorDiv/Mod) vs 절사(/, %)
Math.floorDiv(-7, 2) + " " + Math.floorMod(-7, 2)
    + " vs " + (-7 / 2) + " " + (-7 % 2); // "-4 1 vs -3 -1"

// 아래 코드 2: 천 단위 콤마 + 소수 둘째 자리
new DecimalFormat("#,##0.00").format(new BigDecimal("1234567.891"));
07BigDecimal · BigInteger (금액 계산 규칙)
메서드/시그니처 설명 한 줄 예제 결과
new BigDecimal(double) 금지 — 이진 오차 그대로 new BigDecimal(0.1) 0.1000000000000000055511151231257827021181583404541015625
new BigDecimal("0.1") 문자열 생성자 (권장) new BigDecimal("0.1") 0.1
BigDecimal.valueOf(double) Double.toString 경유 (차선) BigDecimal.valueOf(0.1) 0.1
ZERO / ONE / TWO / TEN 상수 BigDecimal.ZERO + " " + BigDecimal.TEN 0 10
add/subtract/multiply 사칙 (불변, 반환값 사용) new BigDecimal("1.5").multiply(new BigDecimal("2.25")) 3.375
divide(x) (정확히 나눠질 때) 무한소수면 예외 new BigDecimal("10").divide(new BigDecimal("4")) 2.5
divide(x) 무한소수 예외 new BigDecimal("10").divide(new BigDecimal("3")) ArithmeticException: Non-terminating decimal expansion; ...
divide(x, scale, RoundingMode) 자릿수+반올림 지정 (권장) new BigDecimal("10").divide(new BigDecimal("3"), 2, HALF_UP) 3.33
divide(x, MathContext) 유효 자릿수 지정 divide(new BigDecimal("3"), DECIMAL64) / new MathContext(4) 3.333333333333333 / 3.333
setScale(n, RoundingMode.HALF_UP) 사사오입 new BigDecimal("2.345").setScale(2, HALF_UP) 2.35
setScale(n, HALF_EVEN) 은행가 반올림 (5 앞이 짝수면 버림) "2.345" → HALF_EVEN / "2.355" → HALF_EVEN 2.34 / 2.36
setScale(n, HALF_DOWN) 5는 버림, 5 초과는 올림 "2.345" → HALF_DOWN / "2.3451" → HALF_DOWN 2.34 / 2.35
setScale(n, DOWN) / UP 절사 / 절상 (0 방향 / 0 반대) "2.341" → DOWN / "2.341" → UP 2.34 / 2.35
setScale(n, FLOOR) / CEILING 음의 무한 / 양의 무한 방향 "-2.345" → CEILING / "-2.345" → FLOOR -2.34 / -2.35
setScale(n, UNNECESSARY) 반올림 필요하면 예외 new BigDecimal("2.345").setScale(2, UNNECESSARY) ArithmeticException: Rounding necessary
setScale(n) 확장 0 채움 new BigDecimal("2").setScale(3) 2.000
scale() / precision() / unscaledValue() 내부 표현 "123.4500" → 4 / 7 / 1234500
stripTrailingZeros() 뒤 0 제거 (지수 표기 주의) new BigDecimal("100").stripTrailingZeros() / .toPlainString() 1E+2 / 100
toPlainString() 지수 없는 문자열 아래 코드 1 1000 / 1E-7 (toString)
toString() 지수 표기 큰 수 곱셈 결과 new BigDecimal("1234567").multiply(new BigDecimal("1E10")) 1.234567E+16
equals(o) scale까지 비교 new BigDecimal("1.0").equals(new BigDecimal("1.00")) false
compareTo(o) 값만 비교 (권장) new BigDecimal("1.0").compareTo(new BigDecimal("1.00")) 0
hashCode scale 포함 (Map 키 주의) "1.0".hashCode() == "1.00".hashCode() false
0 검사 compareTo(ZERO) == 0 또는 signum() == 0 new BigDecimal("0.00").compareTo(BigDecimal.ZERO) == 0 true
signum() / abs() / negate() 부호 new BigDecimal("-3").signum() + " " + new BigDecimal("-3").abs() -1 3
max(o) / min(o) 비교 선택 new BigDecimal("3").max(new BigDecimal("5")) 5
pow(n) 거듭제곱 (정수) new BigDecimal("1.05").pow(3) 1.157625
movePointLeft/Right(n) / scaleByPowerOfTen(n) 10의 거듭제곱 아래 코드 2 123.45 / 1.5E+2
remainder(x) / divideAndRemainder(x) 나머지 new BigDecimal("10").divideAndRemainder(new BigDecimal("3")) [3, 1]
intValue() / longValue() / doubleValue() 변환 (절사) new BigDecimal("3.99").intValue() 3
intValueExact() / longValueExact() 손실 시 예외 new BigDecimal("3.99").intValueExact() ArithmeticException: Rounding necessary
toBigInteger() 정수부 new BigDecimal("3.99").toBigInteger() 3
스트림 합계 reduce(ZERO, add) 아래 코드 3 6.6
콤마 문자열 파싱 제거 후 생성 new BigDecimal("1,234".replace(",", "")) 1234
new BigInteger("...") 임의 정밀도 정수 new BigInteger("123456789012345678901234567890").add(ONE) 123456789012345678901234567891
BigInteger.valueOf(long) long → BigInteger.valueOf(Long.MAX_VALUE).multiply(BigInteger.TWO) 18446744073709551614
pow(n) 거듭제곱 BigInteger.TWO.pow(100) 1267650600228229401496703205376
팩토리얼 reduce 아래 코드 4 265252859812191058636308480000000
mod/gcd/isProbablePrime/modPow/sqrt 정수론 아래 코드 5 17 true
new BigInteger("ff", 16) / toString(2) 진법 new BigInteger("ff", 16) + " " + BigInteger.TEN.toString(2) 255 1010
longValueExact() / bitLength() 변환/크기 아래 코드 6 5 3

금액 계산 규칙 요약:

규칙 이유 예제 결과
문자열 생성자 사용 double 생성자는 오차 new BigDecimal("0.1") 0.1
나눗셈에는 항상 scale+RoundingMode 무한소수 예외 방지 divide(x, 2, HALF_UP) 3.33
비교는 compareTo equals는 scale 비교 a.compareTo(b) == 0 값 동일 여부
최종 표시 직전에만 반올림 중간 반올림 누적 오차 total.setScale(0, HALF_UP) 12346
반올림 모드 명시 (업무 규정) 세금은 절사, 이자는 HALF_UP 등 new BigDecimal("12345.67").setScale(-2, DOWN).toPlainString() 12300
분배 시 잔액 처리 3등분 후 합이 원금과 다름 100 ÷ 3 = 33.33, ×3 = 99.99 잔액 0.01을 한 곳에 몰아줌
할인 = 원금 × (1 − 율) 두 번 반올림 회피 19900 × 0.85 → HALF_UP 16915

표 칸이 길어 아래로 옮긴 예제입니다.

java
// 아래 코드 1: 지수 표기 ↔ 평문 문자열
new BigDecimal("1E+3").toPlainString(); // "1000"
new BigDecimal("0.0000001"); // toString() → "1E-7"

// 아래 코드 2: 소수점 이동/10의 거듭제곱
new BigDecimal("12345").movePointLeft(2); // 123.45
new BigDecimal("1.5").scaleByPowerOfTen(2); // 1.5E+2

// 아래 코드 3: 문자열 스트림 → BigDecimal 합계
Stream.of("1.1", "2.2", "3.3")
    .map(BigDecimal::new)
    .reduce(ZERO, BigDecimal::add); // 6.6

// 아래 코드 4: 30!을 BigInteger로 계산
IntStream.rangeClosed(1, 30)
    .mapToObj(BigInteger::valueOf)
    .reduce(ONE, BigInteger::multiply);

// 아래 코드 5: 최대공약수 + 소수 판별
new BigInteger("17").gcd(BigInteger.valueOf(51))
    + " " + new BigInteger("17").isProbablePrime(10); // "17 true"

// 아래 코드 6: long 변환 + 비트 길이
new BigInteger("5").longValueExact() + " " + new BigInteger("5").bitLength();
08Random · SecureRandom · UUID
메서드/시그니처 설명 한 줄 예제 결과
new Random(seed) 시드 지정 (재현 가능) new Random(42).nextInt(100) (두 번 생성) 30, 30
nextInt(bound) [0, bound) new Random(1).nextInt(10) 5
nextInt(origin, bound) [origin, bound) (JDK 17+) new Random(1).nextInt(5, 10) 5
nextDouble() / nextBoolean() / nextLong() 기타 new Random(1).nextDouble() 0.7308781907032909
nextGaussian() 정규분포 (평균 0, 표준편차 1) new Random(1).nextGaussian() 1.5616
ints(n, a, b) / doubles(n) 스트림 new Random(7).ints(5, 1, 7).boxed().toList() [5, 3, 4, 5, 5]
Math.random() [0, 1) (int) (Math.random() * 6) + 1 1~6
ThreadLocalRandom.current().nextInt(a, b) 멀티스레드용 (경합 없음) ThreadLocalRandom.current().nextInt(1, 7) 1~6
new SecureRandom() 암호학적 난수 (토큰, 비밀번호) new SecureRandom().nextInt(100) 0~99
SecureRandom.nextBytes(byte[]) 랜덤 바이트 byte[] b=new byte[16];sr.nextBytes(b);HexFormat.of().formatHex(b) 32자 hex
토큰 생성 Base64 URL-safe Base64.getUrlEncoder().withoutPadding().encodeToString(24바이트) 32자
RandomGenerator.of("L64X128MixRandom") 신형 생성기 (JDK 17+) RandomGenerator.of("L64X128MixRandom").nextInt(10) 0~9
Collections.shuffle(list, rnd) 섞기 shuffle(l, new Random(3)) (1,2,3,4) [2, 1, 4, 3]
랜덤 원소 get(nextInt(size)) l.get(new Random(3).nextInt(l.size())) (a,b,c) c
랜덤 문자열 문자 집합에서 뽑기 "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" 6자 (Random(5)) ZFCVR8
UUID.randomUUID() v4 랜덤 u.toString().length() + " v" + u.version() 36 v4
UUID.fromString(s) 파싱 UUID.fromString("123e4567-e89b-12d3-a456-426614174000").version() 1
하이픈 제거 32자 UUID.randomUUID().toString().replace("-", "").length() 32
UUID.nameUUIDFromBytes(bytes) v3 (MD5 기반, 결정적) UUID.nameUUIDFromBytes("hello".getBytes()) 5d41402a-bc4b-3a76-b971-9d911017c592
getMostSignificantBits() / getLeastSignificantBits() 64비트 둘 Long.toHexString(u.getMostSignificantBits()) 123e4567e89b12d3
compareTo / equals 비교 u.compareTo(UUID.fromString("...4001")) -1
  • 보안이 필요한 곳(세션 ID, 비밀번호 재설정 토큰)에 Random/Math.random을 쓰지 않는다. 시드가 예측 가능하다.
  • Random을 공유하면 스레드 경합이 생긴다. 멀티스레드는 ThreadLocalRandom.
09System · Objects · Runtime · Thread 유틸
메서드/시그니처 설명 한 줄 예제 결과
System.currentTimeMillis() epoch ms (벽시계, 조정될 수 있음) System.currentTimeMillis() > 1_700_000_000_000L true
System.nanoTime() 경과 시간 전용 (절대값 의미 없음) long s = nanoTime(); work(); (nanoTime() - s) / 1_000_000 ms
System.getenv(name) 환경 변수 (없으면 null) System.getenv("NO_SUCH_ENV_VAR_XYZ") null
System.getenv() 전체 Map (불변) System.getenv().size() > 0 true
System.getProperty(key) 시스템 프로퍼티 아래 코드 1 21.0.8 Windows 11
System.getProperty(key, default) 기본값 System.getProperty("no.such", "def") def
주요 키 user.dir, user.home, file.separator, java.io.tmpdir 등 System.getProperty("line.separator") \r\n (Windows)
System.setProperty(k, v) 설정 (-Dk=v와 동일) System.setProperty("my.flag", "on"); System.getProperty("my.flag") on
System.lineSeparator() 개행 System.lineSeparator() \r\n / \n
System.exit(code) JVM 종료 (0 정상, finally 실행 안 됨) System.exit(1) 셸 $?=1
System.arraycopy(src, sp, dst, dp, len) 배열 복사 arraycopy({1,2,3}, 0, b, 0, 3) [1, 2, 3]
System.identityHashCode(o) 참조 기반 해시 System.identityHashCode("a") > 0 true
System.in/out/err 표준 스트림 System.err.println("error") stderr
System.console() 콘솔 (IDE/파이프에서 null) System.console() null (IDE)
Objects.requireNonNull(o, msg) null이면 NPE (생성자 검증) this.name = Objects.requireNonNull(name, "name") NullPointerException: name
Objects.requireNonNull(o, supplier) 메시지 지연 생성 requireNonNull(null, () -> "lazy msg") NullPointerException: lazy msg
Objects.requireNonNullElse(o, default) null 대체 (JDK 9+) Objects.requireNonNullElse(null, "default") default
Objects.requireNonNullElseGet(o, supplier) 지연 대체 Objects.requireNonNullElseGet(null, () -> "supplied") supplied
Objects.equals(a, b) null-safe Objects.equals(null, null) + " " + Objects.equals("a", null) true false
Objects.deepEquals(a, b) 배열 내용 Objects.deepEquals(new int[]{1}, new int[]{1}) true (equals는 false)
Objects.hash(a, b, ...) 복합 해시 (hashCode 구현용) Objects.hash(1, "a", null) 33759
Objects.hashCode(o) null → 0 Objects.hashCode(null) + " " + Objects.hashCode("a") 0 97
Objects.toString(o) / toString(o, default) null-safe Objects.toString(null, "-") -
Objects.isNull(o) / nonNull(o) Predicate용 Stream.of("a", null).filter(Objects::nonNull).toList() [a]
Objects.compare(a, b, cmp) null 둘 다면 0 Objects.compare(null, null, naturalOrder()) 0
Objects.checkIndex(i, len) 범위 검사 (JDK 9+) Objects.checkIndex(5, 3) IndexOutOfBoundsException: Index 5 out of bounds for length 3
Runtime.getRuntime().availableProcessors() CPU 수 (스레드풀 크기) availableProcessors() 8 등
maxMemory() / totalMemory() / freeMemory() 힙 (바이트) rt.maxMemory() / 1024 / 1024 + "MB" 4042MB 등
사용 중 메모리 total - free rt.totalMemory() - rt.freeMemory() 바이트
Runtime.version() JDK 버전 Runtime.version().feature() + " " + Runtime.version() 21 21.0.8+12-LTS-250
System.gc() GC 힌트 (보장 없음) System.gc() 힌트
addShutdownHook(Thread) 종료 훅 (배치 정리) Runtime.getRuntime().addShutdownHook(new Thread(() -> log("bye"))) 종료 시 실행
new ProcessBuilder(cmd...).start() 외부 프로세스 아래 코드 2 hi exit=0
ProcessHandle.current().pid() 현재 PID ProcessHandle.current().pid() > 0 true
ManagementFactory.getRuntimeMXBean().getUptime() JVM 가동 시간 ms 왼쪽 >= 0
Thread.currentThread() 현재 스레드 .getName() + " " + .isDaemon() main false
Thread.sleep(ms) 대기 (InterruptedException) Thread.sleep(20) 20ms 이상 대기
new Thread(runnable, name).start() / join() 생성·시작·대기 th.start(); th.join(); th.getState() TERMINATED
Thread.ofVirtual().start(r) 가상 스레드 (JDK 21) Thread.ofVirtual().start(() -> {}).isVirtual() true
Executors.newFixedThreadPool(n) + submit 스레드풀 (JDK 19+ try-with-resources) try(var ex=newFixedThreadPool(2)){ex.submit(()->6*7).get();} 42
CompletableFuture.supplyAsync(s).thenApply(f).join() 비동기 체인 supplyAsync(() -> 2).thenApply(x -> x * 10).join() 20
Thread.interrupted() / isInterrupted() 인터럽트 플래그 (전자는 초기화) currentThread().interrupt(); interrupted() + " " + isInterrupted() true false
AtomicInteger.incrementAndGet() 원자 카운터 아래 코드 3 1000
synchronized (lock) { } 임계 영역 synchronized (lock) { counter++; } 상호 배제
TimeUnit.MINUTES.toSeconds(n) 단위 변환 아래 코드 4 120 2

표 칸이 길어 아래로 옮긴 예제입니다.

java
// 아래 코드 1: 시스템 프로퍼티 두 개 조회
System.getProperty("java.version") + " " + System.getProperty("os.name");

// 아래 코드 2: 외부 프로세스 실행 후 출력·종료 코드 확인
new ProcessBuilder("cmd", "/c", "echo hi")
    .redirectErrorStream(true).start(); // 출력 확인은 waitFor() 이후

// 아래 코드 3: 병렬 스트림에서 원자 카운터 증가
IntStream.range(0, 1000).parallel()
    .forEach(k -> ai.incrementAndGet());
ai.get(); // 1000

// 아래 코드 4: 시간 단위 변환
TimeUnit.MINUTES.toSeconds(2)
    + " " + TimeUnit.MILLISECONDS.toMinutes(150_000); // "120 2"
10정규식 치트표
문법 의미 한 줄 예제 결과
. 개행 제외 아무 문자 "a\nb".matches("a.b") false ((?s)면 true)
\d / \D 숫자 / 비숫자 "010-1234".replaceAll("\\D", "") 0101234
\w / \W [a-zA-Z0-9_] / 그 외 "a b!".replaceAll("\\W", "_") a_b_
\s / \S 공백 / 비공백 "a b".replaceAll("\\s", "_") a_b
[abc] / [^abc] / [a-z] 문자 클래스 / 부정 / 범위 "010-1234-5678".replaceAll("[^0-9]", "") 01012345678
[가-힣] 한글 음절 "홍길동".matches("^[가-힣]{2,5}
quot;)
true
\p{L} / \p{Digit} / \p{IsHangul} 유니코드 속성 "café".matches("\\p{L}+") + " " + "가".matches("\\p{IsHangul}") true true
\p{Alpha} / \p{Space} / \p{Punct} POSIX 클래스 "ab12".replaceAll("\\p{Alpha}", "") 12
^ / $ 줄 시작/끝 ((?m)이면 각 줄) Pattern.compile("^w", MULTILINE).matcher("a\nworld").find() true
\b / \B 단어 경계 / 비경계 "cat category".replaceAll("\\bcat\\b", "dog") dog category
* / + / ? 0+ / 1+ / 0~1 "ab".matches("ab?c?") true
{n} / {n,} / {n,m} 횟수 "aaaa".replaceAll("a{2,3}", "X") Xa
*? / +? / ?? 비탐욕 "<a><b>".replaceAll("<.*?>", "X") vs "<.*>" XX vs X
(...) / \1 / $1 그룹 / 역참조 / 치환 참조 "aa bb cd".replaceAll("(\\w)\\1", "<$0>") <aa> <bb> cd
(?<name>...) / ${name} 이름 그룹 아래 코드 1 17.05.2024
(?:...) 비캡처 그룹 "ab".matches("(?:a|b)+") true
a|b OR "cat".matches("cat|dog") true
(?=x) / (?!x) 전방 탐색 긍정/부정 아래 코드 2 true (비밀번호 규칙)
(?<=x) / (?<!x) 후방 탐색 "price: $100".replaceAll("(?<=\\$)\\d+", "N") price: $N
(?i) / (?s) / (?m) / (?x) 대소문자 무시 / DOTALL / MULTILINE / 주석 허용 "HELLO".matches("(?i)hello") true
split("(?<=\\d)") 구분자 유지 분할 "a1b2".split("(?<=\\d)") [a1, b2]
Pattern.quote(s) 리터럴 이스케이프 Pattern.quote("a.b") \Qa.b\E
전화번호 ^01[016789]-?\d{3,4}-?\d{4}$ "010-1234-5678".matches(...) true
이메일 (실용) ^[\w.+-]+@[\w-]+(\.[\w-]+)+$ "a.b+c@ex-ample.co.kr".matches(...) true
날짜 yyyy-MM-dd ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ "2024-03-15".matches(...) true (2/30은 못 거름 → LocalDate.parse)
IPv4 ^((25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(25[0-5]|2[0-4]\d|1?\d?\d)$ "192.168.0.1".matches(...) true
사업자번호 ^\d{3}-\d{2}-\d{5}$ "123-45-67890".matches(...) true

표 칸이 길어 아래로 옮긴 예제입니다.

java
// 아래 코드 1: 이름 그룹으로 날짜 형식 바꾸기
"2024-05-17".replaceAll(
    "(?<y>\\d{4})-(?<m>\\d{2})-(?<d>\\d{2})", "${d}.${m}.${y}"); // "17.05.2024"

// 아래 코드 2: 전방 탐색으로 비밀번호 규칙 검사
"Abcdef1!".matches(
    "^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[^\\w\\s]).{8,}$"); // true
11실무 스니펫

스니펫 1: 영업일 계산 (주말·공휴일 제외)

datesUntil로 날짜 스트림을 만들어 주말과 공휴일 Set을 걸러 센다. N영업일 후 날짜는 하루씩 전진하며 영업일만 카운트하고, 다음 영업일은 영업일이 될 때까지 전진한다. 공휴일은 DB나 설정 파일에서 Set<LocalDate>로 읽어오면 된다.

java
static boolean isBusinessDay(LocalDate x, Set<LocalDate> holidays) {
    DayOfWeek w = x.getDayOfWeek();
    return w != DayOfWeek.SATURDAY && w != DayOfWeek.SUNDAY && !holidays.contains(x);
}
static long businessDaysBetween(LocalDate from, LocalDate toInclusive, Set<LocalDate> holidays) {
    return from.datesUntil(toInclusive.plusDays(1)).filter(x -> isBusinessDay(x, holidays)).count();
}
static LocalDate addBusinessDays(LocalDate date, int days, Set<LocalDate> holidays) {
    LocalDate cur = date; int added = 0;
    while (added < days) { cur = cur.plusDays(1); if (isBusinessDay(cur, holidays)) added++; }
    return cur;
}
static LocalDate nextBusinessDay(LocalDate x, Set<LocalDate> holidays) {
    LocalDate c = x;
    while (!isBusinessDay(c, holidays)) c = c.plusDays(1);
    return c;
}

businessDaysBetween(LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 31), Set.of(LocalDate.of(2024, 3, 1)));
// 출력: 20   (3월 평일 21일 - 삼일절)
addBusinessDays(LocalDate.of(2024, 3, 15), 3, Set.of());          // 금요일 + 3영업일
// 출력: 2024-03-20
nextBusinessDay(LocalDate.of(2024, 3, 16), Set.of(LocalDate.of(2024, 3, 18)));   // 토요일, 월요일 휴일
// 출력: 2024-03-19

스니펫 2: 나이 계산 (만 나이 / 세는 나이)

만 나이는 Period.between(birth, today).getYears(). 생일이 지났는지 자동으로 반영된다. 세는 나이(한국식)는 올해 - 출생년 + 1.

java
static int age(LocalDate birth, LocalDate today) { return Period.between(birth, today).getYears(); }

LocalDate today = LocalDate.of(2024, 3, 15);
age(LocalDate.of(1990, 5, 20), today);   // 출력: 33 (생일 전)
age(LocalDate.of(1990, 3, 15), today);   // 출력: 34 (생일 당일)
age(LocalDate.of(1990, 3, 16), today);   // 출력: 33 (생일 하루 전)
today.getYear() - 1990 + 1;              // 출력: 35 (세는 나이)

스니펫 3: 기간 포맷 (초 → hh:mm:ss, 사람이 읽는 형식)

총 초에서 / 3600, % 3600 / 60, % 60으로 나누거나, Duration의 toHours()(총량) + toMinutesPart()/toSecondsPart()(자릿수)를 쓴다. 100시간을 넘어도 %02d는 자릿수를 늘려 표시한다.

java
static String hms(long totalSec) {
    return String.format("%02d:%02d:%02d", totalSec / 3600, (totalSec % 3600) / 60, totalSec % 60);
}
static String hms(Duration d) {
    return String.format("%02d:%02d:%02d", d.toHours(), d.toMinutesPart(), d.toSecondsPart());
}
static String human(Duration d) {
    if (d.toDays() > 0) return d.toDays() + "일 " + d.toHoursPart() + "시간 " + d.toMinutesPart() + "분";
    if (d.toHours() > 0) return d.toHours() + "시간 " + d.toMinutesPart() + "분";
    if (d.toMinutes() > 0) return d.toMinutes() + "분 " + d.toSecondsPart() + "초";
    return d.toMillis() / 1000.0 + "초";
}

hms(3725);  hms(59);  hms(360000);  hms(0);
// 출력: 01:02:05  00:00:59  100:00:00  00:00:00
hms(Duration.ofSeconds(3725));                 // 출력: 01:02:05
human(Duration.ofSeconds(93784));              // 출력: 1일 2시간 3분
human(Duration.ofMillis(1500));                // 출력: 1.5초

스니펫 4: 금액 반올림·절사·할인·분배

소수 2자리 HALF_UP이 기본 규칙. 원화는 setScale(0), 100원 단위 절사는 setScale(-2, DOWN). 할인은 원금 × (1 − 율)로 한 번만 반올림. 3등분처럼 나눠떨어지지 않는 분배는 DOWN으로 나눈 뒤 잔액을 마지막 항목에 더한다.

java
static BigDecimal roundMoney(BigDecimal v) { return v.setScale(2, RoundingMode.HALF_UP); }

roundMoney(new BigDecimal("1234.567"));   // 출력: 1234.57
roundMoney(new BigDecimal("0.005"));      // 출력: 0.01
new BigDecimal("12345.67").setScale(0, RoundingMode.HALF_UP);                    // 출력: 12346
new BigDecimal("12345.67").setScale(-2, RoundingMode.DOWN).toPlainString();      // 출력: 12300
new BigDecimal("12345").multiply(new BigDecimal("0.1")).setScale(0, RoundingMode.HALF_UP);   // 출력: 1235 (10%)
new BigDecimal("19900").multiply(BigDecimal.ONE.subtract(new BigDecimal("0.15"))).setScale(0, RoundingMode.HALF_UP);
// 출력: 16915 (15% 할인)

BigDecimal total = new BigDecimal("100");
BigDecimal share = total.divide(new BigDecimal("3"), 2, RoundingMode.DOWN);   // 33.33
BigDecimal remainder = total.subtract(share.multiply(new BigDecimal("3")));   // 0.01
// 출력: [33.33, 33.33, 33.34]  (마지막에 잔액 합산)

스니펫 5: 배치 실행일자 파일명과 처리 기간 계산

배치 잡은 보통 yyyyMMdd 인자를 받는다. BASIC_ISO_DATE로 파싱하고 전일/당월 범위를 계산한다. 파일명에는 실행 시각을 yyyyMMdd_HHmmss로 붙여 재실행 시 충돌을 피한다. 일 배치의 조회 범위는 [전일 00:00, 당일 00:00) 반개구간으로 잡는다.

java
static String batchFileName(String job, LocalDateTime runAt) {
    return job + "_" + runAt.format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) + ".csv";
}

batchFileName("settle", LocalDateTime.of(2024, 3, 15, 2, 0, 0));
// 출력: settle_20240315_020000.csv

String arg = "20240315";
LocalDate bd = LocalDate.parse(arg, DateTimeFormatter.BASIC_ISO_DATE);
bd + " prev=" + bd.minusDays(1) + " ym=" + YearMonth.from(bd);
// 출력: 2024-03-15 prev=2024-03-14 ym=2024-03

LocalDateTime from = bd.minusDays(1).atStartOfDay(), to = bd.atStartOfDay();
// 출력: 2024-03-14T00:00 ~ 2024-03-15T00:00   (SQL: created_at >= from AND created_at < to)

YearMonth ym = YearMonth.of(2024, 2);
ym.atDay(1) + " ~ " + ym.atEndOfMonth();
// 출력: 2024-02-01 ~ 2024-02-29

스니펫 6: 소요 시간 측정 헬퍼

System.nanoTime() 차이로 잰다(currentTimeMillis는 시계 조정에 영향받음). 제네릭 timed(label, supplier)로 감싸면 결과와 시간을 함께 얻는다. Instant 둘의 차이는 Duration.between.

java
static <T> T timed(String label, Supplier<T> task) {
    long start = System.nanoTime();
    T result = task.get();
    long ms = (System.nanoTime() - start) / 1_000_000;
    System.out.println(label + " took " + ms + " ms");
    return result;
}

int size = timed("sort", () -> {
    var l = new ArrayList<>(new Random(1).ints(100_000).boxed().toList());
    Collections.sort(l);
    return l.size();
});
// 출력: sort took 40 ms  (환경에 따라 다름), size = 100000

Instant s = Instant.now();
// ... 작업 ...
Duration.between(s, Instant.now()).toMillis() + "ms";   // 출력: 1234ms 형태

long t0 = System.nanoTime();
long sum = 0; for (int k = 0; k < 1_000_000; k++) sum += k;
(System.nanoTime() - t0) / 1_000_000;                   // 출력: N (ms)

스니펫 7: 만료 검사, 같은 날 판정, 로그 타임스탬프

토큰 만료는 발급시각.plusMinutes(n).isBefore(now). 같은 날인지는 toLocalDate().equals. 로그는 밀리초까지, JSON은 UTC Instant.

java
LocalDateTime issued = LocalDateTime.of(2024, 3, 15, 10, 0);
issued.plusMinutes(30).isBefore(LocalDateTime.of(2024, 3, 15, 10, 31));   // 출력: true (만료)

dt.toLocalDate().equals(dt.plusHours(5).toLocalDate());                    // 출력: true

dt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));        // 출력: 2024-03-15 09:30:05.000
ZonedDateTime z = dt.atZone(ZoneId.of("Asia/Seoul"));
z.toInstant().toString();                                                  // 출력: 2024-03-15T00:30:05Z
z.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);                          // 출력: 2024-03-15T09:30:05+09:00
12자주 하는 실수

❌ 실수 1: MM(월)과 mm(분) 혼동

java
dt.format(DateTimeFormatter.ofPattern("yyyy-mm-dd"));   // 2024-30-15  (분이 들어감)
dt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));   // 2024-03-15
// HH=24시, hh=12시(a 필요), DD=연중일, dd=일

❌ 실수 2: new BigDecimal(double)

java
new BigDecimal(0.1);          // 0.1000000000000000055511151231257827021181583404541015625
new BigDecimal("0.1");        // 0.1   ← 문자열 생성자
BigDecimal.valueOf(0.1);      // 0.1   (double이 이미 있을 때 차선)

❌ 실수 3: BigDecimal.equals로 값 비교

java
new BigDecimal("1.0").equals(new BigDecimal("1.00"));     // false (scale 다름)
new BigDecimal("1.0").compareTo(new BigDecimal("1.00"));  // 0     ← 값 비교
amount.compareTo(BigDecimal.ZERO) == 0;                  // 0원 검사 (equals(ZERO)는 "0.00"에서 실패)

❌ 실수 4: divide에 scale 없이 무한소수

java
new BigDecimal("10").divide(new BigDecimal("3"));                          // ArithmeticException
new BigDecimal("10").divide(new BigDecimal("3"), 2, RoundingMode.HALF_UP); // 3.33

❌ 실수 5: Period.getDays()를 총 일수로 사용 / Duration에 LocalDate

java
Period.between(LocalDate.of(2024, 1, 1), LocalDate.of(2024, 3, 1)).getDays();   // 0 (P2M)
ChronoUnit.DAYS.between(LocalDate.of(2024, 1, 1), LocalDate.of(2024, 3, 1));     // 60
Duration.between(d, d.plusDays(1));   // UnsupportedTemporalTypeException: Unsupported unit: Seconds

❌ 실수 6: Math.round의 음수·.5 동작과 int 나눗셈

java
Math.round(2.5);    // 3
Math.round(-2.5);   // -2  (HALF_UP이 아니라 +0.5 후 floor)
Math.rint(2.5);     // 2.0 (짝수 반올림)
7 / 2;              // 3   (int 나눗셈)
7 / 2.0;            // 3.5
(-7) % 3;           // -1  (양수 나머지가 필요하면 Math.floorMod(-7, 3) = 2)

❌ 실수 7: LocalDateTime으로 타임존이 필요한 값을 저장

java
LocalDateTime.now();                          // 서버 존에 따라 다른 의미
Instant.now();                                // 절대 순간 (저장·전송용)
ZonedDateTime.now(ZoneId.of("Asia/Seoul"));   // 표시용
z.withZoneSameLocal(other);                   // 순간이 바뀜 — 변환은 withZoneSameInstant

❌ 실수 8: STRICT 파싱에 yyyy 사용 / 파싱 예외 미처리

java
LocalDate.parse("2024-02-10", ofPattern("yyyy-MM-dd").withResolverStyle(STRICT));   // 예외 (era 없음)
LocalDate.parse("2024-02-10", ofPattern("uuuu-MM-dd").withResolverStyle(STRICT));   // 2024-02-10
LocalDate.parse(userInput);   // DateTimeParseException(unchecked) — 외부 입력은 try/catch

❌ 실수 9: SimpleDateFormat을 static으로 공유 / Calendar.MONTH 0-based

java
static final SimpleDateFormat F = new SimpleDateFormat("yyyy-MM-dd");   // 멀티스레드에서 값 섞임
static final DateTimeFormatter F = DateTimeFormatter.ofPattern("yyyy-MM-dd");   // 불변, 안전
cal.get(Calendar.MONTH);   // 1월 = 0

❌ 실수 10: 보안 토큰에 Random / 경과 시간에 currentTimeMillis

java
new Random().nextInt();               // 예측 가능 → 토큰/비밀번호에 금지
new SecureRandom().nextBytes(b);      // 암호학적 난수
long t = System.currentTimeMillis(); ...; System.currentTimeMillis() - t;   // 시계 조정 시 음수 가능
long t = System.nanoTime(); ...; System.nanoTime() - t;                     // 경과 시간 전용
13관련 레슨
  • 중급 04 java.lang 심화: Wrapper 캐시, Math 정적 유틸, Integer.parseInt
  • 초급 01 변수·데이터 타입·형변환: double 오차, 정수 오버플로, 형변환
  • 고급 02 멀티스레드: Thread, ExecutorService, AtomicInteger, synchronized, 가상 스레드
  • 고급 03 람다: Supplier로 지연 평가(orElseGet, requireNonNullElseGet, timed)
  • 배치 01 아키텍처: 실행일자 파라미터, 파일명 규칙, shutdown hook
  • 배치 04 트랜잭션: BigDecimal 정산 금액 계산과 반올림 규정
  • 미니 프로젝트 2단계: Money 값 객체(BigDecimal 래핑)
  • 명령어 01 String: String.format, 정규식 Pattern/Matcher 상세
목차
  • 한눈에 보기
  • java.time 생성·조회·계산
  • TemporalAdjusters · 비교 · 기간 (Period / Duration / ChronoUnit)
  • DateTimeFormatter 패턴표 · 파싱
  • 타임존 · Instant · epoch · 레거시 변환
  • Math · 숫자 기본
  • BigDecimal · BigInteger (금액 계산 규칙)
  • Random · SecureRandom · UUID
  • System · Objects · Runtime · Thread 유틸
  • 정규식 치트표
  • 실무 스니펫
  • 자주 하는 실수
  • 관련 레슨
참고 영상 · 인터넷 연결 시 유튜브 검색이 열립니다자바 java.time · BigDecimal · 기타 유틸명령어 LocalDate LocalDateTime Duration
이전04 Files · Path · I/O다음06 Oracle SQL