현재 버전
- Java 1.8
- Spring Boot 2.4.5
자바 1.8의 특징
펼치기
람다표현식의 등장
- 자바 8 에서 등장한 기능입니다.
- 개요
- 이름이 없는 함수
- 쓰레드 , 컬렉션을 다룰 때 매우 유용함
- 문법
- 기본 문법은
( 매개변수 ) -> { 실행 코드 }
로 구성되어 있습니다.
- 예를들어
- a + b 의 기능을 하는 함수의 경우
(a, b) -> { return a + b; }
- 람다 표현식 내부의 변수는
final
혹은사실상의 final
이여야 합니다.
- a + b 의 기능을 하는 함수의 경우
- 기본 문법은
- 함수형 인터페이스에서의 사용
- 개요
- 함수형 인터페이스
- 단 하나의 추상 메서드를 가진 인터페이스를 의미합니다.
@FunctionalInterface public interface MyFunctionalInterface { int add(int a, int b); }
- 이러한 식으로
@FunctionalInterface
애노테이션을 통하여 함수형 인터페이스임을 명시적으로 선언이 가능합니다.MyFunctionalInterface lamb = (a , b) -> a + b;
- 이런식으로 함수형 인터페이스의 경우 람다식으로 사용이 가능함.
- 하지만,
단 하나
여야함.
- 함수형 인터페이스
- 개요
스트림 API ( Stream API )
- 개요
- 데이터를 효율적으로 처리할 수 있는 도구
- 배열이나 컬렉션 등의 데이터를 빠르고 간편하게 처리가능
- 라는데 사실 상황에 따라 많이 다르며, 일반적인 경우에는 스트림이 더 느린 경우가 있음
- 일반적으로 가독성 향상이 된다는 점때문에 많이 사용한다.
- 근래의 하드웨어 성능이 높아져 체감상의 차이는 거의 없다는점에 근거하여 속도는 크게 의미 없을 수 있다. (
하지만 병렬처리의 경우에는 스트림이 우위임
)
- 작동 방식
List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1"); myList .stream() .filter(s -> s.startsWith("c")) .map(String::toUpperCase) .sorted() .forEach(System.out::println);
- 리스트의 데이터를 필터링, 정렬, 출력 하는 일련의 작업을 메서드 체이닝 가능
- 장점
- 선언적인 코드
- 어떻게 작동하는지 무엇을 하고싶은지 명시적으로 선언하여 코드에 대한 집중도가 상승
- 병렬처리에 용이
- 병렬처리를 쉽게 가능하여
병렬처리가 필요한 상황의 경우
성능 향상은 확실함.
- 병렬처리를 쉽게 가능하여
- 선언적인 코드
인터페이스 디폴트 메서드
- 개요
- 디폴트 메서드는 인터페이스에 새로운 메서드를 추가하는 경우
- 기존에 그 인터페이스를 구현한 클래스를 깨뜨리지 않는 방법 제공
- 동작 방식
public interface MyInterface { default void myDefaultMethod() { System.out.println("Default implementation"); } void myAbstractMethod(); }
- 장점
- 유연성
- 기존 코드를 변경하지 않아도, 인터페이스에 새로운 기능을 추가할 수 있음.
- 하위 호환성
- 새로운 기능을 추가해서 기존 작성 코드에 영향을 미치지 않음.
- 유연성
자바 8 자바 17 주요 변경점 개요
- LTS
- Java 17 은 Long Term Support(LTS) 를 제공하는 버전이다.
- Java 8 은 Oracle Premier Support 를 잃었기 때문에, 점차적으로 지원이 줄어들 것이다.
- 새로운 기능 개선 사항
- Java17 에서는 패턴 매칭, 레코드 등의 기능이 추가되었으며
- 코드를 더 깔끔하게 작성할 수 있는 차이점이 있음
- 성능
- Java17 에서는 가비지 컬렉션, JIT 컴파일러 등의 여러 내부 매커니즘이 개선되었음.
- 라이브러리와 API
- 새로운 라이브러리와 API 추가로 개발 과정의 효율화
- Oracle 지원
- Java8에 대한 지원은 나날이 약해질 것으로 예상..
- 반면 Java17 의 경우 오랫동안 안정적인 지원을 받을 수 있음.
Java 8 17 모두 별도의 장 단점이 있음. 하지만, Oracle 지원감소와 새로운 기능의 부재 등을 고려하였을때 Java 17 로의 전환은 필수적으로 보입니다.
전자정부 프레임워크도 결국 4.1에 접어들면서 Java 8 에 대한 공식적인 지원을 그만두고, Java 11 을 필수로 받아들였습니다.
이에 대비하기 위하여 결국 Java 11 혹은 그 이상으로 마이그레이션이 필요하다가 생각.
변경점 본론
일단 ! Java 8 vs Java17 이기에, 언제 등장했는지는 명확하게 표기하기 귀찮아서 안했습니다(일부는 함).
혹시 어느 자바 버전에서 등장한건가 하신분들은 추가적으로 찾아보세요
문법상의 변화
var
키워드의 등장
- 자바 10에서 등장했습니다.
- 사용법
- 간결한 코드 작성
var
키워드 사용시 변수의 타입을 명시적으로 적지 않아도 됨.
- 코드의 간결성을 유지가능
// Java 8 스타일 Map<String, List<MyDtoType>> myMap = new HashMap<String, List<MyDtoType>>(); // Java 10 이상에서의 "var" 키워드 사용 var myMap = new HashMap<String, List<MyDtoType>>();
- 가독성 고려
- 다만
var
는 타입의 명시를 하지 않기에, 변수 이름이 해당 변수의 역할을 명확하게 표현해야합니다.
- 다만
- 간결한 코드 작성
- 제한사항
- 람다 표현식에서 사용 불가능
var
키워드를 람다 표현식의 변수에 할당할 수 없음.
// 컴파일 에러 var fun = MyObject::mySpecialFunction;
- 람다의 인수에서 사용가능
- 람다 표현식의 인수에
var
가능.
- 인수에 어노테이션을 추가할 수 있다는 특징
boolean isThereAneedle = stringsList.stream() .anyMatch((@NonNull var s) -> s.equals("needle"));
- 람다 표현식의 인수에
- 람다 표현식에서 사용 불가능
Record 의 등장
- 정의
- 데이터를 효율적으로 저장하고 관리할 수 있는
타입
- 데이터를 효율적으로 저장하고 관리할 수 있는
- 주요 특징
- 자동 생성되는 멤버
- 자동으로 몇 가지 기본 멤버가 생성됨.
private final
필드
getter
메서드
- 생성자
equals
와hashCode
toString
- 자동으로 몇 가지 기본 멤버가 생성됨.
- Lombok과 유사성
- Lombok 의
@Value
어노테이션과 유사
- Records 는 불변성을 가진 데이터를 표현하는데 사용됨.
- 필드를 선언시, 자동으로 코드가 생성됨.
- Lombok 의
- Enum 과 차이점
- Enum 과 달리 다른 클래스를 상속하거나 상속될 수 없음
- 인터페이스를 구현하거나 정적 필드와 메서드를 가질 수 있음
new
키워드를 사용하여 인스턴스 생성이 가능
- 자동 생성되는 멤버
- 사용법
record BankAccount (String bankName, String accountNumber) implements HasAccountNumber {}
- 요 한줄로 레코드를 간단히 생성가능
- 생성자에서 유효성 검사가능
record BankAccount (String bankName, String accountNumber) implements HasAccountNumber { public BankAccount { if (accountNumber == null || accountNumber.length() != 26) { throw new ValidationException("Account number invalid"); } } }
- 필드에 대한 명시적인 할당이 필요 없음.
Switch 문의 확장
- 개요
- 기존 Java8 의 switch 문에서 조금 더 확장된 기능을 제공합니다.
- 기존적인 확장된
switch
표현식- 그룹화와 값의 반환
- 기존의
switch
문에서는case
를 그룹화하거나 결과값을 반환할 때 상당이 복잡함
- 하지만 확장된
switch
표현식에서는 이런 것이 간단해짐
DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek(); boolean freeDay = switch (dayOfWeek) { case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> false; case SATURDAY, SUNDAY -> true; };
- 월 ~ 금 까지는 false 반환
- 토 ~ 일 까지는 true 반환
break
키워드가 없어도 됨.
switch
표현식 자체가 값을 반환하기에, 변수에 저장이 가능 😍
- 기존의
- 그룹화와 값의 반환
yield
키워드와 복잡한 로직의 처리DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek(); boolean freeDay = switch (dayOfWeek) { case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> { System.out.println("Work work work"); yield false; } case SATURDAY, SUNDAY -> { System.out.println("Yey, a free day!"); yield true; } };
yield
키워드 사용법case
블록 안에서 코드를 실행 한 후, 결과 값을switch
표현식의 결과로 설정가능
- 복잡한 로직의 처리
- 사실 기존 switch 사용방식을 람다식 처럼 사용하기 위한 하나의 포장방식 처럼 보인다.
- return 키워드를 사용할 수 없으니 별도의
yield
키워드를 사용함으로서 멀티라인 로직을 수행할 수 있도록 도와주는 게 아닌가 생각된다.
- 어려운게 아니라 그냥
return
의 역할과 비슷하다.
- 단순히
case
내부에서 로직에 대한 반환값을 처리할 수 있게 된 것이다.
instanceof
패턴 매칭의 확장
- Java 8 에서는
instanceof
사용시 타입 캐스팅을 수행 후, 추가 로직을 적용해야했다.
- 하지만 17에서는 패턴 매칭을 활용한 새로운(?) 문법이 도입
instanceof
패턴 매칭의 특징- 기존의 문제점
if (obj instanceof MyObject) { MyObject myObject = (MyObject) obj; // ... 추가 로직 }
- 별도로 타입을 체크한 후 명시적으로 캐스팅하여 변수를 별도로 로직안에서 선언을 해줘야했습니다.
- 새로ㅇㅇ
if (obj instanceof MyObject myObject) { // ... 추가 로직 }
- 타입을 확인하는 동시에 지역변수를 선언할 수 있게 되었습니다.
- 조건문에서의 활용
if (obj instanceof MyObject myObject && myObject.isValid()) { // ... 추가 로직 }
- 선언된 변수는 if 문 안에서 사용될 수 있습니다. ㄷㄷ..
하지만.. instanceof 문법 자체는 자주 사용되는 문법이 아니기에.. 사실상 사용할 일이 잘 없을 것으로 예상됩니다.
- 기존의 문제점
Sealed Class
- 정의
- 클래스 계층을 엄격히 제한하여 어떤 클래스가 상속을 허용할지 명시적으로 지정가능
switch
||instanceof
에서 경고 메시지 관리도 가능
- 특징과 장단점
- 명확한 클래스 계층
- 특정 클래스가 어떤 자식 클래스들만 허용하는지 명시적으로 표현가능
- 프로그램의 안정성의 증대 가능
public abstract sealed class Animal permits Dog, Cat { } public final class Dog extends Animal { } public final class Cat extends Animal { }
- 경고 메시지 제거
- 컴파일러의 경고 메시지
- 컴파일러는 코드의 가능한 문제점을 미리 알려주기 위해 경고를 출력함
swich
혹은instanceof
연산자 사용시 모든 경우를 다루지 않았다고 컴파일러가 경고 메시지를 줄 수 있음.
sealed classed
의 역할- 특정 클래스가 어떤 서브 클래스만을 허용할지 명시함으로서
if (animal instanceof Dog d) { return d.woof(); } else if (animal instanceof Cat c) { return c.meow(); }
- 에서 별도로 Gecko 를 명시적으로 허용했는데, 이를 고려하지 않았다! 라고 경고(에러아님) 를 출력해줄 수 있는 것이다.
- 컴파일러의 경고 메시지
- 하지만…
- 괜한 코드의 복잡성만 높일 수 있으며
- 순환 참조 같은 안티 패턴을 생성할 가능성이 있다고
합니다.
- 슈퍼 클래스에서 서브 클래스에 대해 명시적으로 알고 있으며, 그 반대도 알고 있는 경우,
- 순환참조가 될 수 있다고 함.
- 명확한 클래스 계층
TextBlocks 기능
- 정의
- Java 13 부터 등장하였음
- 긴 문자열을 훨씬 편리하게 다룰 수 있음.
- 기존의 긴 문자열은 별도 이스케이핑문자 (
\
) 를 사용해야했지만, TextBlock 으로 불편이 줄었음
- 사용법
String myWallOfText = """ 안녕하세요 ㅋㅋ """;
세 개의 따옴표 (
”””
) 를 사용하여 문자열을 선언가능String myWallOfText = """ 안녕하세요 \ ㅋㅋ """;
\
문자를 사용하면 문자열에 대해 별도 띄어쓰기를 적용하지 않는다.
안녕하세요 ㅋㅋ
- 로 출력된다.
- 백슬래시를 사용하고 싶다면?
String myWallOfText = """ 안녕하세요 \\ ㅋㅋ """;
- 별도 백슬래시 안에 이스케이핑처리를 해주긴해야함.
- 장점
- JSON 혹은 XML 템플릿을 더 깔끔하게 유지할 수 있음.
- 원래 자바에서는 xml 이나 json 을 String 변수에 담는 경우 상당히 지저분했음.
Better NPE (JVM 변경점)
- 정의
- 기존의 Java에서는 NPE 가 발생하는 경우
company.getOwner().getAddress().getCity()
같은 메서드 체인에서 어느 한 부분이null
인 경우
- 어느 부분에서
null
이 발생했는지 정확하게 알 수 없었음.
- 하지만 이제는 더 자세한 메시지를 통해 어떤 부분에서 문제가 발생했는지 확인이 가능하다.
- 기존의 문제점
- NPE 발생시 어느 부분에서 발생했는지 디버깅으로 밖에 알 수 없었음
- 개선점
- JVM 런타임에 바이트 코드 분석을 통해 더 자세한 메시지 제공
- "cannot invoke
Person.getAddress()
"- 같은 메시지로 어떤 메서드 호출에서 문제가 발생한 건지 알 수 있게 됨.
- JAVA 언어적 변경점 X → JVM 의 변경점
사실 자바 17 이라서 특이한것이 아니라 이전 버전에서 점진적으로 추가된 내용이 대부분입니다
자바 17에서는 SEALED CLASS , RECORD , INSTANCEOF 의 확장만 추가되었으며,
추가적으로는 JVM 관련 기능의 개선이 주요점입니다!
JVM 관련 기능의 개선
- GC
- 더 효율적인 GC 알고리즘의 도입
- 메모리 관리 효율성 증대
- 응답 시간 개선
- 더 효율적인 GC 알고리즘의 도입
- AOT 컴파일러의 추가
- Ahead-Of-Time 컴파일
- 프로그램이 실행되기 전에 모든 코드를 네이티브 코드를 변환하는 방식
- JIT 컴파일의 경우 프로그램이 실행되는 동안 필요한 코드만 네이티브로 변환하였음
- 하지만 AOT 컴파일러가 추가됨으로서,
- 애플리케이션의 빠른 시간 시간
- JIT 컴파일러가 코드를 컴파일하는 데 드는 CPU 자원을 줄일 수 있게 됩니다.
- 이는 MSA 의 경우 큰 장점으로 느껴질 수 밖에 없습니다.
- Ahead-Of-Time 컴파일
Uploaded by N2T
'자바 > 리팩토링' 카테고리의 다른 글
[리팩토링] 리스트 조회에서 api 만 분리하기 (0) | 2023.09.21 |
---|---|
[리팩토링] DTO 가 너무 분화될 것 같은 경우 어떻게 해야할까? (0) | 2023.09.21 |
[리팩토링] DTO 에서 VO 간의 전환 메서드를 편하게 사용하려면? - MapStruct (0) | 2023.09.21 |
[리팩토링] FM 메서드 → private 생성자 전략 (0) | 2023.09.21 |
[리팩토링]Spring Boot 2.4.5 vs Spring Boot 3.1.xx (0) | 2023.09.12 |