본문 바로가기

Develop/Back-End

[Java] 모던 자바(Modern JAVA) 란 무엇인가!!!!😒 (feat. 새롭게 추가된 기능들)

GPT 3.5

 

"모던 자바(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 클래스 생성 시 불필요하게 코드 생성 하는것을 줄일 수 있는 정도로 나는 이해하고 있다. 🤔

  1. 각 데이터 조각에 대한 private , final 필드
  2. 각 필드에 대한 getter
  3. 각 필드에 해당 인수가 있는 공개 생성자
  4. 모든 필드가 일치할 때 동일한 클래스의 객체에 대해 true를 반환하는 equals 메서드 
  5. 모든 필드가 일치할 때 동일한 값을 반환하는 hashCode 메서드
  6. 클래스 이름, 각 필드 이름 및 해당 값을 포함하는 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

 

GitHub - DongJu-Na/modern-java-practice: Example project to practice modern Java

Example project to practice modern Java. Contribute to DongJu-Na/modern-java-practice development by creating an account on GitHub.

github.com

 

 

최신 Java/JVM 빌드 사례

https://github.com/binkley/modern-java-practices

 

GitHub - binkley/modern-java-practices: Modern Java/JVM Build Practices

Modern Java/JVM Build Practices. Contribute to binkley/modern-java-practices development by creating an account on GitHub.

github.com

 

나는 프로그래머다 웨비너 - 자바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

 

Modern Java in Action

Manning’s bestselling Java 8 book has been revised for Java 9 and 10! In it, you’ll build on your existing Java language skills with the newest features and techniques.

www.manning.com

 

 

https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference

 

https://developer.oracle.com/learn/technical-articles/jdk-10-local-variable-type-inference

Get Free Tier with no time limits on a selection of Always Free services like Autonomous Database, Compute, and Storage, and US$300 in free credits to try additional cloud services.

developer.oracle.com

 

https://d2.naver.com/helloworld/4911107

 

반응형