Jdk 살펴보던 중 재밌어 보이는 기능들 (갱신 중)

강보훈·2021년 11월 22일
0

JDK연대기

목록 보기
1/14

목차

  1. Record
  2. Microbenchmark Suite
  3. Text blocks
  4. Helpful NullpointerException
  5. JFR Event Streaming
  6. Switch

Record

  • Kotlin의 데이터클래스와 비슷한 느낌이다. 데이터를 표현하기 위해 사용한다.
  • 기능
    • 모든 필드를 포함한 생성자를 가진다.
    • 모든 필드는 private final로 고정
    • 모든 필드의 getter 생성
      • getName()의 형식이 아닌 필드의 이름만 가져온다.
    • toString, equals, hashCode 생성
    • annotation 적용 가능
    • 다른 클래스에서 inner class로 Record 생성가능 -> jdk 16에서 가능해짐
  • 제한사항

    • extends 불가능
  • 생성 방식

    • 기본 타입들은 Wrapper 클래스를 집어넣어야한다.
    • 생성자를 명시적으로도 생성 가능하다.
    • static 변수도 가질 수 있다.
    • 메소드도 생성가능하다.
    public record Person(
        String name,
        Integer age,
        Job job
    ) { 
    	public Person{
      	//Do Something
      }
      
      public static int test = 100;
    
      public void testUp() {
          test++;
      }
    
      public static int getTest() {
          return test;
      }
      
      private void testDown() {
          test--;
      }
    }
  • Json으로 만들기
    Jackson-databind를 통해 Json만들기 가능.

    public record Person2(
        @JsonProperty("Name") String name,
        @JsonProperty Integer age,
        @JsonIgnore Job job
     ) {}
     
     Main에서
     Person person = new Person("Arakene", 25, new Job("Android Developer"));
     ObjectMapper mapper = new ObjectMapper();
     String json = mapper.writeValueAsString(person);

    실행 결과

    {"Name":"Arakene","age":25}

Microbenchmark Suite

  • 성능 테스트의 도구 중 하나로 JMH(Java Microbenchmark Harness)란 이름을 있다.

  • Dependency 설정

            <dependency>
                <groupId>org.openjdk.jmh</groupId>
                <artifactId>jmh-core</artifactId>
                <version>1.32</version>
            </dependency>
            <dependency>
                <groupId>org.openjdk.jmh</groupId>
                <artifactId>jmh-generator-annprocess</artifactId>
                <version>1.32</version>
            </dependency>
  • 테스트 코드

    @State(Scope.Thread)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public class BenchMarkTest {
    
       int max = 999;
       List<Integer> testList = new ArrayList<>();
    
       @Setup //테스트 전 준비 과정
       public void set(){
           for (int i = 0; i < max; i++) {
               testList.add(i);
           }
       }
       @BenchmarkMode(Mode.AverageTime)
       @Benchmark //테스트할 메소드
       public void originLoopWithGetSize() {
           int sum = 0;
           for (int i = 0; i < max; i++) {
               sum += testList.get(i);
           }
       }
    }
    public static void main(String[] args) throws IOException, RunnerException {
           Options opt = new OptionsBuilder()
                   .include(BenchMarkTest.class.getSimpleName())
                   .forks(1)                       
                   .build();
           new Runner(opt).run();                 
    }
  • Annotations

    • @State
      테스트에 사용하는 인자의 상태를 지정 가능하다. 테스트 진행에 따라 값이 변경되야 할수도 항상 같은 값이여야 할 경우도 있는데 이걸 @State로 지정한다.
      • Thread -> Thread 별로 인스턴스 생성
      • Benchmark -> 동일 테스트 내 모든 Thread에서 동일 인스턴스 공유(MultiThreading 테스트)
      • Group -> Thread 그룹마다 인스턴스 생성
    • @BenchMark
      벤치마크를 어떤 방법으로 수행할 건지
      • Throughput -> 초당 작업수 측정, 기본값
      • AverageTie -> 작업이 수행되는 평균 시간 측정
      • SampleTime -> 최대, 최소 시간 등 작업이 수행하는데 걸리는 시간 측정
      • SingleShotTime -> 단일 작업 수행 시간을 측정, JVM warmup없이 수행할때 적격
      • All -> 위 4개 모두 실행
    • @OutputTimeUnit
      결과 출력 시 사용할 시간 단위 설정, TimeUnit클래스 사용
      • Nano -> 기본값
    • @Setup, @TearDown
      둘 모두 메소드에 적용 가능, @Setup은 Junit의 Before와 같은 일을 한다. 테스트 실행 전 설정하기 위해서 사용한다. @TearDown은 Junit의 After와 같은 일을 한다. 테스트 후 처리 작업에 사용한다. 둘 모두 Level을 설정해 줄 수 있다.
      • Trial -> 벤치마크 실행할때 마다 한번씩 호출
      • Iteration -> 벤치마크 반복할 때마다 호출
      • Invocation -> 벤치마크 메소드를 호출할 때마다 호출
  • Options
    Annotation으로 벤치마크의 여러 설정을 할 수 있지만 Option을 통해서도 조정이 가능하다.

    Options opt = new OptionsBuilder()
                    .include(BenchMarkTest.class.getSimpleName())
                    .warmupIterations(1)          
                    .measurementIterations(1)     
                    .forks(1)
                    .build();
    new Runner(opt).run(); 

Text Blocks

멀티 라인으로 문자열을 작성할 때 매우 좋은 기능이다.

  • 기존의 문자열
       String query = "SELECT \"name\", \"email\" FROM \"users\"\n" +
              "WHERE \"username\" = 'kbh';";
  • Text blocks 적용
       String  query = """
       	SELECT "name", "email" FROM "users"
         	WHERE "username" = 'kbh';
         	""".stripIndent();
  • 화이트 스페이스도 같이 들어가기때문에 stripIndent()를 마지막에 꼭 써주는 것이 좋다.
    불필요한 공간을 제거하고 내가 원하는 데이터만 집어 넣을 수 있다.

Helpful NullPointerException

  • 기존의 NPE
    기존에는 chain methods에서 npe가 발생할 경우 정확히 어디서 발생한 것이 알 수 없었다.

    • JDK 14 이후

      String name = person.personDetails.name;
      를 실행한 경우
      Exception in thread "main" java.lang.NullPointerException: Cannot read field "name" because "person.personDetails" is null
      			at Main.main(Main.java:6)
      와 같이 어디서 null이 나온건지 알 수 있다.
    • 사용 방법
      Intellij 기준
      VM Options에 -XX:+ShowCodeDetailsInExceptionMessages을 추가해주면 된다.

    • 사용 결과

      String name = person.personDetails.name;
      이 코드를 실행시키면
      Exception in thread "main" java.lang.NullPointerException: Cannot read field "name" because "person.personDetails" is null
      			at Main.test(Main.java:42)
      			at Main.main(Main.java:24)
      
      peronalDetails가 null 인지 name이 null인지 알 수 있다.
      
profile
신입 안드로이드 개발자입니다!

0개의 댓글