모던 자바란?
- JDK 8 버전 이후의 자바를 의미
- 새로운 기능이 많이 추가됨
왜 배워야 하는가?
아니 할 것도 많은데, 굳이 현대문법까지?
- 코드가 더 짧고, 읽기 쉬워지고, 유지보수하기 좋아짐
- 병렬 처리를 쉽게 만들 수 있음
- 함수형 프로그래밍 패러다임의 이해
- 미래의 기술을 익히는데 도움이 된다는 뜻!
무엇을 배우는가?
- 람다식, 스트림, 컬렉션의 추가기능, Optional 클래스, 자바 모듈, 비동기 프로그래밍
- 아래의 텍스트에서 해당 주제들을 간단하게 살펴보자.
람다식
- 모던 자바에서는 함수도 파라미터로 쓸 수 있다.
- 그럼 뭐가 좋은데? 더 간결해짐.
- 어떻게 쓰면 돼?
- 메서드 참조
- 람다식
java
List<String> names = Arrays.asList("Kim", "Lee", "Park");
names.forEach(System.out::println); // 메서드 참조
names.forEach(name -> System.out.println(name)); // 람다식
스트림
- 반복문이 너무 길면 어떻게 할까?
- 마치 터미널의 '파이프'처럼 꼬리물기를 하면서 이걸 해결할 수 있다.
- 이를 스트림(stream)이라고 한다.
응용 : 멀티쓰레딩
-
멀티쓰레딩을 구현할 때 스트림을 응용하면 좀 더 편리하게 멀티쓰레딩을 할 수 있다!
-
보통 멀티쓰레딩을 한다고 하면, 공유자원의 문제를 가정해서 다음과 같은 방법을 쓴다.
- 뮤택스 / 세마포어 -> 코드 치기 어렵다.
Synchronized키워드 -> 섬세한 통제가 어렵다.
-
그렇다면, 아예 공유 자원을 없애버리면 안 될까?
-
공유 자원이 없다고 치고 람다식, 스트림을 이용하면 더 편하게 멀티쓰레딩을 구현할 수 있다!
<예시>
java
List<Integer> list = Arrays.asList(new Integer[]{1, 2, 3, 4, 5, 6, 7});
List<Integer> doubled = list.parallelStream()
.map(x -> x * 2) // 각 쓰레드는 x * 2만 계산
.collect(Collectors.toList()); // 내부에서 안전하게 병합
[작동 원리?]
- list[1]을 위한 긴 줄의 코드, list[2]를 위한 긴 줄의 코드, ...가 한 번에 돈다는 뜻!
- list[1]을 위한 긴 줄의 코드 = 1번 쓰레드!
- list[2]를 위한 긴 줄의 코드 = 2번 쓰레드!
- ....
- 어떻게? cpu 내부의 코어들을 이용한다. -> 그래서 옛날 컴퓨터로는 오히려 느릴 수도 있다.
[공유자원이 없다?] - 근데, 저런 방식이 왜 공유자원이 없다는 거지? -> 각 쓰레드는 정해진 데이터만 처리하기 때문!
- 즉, 1번 쓰레드는 무조건 list[1]의 값만 건드리고, 2번 쓰레드는 무조건 list[2]의 값만 건드린다.
- 따라서 필연적으로 공유자원이 생길 수 밖에 없는 상황에서는 뮤택스/세마포어를 쓰는 것이 더 낫다.
- 그치만 그렇지 않은 상황이라면 스트림을 이용한 병렬처리는 굉장히 좋은 방식!
모듈 & 디폴트 메서드
- 모듈: 패키지의 상위 단위. 여러 패키지를 포함하며, 프로젝트 전체를 컴포넌트처럼 나누는 데 사용
- 프로젝트를 모듈화해서 의존성 관리를 체계적으로 하기 위함
- 보안성과 캡슐화 강화
- JDK 자체도 모듈화됨 (java.base, java.sql 등)
- 디폴트 메서드 : 인터페이스에 구현체를 포함한 메서드를 작성하게 해주는 기능
- 기존 인터페이스에 기능을 추가하면서도, 하위 호환성을 유지하기 위해서
- 원래 기존 인터페이스에 새 기능을 추가하면 그걸 구현한 모든 클래스가 에러가 나나, 디폴트 메소드는 그렇지 않음.
Optional
- Optional : null 안전 처리를 위한 컨테이너 클래스
- 어떤 값이 있을 수도 있고 없을 수도 있는 상황을 깔끔하게 표현하기 위해 등장
- Optional
은 null이 올 수 있는 값을 감싸는 래퍼 클래스로, 값이 있으면 값을 담고, 없으면 빈(empty) 상태로 표현함.