날짜/시간(
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 실행값이다.
| 메서드 | 설명 | 예제 | 결과 |
|---|---|---|---|
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 |
| 메서드/시그니처 | 설명 | 한 줄 예제 | 결과 |
|---|---|---|---|
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)의 반환값을 받아야 한다.getMonthValue()), 요일은 월요일=1. 레거시 Calendar는 월이 0부터라 혼동하기 쉽다.표 칸이 길어 아래로 옮긴 예제입니다.
// 아래 코드 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| 메서드/시그니처 | 설명 | 한 줄 예제 | 결과 |
|---|---|---|---|
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.| 패턴/상수 | 의미 | 한 줄 예제 | 결과 |
|---|---|---|---|
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). 외부 입력은 반드시 잡는다.표 칸이 길어 아래로 옮긴 예제입니다.
// 아래 코드 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));| 메서드/시그니처 | 설명 | 한 줄 예제 | 결과 |
|---|---|---|---|
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은 존 정보가 없어 서버 존이 바뀌면 의미가 달라진다.z.toInstant().toString()(2024-03-15T00:30:05Z) 또는 ISO_OFFSET_DATE_TIME.표 칸이 길어 아래로 옮긴 예제입니다.
// 존 포함 문자열을 파싱해 존 정보만 꺼내기
ZonedDateTime.parse("2024-03-15T09:30:05+09:00[Asia/Seoul]").getZone();| 메서드/시그니처 | 설명 | 한 줄 예제 | 결과 |
|---|---|---|---|
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 |
표 칸이 길어 아래로 옮긴 예제입니다.
// 아래 코드 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"));| 메서드/시그니처 | 설명 | 한 줄 예제 | 결과 |
|---|---|---|---|
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 |
표 칸이 길어 아래로 옮긴 예제입니다.
// 아래 코드 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();| 메서드/시그니처 | 설명 | 한 줄 예제 | 결과 |
|---|---|---|---|
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 |
Random/Math.random을 쓰지 않는다. 시드가 예측 가능하다.Random을 공유하면 스레드 경합이 생긴다. 멀티스레드는 ThreadLocalRandom.| 메서드/시그니처 | 설명 | 한 줄 예제 | 결과 |
|---|---|---|---|
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 |
표 칸이 길어 아래로 옮긴 예제입니다.
// 아래 코드 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"| 문법 | 의미 | 한 줄 예제 | 결과 |
|---|---|---|---|
. |
개행 제외 아무 문자 | "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} |
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 |
표 칸이 길어 아래로 옮긴 예제입니다.
// 아래 코드 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,}$"); // truedatesUntil로 날짜 스트림을 만들어 주말과 공휴일 Set을 걸러 센다. N영업일 후 날짜는 하루씩 전진하며 영업일만 카운트하고, 다음 영업일은 영업일이 될 때까지 전진한다. 공휴일은 DB나 설정 파일에서 Set<LocalDate>로 읽어오면 된다.
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만 나이는 Period.between(birth, today).getYears(). 생일이 지났는지 자동으로 반영된다. 세는 나이(한국식)는 올해 - 출생년 + 1.
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 (세는 나이)총 초에서 / 3600, % 3600 / 60, % 60으로 나누거나, Duration의 toHours()(총량) + toMinutesPart()/toSecondsPart()(자릿수)를 쓴다. 100시간을 넘어도 %02d는 자릿수를 늘려 표시한다.
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초소수 2자리 HALF_UP이 기본 규칙. 원화는 setScale(0), 100원 단위 절사는 setScale(-2, DOWN). 할인은 원금 × (1 − 율)로 한 번만 반올림. 3등분처럼 나눠떨어지지 않는 분배는 DOWN으로 나눈 뒤 잔액을 마지막 항목에 더한다.
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] (마지막에 잔액 합산)배치 잡은 보통 yyyyMMdd 인자를 받는다. BASIC_ISO_DATE로 파싱하고 전일/당월 범위를 계산한다. 파일명에는 실행 시각을 yyyyMMdd_HHmmss로 붙여 재실행 시 충돌을 피한다. 일 배치의 조회 범위는 [전일 00:00, 당일 00:00) 반개구간으로 잡는다.
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-29System.nanoTime() 차이로 잰다(currentTimeMillis는 시계 조정에 영향받음). 제네릭 timed(label, supplier)로 감싸면 결과와 시간을 함께 얻는다. Instant 둘의 차이는 Duration.between.
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)토큰 만료는 발급시각.plusMinutes(n).isBefore(now). 같은 날인지는 toLocalDate().equals. 로그는 밀리초까지, JSON은 UTC Instant.
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:00MM(월)과 mm(분) 혼동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=일new BigDecimal(double)new BigDecimal(0.1); // 0.1000000000000000055511151231257827021181583404541015625
new BigDecimal("0.1"); // 0.1 ← 문자열 생성자
BigDecimal.valueOf(0.1); // 0.1 (double이 이미 있을 때 차선)BigDecimal.equals로 값 비교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"에서 실패)divide에 scale 없이 무한소수new BigDecimal("10").divide(new BigDecimal("3")); // ArithmeticException
new BigDecimal("10").divide(new BigDecimal("3"), 2, RoundingMode.HALF_UP); // 3.33Period.getDays()를 총 일수로 사용 / Duration에 LocalDatePeriod.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: SecondsMath.round의 음수·.5 동작과 int 나눗셈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)LocalDateTime으로 타임존이 필요한 값을 저장LocalDateTime.now(); // 서버 존에 따라 다른 의미
Instant.now(); // 절대 순간 (저장·전송용)
ZonedDateTime.now(ZoneId.of("Asia/Seoul")); // 표시용
z.withZoneSameLocal(other); // 순간이 바뀜 — 변환은 withZoneSameInstantSTRICT 파싱에 yyyy 사용 / 파싱 예외 미처리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/catchSimpleDateFormat을 static으로 공유 / Calendar.MONTH 0-basedstatic final SimpleDateFormat F = new SimpleDateFormat("yyyy-MM-dd"); // 멀티스레드에서 값 섞임
static final DateTimeFormatter F = DateTimeFormatter.ofPattern("yyyy-MM-dd"); // 불변, 안전
cal.get(Calendar.MONTH); // 1월 = 0Random / 경과 시간에 currentTimeMillisnew Random().nextInt(); // 예측 가능 → 토큰/비밀번호에 금지
new SecureRandom().nextBytes(b); // 암호학적 난수
long t = System.currentTimeMillis(); ...; System.currentTimeMillis() - t; // 시계 조정 시 음수 가능
long t = System.nanoTime(); ...; System.nanoTime() - t; // 경과 시간 전용Math 정적 유틸, Integer.parseIntdouble 오차, 정수 오버플로, 형변환Thread, ExecutorService, AtomicInteger, synchronized, 가상 스레드Supplier로 지연 평가(orElseGet, requireNonNullElseGet, timed)BigDecimal 정산 금액 계산과 반올림 규정Money 값 객체(BigDecimal 래핑)String.format, 정규식 Pattern/Matcher 상세