Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[모던 자바 인 액션] 6주차 #8

Open
so3500 opened this issue Jul 28, 2023 · 3 comments
Open

[모던 자바 인 액션] 6주차 #8

so3500 opened this issue Jul 28, 2023 · 3 comments
Assignees
Labels
SummerCoding 땅울림 여름코딩 스터디 모던 자바 인 액션

Comments

@so3500
Copy link
Contributor

so3500 commented Jul 28, 2023

스터디 날짜

2023.08.04 금 9:00-10:00

내용

챕터11. 널 대신 옵셔널 클래스
챕터12 새로운 날짜와 시간 API

공유

최승위

이성온

정민교

@so3500 so3500 added SummerCoding 땅울림 여름코딩 스터디 모던 자바 인 액션 labels Jul 28, 2023
@jeongminkyo
Copy link

자바 8 이전의 날짜와 시간 API의 문제들

Date date = new Date(117, 8, 21) // Thu Sep 21 00:00:00 CET 2017
  • java.util.Date 클래스는 모호한 설계, 직관적이지 못하며 자체적으로 시간대를 가지고 있지도 않는다.
  • Date를 deprecated 시키고 등장한 Calendar 클래스 또한 달의 index를 0부터 시작되는 등 쉽게 에러를 일으키는 설계 문제를 갖고 있다.
  • Date와 Calendar 두 가지 클래스가 등장하면서 개발자들에게 혼란만 가중되었다.
  • 날짜와 시간을 파싱하는데 등장한 DateFormat은 Date에만 지원되었으며, 스레드에 안전하지 못했다.
  • Date와 Calendar는 모두 가변 클래스이므로 유지보수가 아주 어렵다.

LocalDate와 LocalTime

LocalDate 인스턴스는 시간을 제외한 날짜를 표현하는 불변 객체다. LocalDate 객체는 어떤 시간대 정보도 포함하지 않는다. 정적 팩토리 메서드 of으로 LocalDate 인스턴스를 만들 수 있다.

LocalDate date = LocalDate.of(2020, 12, 22); // of
int year = date.getYear();
Month month = date.getMonth();
int day = date.getDayOfMonth();
LocalDate now = LocalDate.now(); // 현재 날짜 정보

시간에 대한 정보는 LocalTime 클래스로 표현할 수 있다. LocalTime도 정적 메서드 of로 인스턴스를 만들 수 있다.

LocalTime time = LocalTime.of(13, 45, 20); // 13:45:20
int hour = time.getHour();
int minute = time.getMinute();
int second = time.getSecond();

날짜와 시간 조합

LocalDateTime은 LocalDate와 LocalTime을 쌍으로 갖는 복합 클래스다. 날짜와 시간을 모두 표현할 수 있으며 정적 메서드 of로 인스턴스 또한 만들 수 있다.

LocalDateTime dateTime = LocalDateTime.of(2020, Month.DECEMBER, 22, 13, 45, 20);
LocalDateTime dateTime2 = LocalDateTime.of(date, time);

지금까지 살펴본 모든 클래스는 불변이다. 함수형 프로그래밍, 스레드 안정성과 도메인 모델의 일관성을 유지하는데 좋다.

날짜와 시간 객체 출력과 파싱

날짜와 시간 관련 작업에서 포매팅과 파싱은 필수적이다. java.time.format 패키지가 이를 지원한다.

parse 메서드를 통해 날짜와 시간 문자열로 LocalDate와 LocalTime의 인스턴스를 만들 수 있다.

LocalDate date = LocalDate.parse("2020-12-22");
LocalTime time = LocalTime.parse("13:45:20");

가장 중요하게 알아야 할 클래스는 DateTimeFormatter이다. 정적 팩토리 메서드와 상수를 이용해서 손쉽게 포매터를 만들 수 있다.

LocalDate date = LocalDate.of(2014, 3, 18);
String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE); // 20140318
String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE); // 2014-03-18

기존 java.util.DateFormat 클래스와 달리 모든 DateTimeFormatter는 스레드에서 안전하게 사용할 수 있는 클래스다.

또한 DateTimeFormatter 클래스는 특정 패턴으로 포매터를 만들 수 있는 정적 팩토리 메소드도 제공한다.

DateTimeFormatter formatter = DateTimeFormatter.ofPatterm("dd/MM/yyyy");
LocalDate date = LocalDate.of(2014, 3, 18);
String formattedDate = date1.format(formatter);
LocalDate date2 = LocalDate.parse(formattedDate, formatter);

시간대 사용하기

표준이 같은 지역을 묶어서 시간대(time zone) 규칙 집합을 정의한다. ZoneRules 클래스에는 약 40개 정도의 시간대가 있다. ZoneId의 getRules()를 이용해서 해당 시간대의 규정을 획득할 수 있다.

ZoneId romeZone = ZoneId.of("Europe/Rome");

지역 ID는 '{지역}/{도시}' 형식으로 이루어 진다. 지역 집합 정보는 [IANA Time Zone Database](https://www.iana.org/time-zones)에서 제공하는 정보를 사용한다. getDefault() 메서드를 이용하면 기존의 TimeZone 객체를 ZoneId 객체로 변환할 수 있다.

ZoneId zoneId = TimeZone.getDefault().toZoneId();

ZoneId는 LocalDate, LocalTime, LocalDateTime과 같이 ZonedDateTime 인스턴스로 변환할 수 있다.

LocalDate date = LocalDate.of(2014, 13, 18);
ZonedDateTime zdt = date.atStartOfDay(romeZone);

UTC/Greenwich 기준의 고정 오프셋

때로는 UTC/GMT 를 기준으로 시간대를 표현한다. ZoneId의 서브클래스인 ZoneOffset 클래스로 런던의 그리니치 0도 자오선과 시간값의 차이를 표현할 수 있다. 서머 타임을 처리할 수 없으므로 권장하지 않는다.

ZoneOffset newYorkOffset = ZoneOffset.of("-05:00");

대안 캘린더 시스템 사용하기

ISO-8601 캘린더 시스템이 실질적으로 전 세계에서 통용되지만, 자바 8에서는 추가로 ThaiBuddhistDate, MinguoDate, JapaneseDate, HijrahDate가 추가되었다.

@so3500
Copy link
Contributor Author

so3500 commented Aug 3, 2023

import static org.assertj.core.api.AssertionsForClassTypes.*;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

class DateTest {

	@DisplayName("duration 은 두 시간 사이의 간격을 나타낼 때 사용한다.")
	@Test
	void durationTest() {
		LocalTime lunchStartTime = LocalTime.of(11, 30);
		LocalTime lunchEndTime = lunchStartTime.plusHours(1).plusMinutes(30);

		Duration duration = Duration.between(lunchStartTime, lunchEndTime);

		assertThat(duration.toMinutes()).isEqualTo(90);
		System.out.println(duration.toString()); // quiz: 출력값이 PT1H30M 인 이유는?
	}

	@DisplayName("period 은 두 날짜 사이의 간격을 나타낼 때 사용한다.")
	@Test
	void periodTest() {
		LocalDate holidayStartDate = LocalDate.now();
		LocalDate holidayEndDate = holidayStartDate.plusWeeks(3);

		Period period = Period.between(holidayStartDate, holidayEndDate);

		assertThat(period.getDays()).isEqualTo(21);
		System.out.println(period.toString()); // quiz: 출력값이 P21D 인 이유는?
	}
}

Duration, Period 출력값이 아래와 같을 때 주의할 점은?

  • PT1H30M, P21D, ...
  • hint: Serializable 인터페이스를 구현하고 있음

@s5646s
Copy link
Contributor

s5646s commented Aug 4, 2023


marp: true
theme: gaia
class: invert
paginate: true

Modern Java in Action

Week 6
발표자: 최승위


#이번 주 범위

  • 11장: Null 대신 Optional 클래스
  • 12장: 새로운 날짜와 시간 API

Java Optional vs Kotlin Nullable

  • 의도와 목적은 비슷한데..
  • 어떤 점이 다르려나?

선언되는 형태

  • Java's Optional
    • Optional<Integer> getAge();
  • Kotlin's Nullable
    • val age: Int?

안전하게 호출하는 방법

  • Java's Optional.map()
    • Optional<Integer> driversAge = car.map(Car::getDriver).flatMap(Person::getAge);
  • Kotlin's Safe-Call Operator(?.)
    • val driversAge: Int? = car?.driver?.age

안전하게 외부메서드를 활용하여 호출하는 방법

  • Java's Optional.map()
    • Optional<DriversLicence> driversLicence = car.map(Car::getDriver).map(licenceService::getDriversLicence);
  • Kotlin's Safe-Call Operator(?.)
    • val driversLicence: DriversLicence? = car?.driver?.let { licenceService.getDriversLicence(it) }

가져다 쓸 때 Null이라면 예비값 넣기

  • Java's Optional.orElse()
    • boolean isOfLegalAge = car.map(Car::getDriver).flatMap(Person::getAge).orElse(0) > 18;
  • Kotlin's 앨비스 연산자
    • val isOfLegalAge: Boolean = car?.driver?.age ?: 0 > 18

코틀린의 Nullable이 왜 더 좋은가?

  • 문법이 더 간결하다.
  • Optional과 같은 래퍼 객체를 만드는 과정이 필요하지 않다.
  • Nullable은 컴파일 타임에 오류를 탐지할 수 있다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
SummerCoding 땅울림 여름코딩 스터디 모던 자바 인 액션
Projects
None yet
Development

No branches or pull requests

3 participants