모던 자바란?
- 이전 자바와는 완전히 다르다는 뜻으로 자바 8 이후에 자바를 모던 자바라고 말함
- 자바 8 이후에 새로운 기능을 활용하는 개발 패러다임
모던 자바의 주요 변화
1) 람다와 스트림 도입
- 람다와 스트림이 도입되어 함수형 프로그래밍 지원
2) 멀티코어 환경 대응
- 스트림를 API를 이용해 병렬 처리
3) 높은 안정성
- Optional 도입
람다식
예제로 먼저 알아보자
요구사항1 : 백엔드 크루만 찾아줘
위와같이 백엔드 크루가 일치하는지 확인해서 결과를 담아서 반환
요구사항2 : 프론트엔드 크루도 찾아줘
반복을 줄이기 위해 파라미터로 코스를 추가해서 코스에 해당하는 값을 받아서 반환
요구사항3 : 백엔드 크루면서 남자인 크루만 찾아줘
파라미터를 추가해서 반환
이런 식으로 한다면 요구사항이 계속 늘어날수록 파라미터를 계속 추가하고 함수를 새로 생산하고 불필요한 코드가 반복되게 된다.
그래서 인터페이스를 정의해서 인터페이스를 구현하는 구현체의 해당 로직을 추가해서 인자로 인터페이스를 구현한 구현체를 넘겨준다. 이 과정을 동작구에 넘겨준다고 해서 동작파라미터화라고 한다.
그렇다면 요구 사항이 늘어날 때마다 구현하는 클래스를 계속 생성 해야 되나? 백 개의 요구사항이 생긴다면 백 개의 클래스를 생성 해야 되나? 라는 의문이 생길 수 있다.그래서 등장한 것이 익명 함수이다.
익명 함수는 클래스를 새로 생성 하지 않고 파라미터로 넘겨준 부분에서 익명 클래스를 정의해서 파라미터로 넘겨줄 수 있다. 그치만 익명 클래스도 길다. 중요한 것은 리턴 문에 들어가는 핵심 로직인데 선언도 해야 되고 여러가지 다룰게 많다. 그것들을 줄이고 싶어서 람다식이 등장한다.
람다식
- 메서드를 하나의 식으로 표현
- 코드가 간결해지고 명확해짐
- 파라미터, 화살표, 바디로 구성
- 코드의 가독성과 의도를 명확하게 함
- 리턴 타입도 없고, 이름도 없어서 익명 함수 또는 익명 객체라고도 함
- 변수에 할당하거나 함수형 인터페이스를 인수로 받는 메서드로 전달할 수 있음
- 함수형 인터페이스의 인스턴스로 취급
- 자바에서 모든 메서드는 클래스 내에 포함되어야 하므로 람다식은 익명 클래스 객체와 동등
- 람다식을 다루기 위한 인터페이스가 함수형 인터페이스
위 코드는 자바에서 기본적으로 제공하는 함수형 인터페이스 이다. 자바 8 에서부터 FuntionalInterface라는 어노테이션에 추가되어 명시적으로 함수형 인터페이스로 사용하겠다 라고 선언할 수 있다.
스트림
예제로 먼저 알아보자
요구사항 : 크루 중에 나이가 20 살보다 작은 크루의 이름을 찾아줘, 이름 순으로 정렬도 해줘
자바 8 이전에는?
1) 먼저 크루들 중 나이가 스무 살보다 작은 크루를 리스트로 분리
2) 분리한 리스트에서 크루들의 이름만 추출해서 분리
3) 분리한 이름들을 비교하며 정렬
위와 같이 세 개의 일련의 과정을 거쳐야 한다.
스트림 도입
스트림이 도입된 이후부터는 좀 더 명확하게 한 줄로 어떤 행위를 나타낼 수 있다.
- 컬렉션 처리를 위한 새로운 API
- 스트림은 다량의 데이터 처리 작업을 위해 자바 8에서 등장
- 데이터베이스 쿼리를 작성하듯 직관적인 코드 제공
SELECT, FROM, WHERE, ORDER BY라는 문을 작성했는데 그 위에 있는 스트림 구문과 거의 일치한다고 볼 수 있다.
- 초기 데이터 → 중간 연산 → 최종 연산 구조
- 메서드 체이닝 방식을 사용
중간 연산에서 제공되는 대표적인 API
중간 연산 | 기능 |
filter | 조건에 맞는 요소만 뽑기 |
map | 원하는 필드만 뽑거나 특정 형태로 반환 |
distinct | 중복 제거 |
sorted | 스트림 요소 정렬 |
limit | 스트림의 일부를 잘라내기 |
최종 연산에서 제공되는 대표적인 API
최종 연산 | 기능 |
collect | 리스트, 맵, 정수 타입의 컬렉션 생성 |
count | 스트림 요소들의 개수 반환 |
max, min | 스트림 요소들의 최대, 최소 |
allMatch | 스트림 요소가 모두 만족하는지 |
anyMatch | 스트림 요소가 하나라도 만족하는지 |
- 지연 연산 수행 (최종 연산하기 전까지 실질적인 연산을 수행하지 않는다.)
요구사항 : 1부터 10사이의 자연수 중에서 3보다 크고 9보다 작은 값 중에서 2을 곱했을 때 10보다 큰 가장 작은 수를 찾아줘
일반 for문으로 작성하는 경우 1부터 10 까지의 수를 차례대로 내려오면서 브레이크 걸릴 때까지 수행되는 연산이 15번이다.
스트림은 한 스트림이 돌 때마다 스트림 결과가 반환되고 다음 스트림으로 넘어가는 체이닝 구조로 연결돼 있다. 단순하게 생각해 보면 스트림이 for문보다 연산 횟수가 더 많지 않겠나 라고 생각할 수 있다.
● 첫 번째 filter 에서 1부터 10까지 모든 수를 확인하고 → 10회
● 두 번째 filter 에서는 첫 번째에서 걸러진 4부터 10까지 → 7회
● 세 번째 map 에서는 두 번째에서 걸러진 4부터 8까지 5회
● 네 번째 filter 에서는 세 번째에서 연산된 4(8)부터 8(16)까지 →5회
총 27회를 연산한 후, [12, 14, 16] 중에서 첫 번째 값인 12를 반환하지 않을까? 라는 추측을 할 수 있다.
확인해 보면 스트림은 for문과 동일하게 15번 수행한다.
결과적으로 스트림은 자체적으로 지연 수행한다는 것이다.
최종 연산이 호출될 때서야 비로소 연산이 평가가 되고 최종 연산에 필요 없는 데이터는 쓰지 않는다는 것이다.
- 명시적으로 병렬로 지정되지 않는 한 자바의 모든 Stream 작업은 순차적으로 처리
- parallelStream 덕분에 병렬 처리에 용이
병렬 처리 같은 부분은 성능적인 이슈가 중요하기 때문에 잘 고려해서 사용해야 한다.
Optional
메서드가 특정 조건에서 값을 반환할 수 없다면?
1) 예외 처리
- Stack Trace를 캡쳐해야 하기 때문에 예외 생성 비용 발생
2) null 반환
- 클라이언트입장에서 이 메서드가 null인지 알기 힘듬
- nullPointException이 발생하지 않도록 null 처리 코드를 작성해야함
예를 들어서 만약 크루의 우편번호를 가져오는 메서드가 있다고 했을때 크루가 null 이 될 수 있다면 무슨 상황이 벌어질까? NullPointException이 발생한다.
그리고 이 코드를 처리하기 위해서 저희는 if문으로 null처리 추가 코드가 필요하다.
Optional 클래스의 개념
자바 8부터 Optional 클래스가 도입됐는데 Optional 클래스는 값을 최대 한 개 가질 수 있는 컨테이너 클래스라고 보면 된다. 값을 가질 수도 있고 가지지 않을 수도 있다.
위에서 if를 사용한 코드에 Optional을 사용하면 깔끔하게 처리할 수 있다.
만약에 Optional에 또 Optional이 반환된다면 어떻게 처리할까?(getAddress가 Optional을 반환한다면?)
여기 Optional이 또 Optional을 감싸는 경우인데 이 경우 map 대신 flatMap을 사용하면 Optional을 한번 감싸도록 사용할 수 있다.
Optional 클래스의 장단점
Optional 클래스를 사용하면 메서드에 명시적으로 null 가능성을 표현 가능하다. 그러면 클라이언트 입장에서 메서드 시그니처만 보고 이게 null이 될 수 있다 생각할 수 있고 위에서 if문을 제거한 것처럼 코드 가독성도 올릴 수 있다. 그리고 null이 될 수 있는 클래스가 아닌 Optional를 사용함으로써 NullPointException을 방지할 수 있다. 하지만 Optional이라는 클래스를 생성 해야 되기 때문에 객체 생성 비용이 발생한다. 그리고 만약 클래스에 필드로 Optional을 사용한다면 직렬화를 지원하지 않기 때문에 직렬화 문제도 발생한다.
Optional 클래스 사용법
생성
메소드 명 | 값 존재 : O | 값 존재 : X |
empty | 빈 Optional 반환 | |
of | 값을 감싸는 Optional을 반환 | NPE |
ofNullable | 값을 감싸는 Optional을 반환 | 빈 Optional 반환 |
생성 방법에는 empty, of, ofNullable이 있다.
empty()
빈 Optional 반환
of()
값 존재 O : 값을 감싼 Optional 반환
값 존재 X : NPE 발생
ofNullable()
값 존재 O : 값을 감싼 Optional 반환
값 존재 X : 빈 Optional 반환
값 접근
메소드 명 | 값 존재 : O | 값 존재 : X |
get | 값 반환 | NoSuchElementException |
orElse | 값 반환 | 기본값 반환(아래 두 방식 권장) |
orElseGet | 값 반환 | Supplier에서 생성한 값 반환 |
orElseThrow | 값 반환 | Supplier에서 생성한 예외 발생 |
get() - 값이 항상 있다는 가정하에 사용
orElse() - 값이 없다면 기본 값으로 대체할 수 있는 값을 제공해 줄 수 있음
orElseGet() - orElse의 lazy 버전이라고 생각하시면 됨
- 값이 존재한다면 이 인스턴스가 생성되지 않고 값이 존재하지 않을 때만 인스턴스가 생성돼서 orElseGet이 좀 더 효과적이라고 할 수 있다.
orElseThrow() - 대체값이 아닌 Exception을 발생시키고 싶을 때 예외를 반환하도록 로직을 짤 수 있음
Optional을 언제 사용 하면 좋을까?
라이브러리 메서드가 반환할 결과값이 '없음'을 명백하게 표현할 필요가 있는 곳에서 제한적으로 사용할 수 있는 메커니즘을 제공하는 것이 Optional의 의도이다. - Brian Goetz(Java Architect) -
언제 사용하면 안될까?
- 단순히 값을 얻으려는 목적으로 사용하는 경우
Optional을 쓰기보다 그냥 if문이나 이 안에서 if문으로 기본 값을 처리해 주거나 예외를 던져주는게 좋다.
- 생성자, 수정자, 메서드 파라미터 등으로 Optional을 사용하는 경우
이 경우 이 메서드에 책임이 맞나 한번 고려해 볼 필요가 있다.
- 필드나 Getter에 사용하는 경우
필드에는 직렬화 문제가 발생하기 때문에 사용하지 않는 것이 좋고 Getter의 경우 클래스 필드의 이 필드가 진짜 필요한지 아니면 Getter가 필요한지 고려해 볼 필요가 있다.
- Collection을 사용하는 경우
컬렉션을 Optional로 감싸기보다 컬렉션의 emptyList로 빈 컬렉션을 반환해 주는 것이 좋다.
정리
- 클라이언트 시점 : orElseGet()을 사용해 기본값을 정하거나 orElseThrow()를 이용해 값이 없을 시 예외를 던진다.
- API 작성 시점 : 작성한 메서드가 반환값이 없을 수 있으며 클라이언트가 이 상황을 특별하게 처리해야 한다면 메서드의 반환타입으로 Optional를 한번 고려하자
자바 8 이후 추가된 기능
● Java 10
var 타입 추가
- 로컬 변수 타입 추론
● Java 11
String 클래스에 유용한 메서드 추가
- isBlank() : 공백 문자만 포함됐는지 확인
- lines() : newLine(개행)을 기준으로 쪼개서 Stream으로 제공
- repeat() : 문자열를 반복해서 하나의 문자열로 반환
● Java 15
String 클래스에 포멧팅관령 추가 기능
- formatted를 사용하면 코드가 조금 더 간결해질 수 있다.
● Java 16
Stream 추가 기능
- toList() 추가
리스트로 반환하고 싶으면 컬렉터에서 toList()를 많이 사용하는데 toList()만 사용해주면 똑같이 리스트를 반환해 주는 것을볼 수 있다.
- instanceof와 패턴 매칭
value의 타입이 오브젝트인데 오브젝트가 만약 스트링의 instanceof라면 if 블록안에서 스트링처럼 스트링 메서드를 사용할 수 있다. if 조건문에서도 스트링 관련 메서드를 사용할 수 있는 것을 볼 수 있다. early return 타입으로 사용하면 if문 밖에서도 instanceof 키워드인 s에 스트링 메서드를 사용할 수 있다.
- record 클래스 추가
● Java 17
- sealed 타입 추가
class나 interface를 sealed 타입으로 지정해서 상속할 수 있는 타입을 제한
- sealed 타입을 상속한 타입은 다음을 만족해야 한다.
참고
https://www.youtube.com/watch?v=veJO12VV-Mg&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9C%ED%85%8C%ED%81%AC
'개발 관련 강의 정리 > 10분 테코톡' 카테고리의 다른 글
[10분 테코톡] 🐯 심바의 RESTful 정리 (0) | 2023.06.09 |
---|---|
[10분 테코톡] 메리의 Gradle 정리 (0) | 2023.06.08 |
[10분 테코톡] 칙촉의 TCP/UDP 정리 (0) | 2023.06.05 |
[10분 테코톡] 썬의 캐싱 정리 (0) | 2023.06.04 |
[10분 테코톡] 아벨의 상태 패턴 정리 (0) | 2023.06.03 |
댓글