"모던 자바(Modern Java)"는 주로 자바 프로그래밍 언어의 최신 기능과 개선된 패러다임을 지칭합니다. 기존의 자바 버전에서 도입된 기능들과는 달리, 자바 8 이후부터의 새로운 기능과 변경된 프로그래밍 스타일을 포함합니다.
모던 자바에서는 함수형 프로그래밍의 개념을 도입하고, 람다 표현식과 스트림 API 등을 통해 코드를 더욱 간결하고 유연하게 작성할 수 있습니다. 또한, 형식 추론(var 키워드), 모듈 시스템, 레코드(Records) 등과 같은 새로운 기능들이 추가되어 프로그래머가 코드를 작성하고 유지보수하는 데 도움이 됩니다.
따라서 모던 자바는 자바 언어를 사용하여 최신의 개발 트렌드와 요구 사항에 부합하는 현대적이고 효율적인 코드를 작성하는 것을 의미합니다.
자바8 이후에 새로운 기능들을 활용하여 개발하는 개념을 모던 자바라고 이해하면 될 것 같다. 😁
JDK 8 이후에 새롭게 추가된 기능들에 대해 알아보자!
var 키워드의 확장(JDK 10 이상) - 자바 10부터는 var 키워드가 지역 변수 뿐만 아니라 반복 변수 및 익명 클래스의 파라미터로도 사용 가능하고 이는 코드의 가독성을 향상시키고, 반복 변수와 익명 클래스의 형식을 더 명확하게 표현할 수 있게 된다. 😁
(* Type Inference : 타입을 생략하여도 이를 문맥상 충분히 알 수 있으면 컴파일러가 타입을 추론해주는 것)
단 var 타입을 사용하기 전에
오라클에서 var를 출시하게 된 이유와 사용하였을 때 기대효과 단점 등등 꼭 읽어보고 사용하도록 하자!
https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference
package org.ndj;
import java.util.Arrays;
public class LocalVariableTypeInference {
public static void main(String[] args) {
// old Java
String oldName = "DONGJU";
int[] oldNums = new int[]{1,2,3,4,5};
// modern Java
var newName = "DONGJU";
var nums = new int[]{1,2,3,4,5};
System.out.println("oldName > " + oldName + " Class > " + oldName.getClass());
System.out.println("oldNums > " + Arrays.toString(oldNums) + " Class > " + oldNums.getClass());
System.out.println("newName > " + newName + " Class > " + newName.getClass());
System.out.println("nums > " + Arrays.toString(nums) + " Class > " + nums.getClass());
}
}
스위치 표현식 (Switch Expressions) - 자바 12부터는 스위치 표현식이 개선되어서 더 간결하고 가독성 있는 코드를 작성할 수 있다.👍 아래 코드를 보고 표현식 사용 유무 차이를 확인해보자! 🤨
package org.ndj;
public class SwitchNewStatement {
public static void main(String[] args) {
// old way
int olcDayNum = 6;
String oldDay = "";
switch(olcDayNum) {
case 1:
oldDay = "Monday";
break;
case 2:
oldDay = "Tuesday";
break;
case 3:
oldDay = "Wednesday";
break;
case 4:
oldDay = "Thursday";
break;
case 5:
oldDay = "Friday";
break;
case 6:
oldDay = "Saturday";
break;
case 7:
oldDay = "Sunday";
break;
default:
oldDay = "Not Valid";
break;
}
// new way
int newDayNum = 6;
String newDay = switch (newDayNum) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
case 6 -> "Saturday";
case 7 -> "Sunday";
default -> "Not Valid";
};
System.out.println("oldDay > " + oldDay);
System.out.println("newDay > " + newDay);
}
}
텍스트 블록(Text Block) - 기능이 자바 15에 정식으로 추가 되었다. 기능 추가가 아닌 언어적인 변화로 자바에서 XML, SQL 등 멀티라인으로 문자열을 사용하는 개발자들에게 희소식이다. 😊
아래 코드를 보면 이스케이프 시퀀스 와 (+) 연산자를 사용하지 않아 코드가 훨씬 깔끔한걸 볼 수 있다.
package org.ndj;
public class TextBlock {
public static void main(String[] args) {
// old way
String oldMultiLineString = "<header>\n" +
"\t<h1>Welcome DJ</h1>\n" +
"</header>";
// new way
String newMultiLineString = """
<header>
<h1>Welcome DJ</h1>
</header>
""";
System.out.println(oldMultiLineString);
System.out.println(newMultiLineString);
}
}
Records (레코드) - 자바 14부터는 레코드(record)라는 새로운 데이터 타입이 도입되었는데, 레코드 타입은 불변성(immutability)과 데이터 전달 객체(data transfer object)를 지원하는 간결한 방식으로 데이터를 표현할 수 있도록 한다.
* 해당 타입을 사용하기전 읽어보면 좋을만한 글
https://www.baeldung.com/java-record-keyword
DTO 클래스 생성 시 불필요하게 코드 생성 하는것을 줄일 수 있는 정도로 나는 이해하고 있다. 🤔
- 각 데이터 조각에 대한 private , final 필드
- 각 필드에 대한 getter
- 각 필드에 해당 인수가 있는 공개 생성자
- 모든 필드가 일치할 때 동일한 클래스의 객체에 대해 true를 반환하는 equals 메서드
- 모든 필드가 일치할 때 동일한 값을 반환하는 hashCode 메서드
- 클래스 이름, 각 필드 이름 및 해당 값을 포함하는 toString 메소드
package org.ndj;
public class RecordClass {
// old way MemberDto 클래스를 외부 클래스로 변경
public static class MemberDto {
private String name;
private int age;
public MemberDto(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "MemberDto{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
// new way Record 클래스 선언
record Member(String name, int age) {}
public static void main(String[] args) {
MemberDto oldMember = new MemberDto("DJ",30);
System.out.println(oldMember.toString());
System.out.println("name > " + oldMember.name);
System.out.println("age > " + oldMember.age);
Member member = new Member("DJ",30);
System.out.println(member.toString());
System.out.println("name > " + member.name);
System.out.println("age > " + member.age);
}
}
Stream API (스트림 API) - 자바 8 부터 컬렉션을 처리하고 변환하는 기능을 제공하는데 이를 통해 데이터 처리 과정을 선언적으로 표현할 수 있어 코드의 가독성과 유지보수성을 향상시킨다 👍
Java 8 스트림 API의 특징을 다음처럼 요약할 수 있다.
- 선언형 : 가독성 +
- 코드 조립 : 유연성 +
- 병렬화 : 성능 +
package org.ndj;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamApi {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Doe", "Jane", "Alex", "Alice");
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
/*******************************************************************
* old way
********************************************************************/
//Filtering - 데이터 컬렉션에서 특정 조건을 만족하는 요소들만 선택
List<String> oldFilteredNames = new ArrayList<>();
for (String name : names) {
if (name.startsWith("J")) {
oldFilteredNames.add(name);
}
}
System.out.println(oldFilteredNames);
//Mapping - 데이터 컬렉션의 요소를 다른 형태로 변환
List<Integer> oldNameLengths = new ArrayList<>();
for (String name : names) {
oldNameLengths.add(name.length());
}
System.out.println(oldNameLengths);
//Sorting - 데이터 컬렉션의 요소를 정렬
List<String> oldSortedNames = new ArrayList<>(names);
oldSortedNames.sort(Comparator.naturalOrder());
System.out.println(oldSortedNames);
//Grouping - 데이터 컬렉션의 요소를 특정 기준으로 그룹화
Map<Integer, List<String>> oldNamesByLength = new HashMap<>();
for (String name : names) {
int length = name.length();
List<String> group = oldNamesByLength.getOrDefault(length, new ArrayList<>());
group.add(name);
oldNamesByLength.put(length, group);
}
System.out.println(oldNamesByLength);
//Reducing - 데이터 컬렉션의 모든 요소를 하나로
int oldSum = 0;
for (int num : numbers) {
oldSum += num;
}
System.out.println(oldSum);
//Processing - 데이터 컬렉션을 병렬로 처리
int oldSumValue = 0;
for (int num : numbers) {
oldSumValue += num;
}
System.out.println(oldSumValue);
//Stream Concatenation - 두 개의 스트림을 연결
List<String> oldConcatenatedList = new ArrayList<>();
List<String> oldFirstNames = Arrays.asList("John", "Doe");
List<String> oldLastNames = Arrays.asList("Smith", "Johnson");
oldConcatenatedList.addAll(oldFirstNames);
oldConcatenatedList.addAll(oldLastNames);
System.out.println(oldConcatenatedList);
/*******************************************************************
* new way Stream API Use
********************************************************************/
//Filtering - 데이터 컬렉션에서 특정 조건을 만족하는 요소들만 선택
List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("J"))
.toList(); // collect(Collectors.toList()) same Code 같은 동작화는 코드
System.out.println(filteredNames.toString());
//Mapping - 데이터 컬렉션의 요소를 다른 형태로 변환
List<Integer> nameLengths = names.stream()
.map(String::length)
.toList();
System.out.println(nameLengths);
//Sorting - 데이터 컬렉션의 요소를 정렬
List<String> sortedNames = names.stream()
.sorted()
.toList();
System.out.println(sortedNames.toString());
//Grouping - 데이터 컬렉션의 요소를 특정 기준으로 그룹화
Map<Integer, List<String>> namesByLength = names.stream()
.collect(Collectors.groupingBy(String::length));
System.out.println(namesByLength.toString());
//Reducing - 데이터 컬렉션의 모든 요소를 하나로
Optional<Integer> sum = numbers.stream()
.reduce(Integer::sum);
System.out.println(sum.toString());
//Processing - 데이터 컬렉션을 병렬로 처리
int sumValue = numbers.parallelStream()
.mapToInt(Integer::intValue)
.sum();
System.out.println(sumValue);
//Stream Concatenation - 두 개의 스트림을 연결
List<String> firstNames = Arrays.asList("John", "Doe");
List<String> lastNames = Arrays.asList("Smith", "Johnson");
Stream<String> concatenatedStream = Stream.concat(firstNames.stream(), lastNames.stream());
System.out.println(concatenatedStream);
}
}
이 외에도 추가된 기능이 많으니 책 또는 오라클 Docs에서 꼭 확인하도록 하자 !! 😛
Ref
블로그에서 사용한 코드 github (더 좋은 예제가 있다면 PR 또는 댓글 남겨주세요😅)
https://github.com/DongJu-Na/modern-java-practice
최신 Java/JVM 빌드 사례
https://github.com/binkley/modern-java-practices
나는 프로그래머다 웨비너 - 자바8 깊숙히! - 케빈(Kevin Lee 영상도 이어서 보길 추천!)
https://www.youtube.com/watch?v=lIEKOe0bh0M&t=10s
[10분 테코톡] 그레이, 호이의 Modern Java
https://www.youtube.com/watch?v=veJO12VV-Mg
모던 자바 인 액션 책 추천!
https://www.manning.com/books/modern-java-in-action
https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference
https://d2.naver.com/helloworld/4911107
'Develop > Back-End' 카테고리의 다른 글
[Java] 리플렉션(Reflection) 이란 무엇인가요? (6) | 2024.10.07 |
---|---|
[SpringBoot] 스프링을 이용하여 가벼운(간단한) 스케줄링 작업 처리하는 방법 😁 (4) | 2024.08.13 |
스프링 배치(Spring Batch) 시작하기 !😭 (131) | 2024.02.03 |
스프링 부트 카카오 로그인 API 기능 추가하기 😳 (114) | 2023.10.22 |
Spring Boot 환경에서 Appium을 통해 모바일 환경 테스트 하기 + 플러그인 (09.19 수정) (66) | 2023.09.17 |