ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바 17로 바꿔야 할까? (자바 JDK 10 ~ 17 정리)
    JAVA/자바공부 2022. 10. 1. 00:16

    잠이 안 와서 유튜브에 보는데
    intellij conf에 자바 17에 대한 발표가 있었다. 

     

    정리해 본다. 

     

    출처

    Project Repo : github

    Intelij Conf 2022 : youtube

     

     🧑‍🏫 발표자가 생각하는 Java 17 요약

    • 17 오면서 성능 향상 (빠르다, 메모리 조금 쓴다), 새로운 기능 추가 됨
    • 자바 8 쓰는 중이라면 11 건너뛰고 바로 17로 가자 (라이브러리 버전들이 영향받을 것…그렇지만)
    • JDK 17은 발표된 지 1년 지났고 라이브러리들 안정화된 것 같음 (17은 Sept 2021 발표)
    • JDK 19도 이미 출시
    • JDK 21(LTS) 출시 예정 (Sept 2023, LTS 출시가 2년 주기로 바뀜 관련 기사)
    • JDK 17은 6년 이상 지원 될 것  

    1. 발표자

    • Nikhil Nanivadekar
      • Principle Engineer with Amazon
      • 시애틀 거주
      • 자바 챔피언 (전 세계 30명 정도 있다고 함)
      • 트위터 : NikhilNanivade
     

    Nikhil Nanivadekar (@NikhilNanivade) / 트위터

    Project lead Eclipse Collections (https://t.co/Bz4h5Ytpb8) Software Developer, Mechanical Engineer, Java Champion. All opinions stated by me are my own.

    twitter.com

     

    2. 주제 : 자바 17로 바꿔야 할까?

    자바 17에서 변한 것

    2.1. 더 좋아진 성능

    • Java 8 vs 11 vs 17 성능 측정 결과는 JMH Tests을 사용해서 테스트함 (Java Microbenchmark Harness)
    1. Interger의 속도가 매우 빨라짐 Map.put, Map.get
    2. String의 경우 size가 커지면 성능이 좋아짐 (50,000 건부터 점점 더 빠름)
    3. 17은 메모리를 덜 쓴다.

    🧑‍🏫 성능 측정 결과 보는 곳 : 깃허브

    깃 타고들어가면 이런것 볼 수 있다.

    2.2. 새로 추가된 기능 (JDK 10 ~ JDK 17)

    var (JDK 10)

    • Local variable type inference
    • 컴파일러가 type 알아서 확인해줌
      • null로 초기화할 수 없다.
      • 람다 표현식 할당 할 수 없다.
      • 다형성 코드에서 사용 피해라.
    @Test
    public void var() {
        Map<Integer, String> map = Map.of(1, "One", 2, "Two");
        var withVar = Map.of(1, "One", 2, "Two"); // Map으로 알아서 type check 
        Assertions.assertEquals(map, withVar);
    }
    

    Switch Stataments (JDK 14)

    • 기존의 스위치문 (가독성…)
    private String getQuarterOldSwitch(Integer monthNumber) {
        switch (monthNumber) {
            case 1:
                return "Q1";
            case 2:
                return "Q1";
            case 3:
                return "Q1";
            case 4:
                return "Q2";
            case 5:
                return "Q2";
            case 6:
                return "Q2";
            case 7:
                return "Q3";
            case 8:
                return "Q3";
            case 9:
                return "Q3";
            case 10:
                return "Q4";
            case 11:
                return "Q4";
            case 12:
                return "Q4";
            default:
                return "Not a month in year";
        }
    }
    
    • 업그레이드된 스위치문
    private String getQuarterNewSwitch(Integer monthNumber) {
        return switch (monthNumber) {
            case 1, 2, 3 -> "Q1";
            case 4, 5, 6 -> "Q2";
            case 7, 8, 9 -> "Q3";
            case 10, 11, 12 -> "Q4";
            default -> "Not a month in year";
        };
    }
    
    private String getQuarterNewSwitch(Integer monthNumber) {
        final String quarter = switch (monthNumber) {
            case 1, 2, 3 -> "Q1";
            case 4, 5, 6 -> "Q2";
            case 7, 8, 9 -> "Q3";
            case 10, 11, 12 -> "Q4";
            default -> "Not a month in year";
        };
        return quarter;
    }
    
    • 표현식에 yeild value 사용할 수 있다.
    private String getQuarterYieldSyntax(Integer monthNumber) {
        return switch (monthNumber) {
            case 1, 2, 3 -> "Q1";
            case 4, 5, 6 -> "Q2";
            case 7, 8, 9 -> "Q3";
            case 10, 11, 12 -> {
                System.out.println("Yay Last Quarter");
                yield "Q4";
            }
            default -> "Not a month in year";
        };
    }
    
    • Switch with Enums
      • 컴파일 safety 증가..?
    public enum Months {
        JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
    }
    
    private String getQuarterEnum(Months month) {
        return switch (month) {
            case JAN, FEB, MAR -> "Q1";
            case APR, MAY, JUN -> "Q2";
            case JUL, AUG, SEP -> "Q3";
            case OCT, NOV, DEC -> "Q4";
            // No need for default as all possible values are covered (exhaustive).
        };
    }
    

    Text Blocks (JDK 15)

    • 기존의 String 사용법
    String json = "{\\n" +
            "  \\"firstName\\": \\"Nikhil\\",\\n" +
            "  \\"lastName\\": \\"N\\",\\n" +
            "  \\"city\\": \\"Seattle\\",\\n" +
            "  \\"phone\\": 123\\n" +
            "}";
    
    • text block 등장 (따옴표가 3개!)
    String textBlockJson = """
            {
              "firstName": "Nikhil",
              "lastName": "N",
              "city": "Seattle",
              "phone": 123
            }""";
    
    • formatted syntax를 사용해서 string 다루기
    String textBlockJson = """
            {
              "firstName": "%s",
              "lastName": "%s",
              "city": "%s",
              "phone": %d
            }""";
    
    String formattedTextBlockJson = textBlockJson.formatted(
            "Nikhil",
            "N",
            "Seattle",
            123);
    

    Helpful Null Pointer Exceptions (JDK 14)

    • null 발생했을 때 메시지, 플래그를 던져줌 (NPE)

    자바 13 이전

    Person person = new Person("Nikhil", "N", null);
    String lowercaseCity = persoon.getAddress().getCity().toLowerCase();
    
    /** 자바 13 이전의 nullException 메시지 
    Exception in thread "main" java.lang.NullPointerException
    at nikhil.nani.code.examples.ExamplesHelpfulNPEsTest.helpfulNpesTest1(ExamplesHelpfulNPEsTest.java:13)
    **/ 
    

    자바 14 이후

    • 실제 null 이 일어난 이유를 상세하게 설명해 준다.
    • 디버깅을 매우 쉽게 해 줌 → 어떤 값이 null 인지 알려준다.
    Person person = new Person("Nikhil", "N", null);
    String lowercaseCity = persoon.getAddress().getCity().toLowerCase();
    /** 자바 14 이후 nullException 메시지 
    java.lang.NullpointerException : Cannot invoke
    "nikhil.nani.code.examples.ExamplesHelpfulNPEsTest$Address.city()" because the return value at "nikhil.nani.code.examples.ExamplesHelpfulNPEsTest$Address()" is null
    at nikhil.nani.code.examples.ExamplesHelpfulNPEsTest.helpfulNpesTest1(ExamplesHelpfulNPEsTest.java.13)
    **/
    Person person = new Person("Nikhil", "N", new Address("", "", null));
    String lowercaseCity = person.address().city().toLowerCase();
    
    /** Prints:
    java.lang.NullPointerException: Cannot invoke "String.toLowerCase()" because the return value of "nikhil.nani.code.examples.ExamplesHelpfulNPEsTest$Address.city()" is null
    at nikhil.nani.code.examples.ExamplesHelpfulNPEsTest.helpfulNpesTest2(ExamplesHelpfulNPEsTest.java:23)
    **/

    Pattern Matching for instanceof (JDK 16)

    • 객체의 컴포넌트를 적출하기 더 간결하고 safety
    • 기존의 instanceof 사용법 → 주로 casting 할 때 아래처럼 사용
    private String withoutPatternMatching(Object input) {
        if (input instanceof String) {
            String string = (String) input;
            return "This is a String:" + string;
        }
        if (input instanceof Integer) {
            Integer integer = (Integer) input;
            return "This is an Integer:" + integer;
        }
        if (input instanceof Double) {
            Double dbl = (Double) input;
            return "This is a Double:" + dbl;
        }
        return "";
    }
    
    • Pattern Matching for Instanceof
      • input객체가 aString이고 aString은 String이라는 것을 확인
    // Note each pattern variable's scope is only within the respective flow
    private String withPatternMatching(Object input) {
        if (input instanceof String aString) {
            // Scope of aString is only within this block
            return "This is a String:" + aString;
        }
        if (input instanceof Integer anInteger) {
            // Scope of anInteger is only within this block
            return "This is an Integer:" + anInteger;
        }
        if (input instanceof Double aDouble) {
            // Scope of aDouble is only within this block
            return "This is a Double:" + aDouble;
        }
        return "";
    }
    

    Records (JDK 16)

    • Data를 A to B로 옮기려는 홀더라면?
    • https://www.infoq.com/articles/data-oriented-programming-java/
    • 모든 필드는 private final이다.
    • instance filelds는 선언할 수 없다. (immutable)
    • accessors, hashcode, toString, equals 자동생성
    • default implementations override 가능
    • 커스텀 메서드 데피니션 작성 가능
    • 읽기 전용 불편 DTO라 생각하면 되겠다. Kotlin의 Data class 

    옛날 스타일

    public final class PersonNonRecord {
        private final String firstName;
        private final String lastName;
        /**
         * Constructor, Accessor, hashcode, equals, toString
         */
    }
    

    Records 적용

    public record PersonRecord(String firstName, String lastName) {
        public String getFullName() {
            return firstName + ' ' + lastName;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "firstName='" + firstName + '\\'' +
                    ", lastName='" + lastName + '\\'' +
                    '}';
        }
    }
    

    Sealed Classes (JDK 17)

    • 원하는 클래스만 상속할 수 있도록 조작할 수 있는 기능 
      • sealed 명령어로 class 만들면 밀봉  
        • permit 뒤에 오는 sub class만 상속을 받도록 제어할 수 있다. 
      • non-sealed
        • non-final class는 sub-classes를 any number 상속할 수 있다.
    • 예시와 코드를 통한 설명

    - User (Sealed Interface)

    public sealed interface User permits Owner, Admin, Resident {
        default String login() {
            return "Logged in";
        }
    }

    - Owner : Final Class

    public final class Owner implements User {
    
    }

    - Admin : Sealed Class (permits 된 것만 상속 가능)

    public sealed class Admin implements User permits SuperAdmin {
    
    }

     

    - Resident : Non-Sealed Class

    public non-sealed class Resident implements User  {
    }

    하위 클래스

     

    - SuperAdmin, TempAdmin

    public final class SuperAdmin extends Admin {
    }
    // This test passes
    Assertions.assertEquals("Logged in", superAdmin.login());
    
    // Below class TempAdmin does not compile as TempAdmin is not permitted in the sealed hierarchy
    public final class TempAdmin extends Admin {
    }

    - DayGuest, Overnight Guest

    // Since Resident is non-sealed, it is open for any number of sub-classes, hence it opens up the hierarchy
    public final class DayGuest extends Resident {
    }
    
    public final class OvernightGuest extends Resident {
    }
    // These tests passed
    Assertions.assertEquals("Logged in", dayGuest.login());
    Assertions.assertEquals("Logged in", overnightGuest.login());

    지워진 기능

    • Nashorn Engine (JDK 15)
    • CMS Garbage Collector (JDK 14)
    • Strongly Encapsulate JDK Internals (JDK 17)
    • And a lot more deprecations…

    Garbage Collector

    • Serial GC
    • Parallel GC
    • G1 GC
    • ZGC
    • Shenandoah GC
    • Epsilon (Experimental as of Sept 2022)
    반응형

    'JAVA > 자바공부' 카테고리의 다른 글

    자바  (0) 2023.02.20
    정규식 표현 (자바, 코틀린) - 전화번호, 우편번호, 이메일  (0) 2022.10.14
    Optional<> 과 Null (이론편)  (0) 2022.07.15
    TIL - Final 키워드  (3) 2022.02.11
    TIL - 제네릭(generic) 정리  (0) 2022.02.04
Designed by Tistory.