Spring Boot 및 Java 16 레코드

In this article, we will discuss Java 16's newest feature, Records. Then we will apply this knowledge and use it in conjunction with a Spring Boot application.


소개하다.


2021년 3월 16일, 자바16이 정식으로 발표되었습니다. 이 새로운 버전이 발표됨에 따라 흥미로운 새로운 기능이 대량으로 추가되었습니다.변경 사항에 대한 자세한 내용은 release notes를 참조하십시오.본고의 중점은 자바 기록인데 JEP 395과 함께 교부한 것이다.기록은 처음에 JDK 14에서 JEP 359이 제시한 미리보기 기능으로 도입되었지만 JDK 15에서는 JEP 384에서 미리보기를 진행했다.그러나 JDK 16의 경우 레코드가 더 이상 미리보기 상태가 아닙니다.
자바 챔피언 마라 쿱타가 트위터에 올린 이 여론조사에 따르면 내가 기록을 선택한 것은 자바 16에서 가장 인기 있는 기능이기 때문이다.

마라고프타
에마라 고타

이 영화는 곧 상영될 것이다.가장 좋아하는 Java 16 언어 기능에 대해 투표하십시오.
2021년 3월 4일 오전 00:41
나도 비슷한 조사를 했지만 자바8 이후의 특성에 초점을 맞췄다.럼버스, 스트림, 옵티올은 이번 투표에서 가장 많은 표를 얻었다.Java8이 여전히 널리 사용되고 있기 때문에 결과는 의외가 아니다.그러나 불행하게도 새로운 자바 버전에는 많은 새로운 기능과 개선이 추가되었다.그러나 기능의 경우 개발자의 입장에서 볼 때 자바8은 게임 규칙의 변화자임에 틀림없다.

아시 조두리👨🏻‍💻🧔🏻👨‍👩‍👦
@ 아시에시

당신은 8 이상 버전 중의 어떤 기능을 가장 좋아합니까?재방문 마스터 코드 극객
2021년 1월 24일 오전 5:05
Java 및 기술에 대한 자세한 내용은
그렇다면 자바 기록에 대해 놀랄 만한 점이 무엇인지 토론해 보자.

기록이란 무엇입니까?


JEP 395에 따르면:

Records are a new kind of class in the Java language. They act as transparent carriers for immutable data with less ceremony than normal classes. Records can be thought of as nominal tuples.


JEP의 또 다른 말은 전형적인 데이터 캐리어 클래스를 작성할 때 개발자들의 좌절감을 명확하게 설명한다.

Properly writing such a data-carrier class involves a lot of low-value, repetitive, error-prone code: constructors, accessors, equals, hashCode, toString, etc. For example, a class to carry x and y coordinates inevitably ends up like this:


class Point {
    private final int x;
    private final int y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    int x() { return x; }
    int y() { return y; }

    public boolean equals(Object o) {
        if (!(o instanceof Point)) return false;
        Point other = (Point) o;
        return other.x == x && other.y == y;
    }

    public int hashCode() {
        return Objects.hash(x, y);
    }

    public String toString() {
        return String.format("Point[x=%d, y=%d]", x, y);
    }
}
개발자들이 가장 많이 사용하는 또 다른 선택은 템플릿 파일 처리를 IDE에 남겨두는 것입니다.예를 들어 Intellij를 사용하면 Command+N 단축키만 누르면 구조 함수, Getter, setter, equals,hashCode, toString 등을 생성할 수 있다.템플릿 코드는 여전히 존재합니다.

Java 16 레코드의 경우 코드는 한 줄에 불과합니다.멋있지 않아요?
record Point(int x, int y) { }
여기서 레코드 클래스 선언은 이름, 선택 가능한 유형 매개변수, 헤드 및 바디로 구성됩니다.

레코드 해독


Java record 클래스 내부는 IntelliJ IDE와 함께 제공된 반컴파일러를 사용하여 검사하거나 javap 명령행 유틸리티를 사용하여 검사할 수 있습니다.내부 구조를 이해하기 위해 다음과 같은 기록류를 만들었습니다.
public record State(String name, String capital) {}
다음은 역컴파일된 Java 레코드 클래스입니다.나는 클래스 파일 내부를 검사하기 위해 javap 명령행 실용 프로그램을 사용했다.
 $ javap State.class
다음은 출력입니다.
Compiled from "State.java"
public final class com.example.indianstates.State extends java.lang.Record {
  public com.example.indianstates.State(java.lang.String, java.lang.String);
  public final java.lang.String toString();
  public final int hashCode();
  public final boolean equals(java.lang.Object);
  public java.lang.String name();
  public java.lang.String capital();
}
이상의 출력에서 다음과 같은 결론을 얻을 수 있다.
  • 상태 기록 클래스가 확장 중java.lang.Record 추상 클래스입니다.
  • 상태 기록 클래스는final로 표시되며 extends 키워드를 사용하여 확장할 수 없습니다.
  • hashCode(), equals(), toString()와 규범화된 구조 함수는 우리를 위해 은밀하게 생성된 것이다.
  • 설정기나 수령기가 없고 액세서리만 있습니다.
  • 클래스 성명에는 setters와final이 없습니다. 이것은 상태를 변경할 수 없기 때문에 기록은 변할 수 없습니다.
  • 또한 작성 테스트를 통해 이러한 요점을 더욱 검증할 수 있습니다.
        @Test
        public void testRecordAccessors() {
            String name = "Maharashtra" ;
            String capital = "Mumbai" ;
            State state = new State("Maharashtra", "Mumbai");
            Assert.assertEquals(name, state.name());
            Assert.assertEquals(capital, state.capital());
        }
    
        @Test
        public void testRecordToString() {
            State state = new State("Maharashtra", "Mumbai");
            System.out.println(state);
            //Output:-State[name=Maharashtra, capital=Mumbai]
        }
    
        @Test
        public void testRecordEquals() {
            State state1 = new State("Maharashtra", "Mumbai");
            State state2 = new State("Maharashtra", "Mumbai");
            Assert.assertTrue(state1.equals(state2));
        }
    
        @Test
        public void testRecordHashCode() {
            State state1 = new State("Maharashtra", "Mumbai");
            State state2 = new State("Maharashtra", "Mumbai");
            Assert.assertEquals(state1.hashCode(), state2.hashCode());
        }
    
    일반 클래스에 비해 기록 클래스의 성명에는 약간의 제한이 있다.체크아웃JEP 395은 이러한 제한 사항을 이해합니다.

    용목산과 레코드, 친구 아니면 적?


    @ Lombok 주석을 사용하고 있을 수도 있습니다. 예를 들어 @ Value 주석은 자바 기록과 가장 가깝습니다. (같지 않으면)그리고 의존항과 주석을 제거할 수 있는 크리스마스 트리를 만들 수 있다.나는 일을 간단하게 할 수도 있고, 어떤 경우에는 용목무를 교체하는 것이 의미가 있을 수도 있다.단, 로붐을 제공하는 주석이 아닌 다른 기능에 사용할 수도 있습니다.나를 믿어라. 비록 자바 기록은 자바 애호가들에게 인기 있는 기능이지만, 자바 기록은 롬보를 대체하지 않을 것이다. 적어도 현재는 그렇지 않을 것이다.너는 나를 믿지 않니?Stack Overflow의 Brain Goetz에서 이것answer을 보십시오.
    의존 관계의 문제도 당신의 문제로 변할 때, 프로젝트에 어떤 의존 관계를 추가했는지 조심해야 한다.

    Spring Boot 및 Java 로깅


    2.5.0-M1 에디션부터 Spring Boot은 Java 16에 기본support을 제공합니다.작업하는 Spring Boot 응용 프로그램이 있는데 이 응용 프로그램을 사용하여 Java 레코드를 보여 줍니다.소스 코드를 사용할 수 있습니다here.
    이것은/states 또는/state를 통해 접근할 때 간단한 Spring 안내 프로그램입니다.name=statename은 모든 인도주와 수도를 표시합니다.이 응용 프로그램은 응용 프로그램의 시작 부분에 줄을 삽입하는 메모리에 있는 H2 데이터베이스를 사용합니다.
    예전과 같이 start를 사용할 수 있습니다.봄.io는 앞서 설명한 대로 Spring Boot 응용 프로그램의 스텁을 생성합니다. 2.5를 선택해야 합니다.x 이정표 버전.
    다음은 REST 컨트롤러 클래스의 모양새입니다.
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    @RestController
    public class Controller {
        private final StateService stateService;
    
        public Controller(StateService stateService) {
            this.stateService = stateService;
        }
    
        @GetMapping("/states")
        private List<State> getAllStates() {
            return stateService.findAll();
        }
    
        @GetMapping(value = "/state")
        private String getSpecificState(@RequestParam(required = false, name = "name", defaultValue = "Maharashtra") String name) {
            return stateService.findByName(name);
        }
    }
    
    
    상태 기록 클래스 대상의 목록을 되돌려주는 getAllState () 방법을 주목할 수 있습니다.
    우리는 이미 국가기록 수업을 보았다.이 점은 변하지 않았다.
    public record State(String name, String capital) {}
    
    다음은 StateRepository류로 이루어진StateService인터페이스입니다.
    import java.util.List;
    
    public interface StateRepository {
        List<State> findAll();
    
        String findByName(String name);
    }
    
    @Service
    public class StateService implements StateRepository{
        private final JdbcTemplate jdbcTemplate;
    
        public StateService(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        }
        private final RowMapper<State>  rowMapper = (rs, rowNum) -> new State(rs.getString("name"),rs.getString("capital"));
    
        @Override
        public List<State> findAll() {
            String findAllStates = """
                    select * from States
                    """;
            return jdbcTemplate.query(findAllStates, rowMapper);
        }
    
        @Override
        public String findByName(String name) {
            String findByName = """
                    select capital from States where name = ?;
                    """;
            return jdbcTemplate.queryForObject(findByName, String.class, name);
        }
    }
    
    StateService류의 구조 함수를 사용하여 자동으로 연결한다.Spring JdbcTemplate를 사용하여 메모리 H2 데이터베이스에서 Controller 레코드 클래스 목록을 조회하고 반환하는findAll () 방법이 있습니다.보시다시피, 우리는 State 함수 인터페이스를 사용했고, JdbcTemplate는 이 인터페이스를 사용하여 줄에 따라 ResultSet의 줄을 비추고 현재 줄의 줄 대상을 되돌려줍니다.리코더 클래스를 초기화하는 데 RowMapper 키워드를 사용했습니다. 이것은 자바의 일반 클래스처럼 리코더 클래스를 초기화할 수 있음을 의미합니다.나는 또한 자바 15Text Blocks 기능을 사용했는데 이것은 SQL 조회와 JSON 문자열 값의 가독성을 향상시키는 데 도움이 된다.
    그러나 이 프로그램에서 기록을 사용하기 시작했을 때 문제가 발생했습니다.이전에 내가 사용한 것은 new 인데, 내가 Lombok을 사용하지 않고 BeanPropertyRowMapper, 클래스에 기록을 남겼을 때 다음과 같은 이상이 발생했다.
    2021-03-19 02:01:55.434 ERROR 66059 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.indianstates.State]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.example.indianstates.State.<init>()] with root cause
    
    이상화Statedocumentation에서 알 수 있듯이 우리는 BeanPropertyRowMapperrecords 클래스에 기본적 또는 무변수 구조 함수를 명시해야 하기 때문에 자바에서records 클래스에 대한 흥미로운 발견을 초래했다.
    이 오류를 해결하기 위해서, 나는 State 기록 클래스에 무변수 구조 함수를 천진스럽게 추가했다.
    public record State(String name, String capital) {
        public State() {
        }
    }
    
    그러나 이로 인해 다음과 같은 컴파일 오류가 발생했다.

    Non-canonical record constructor must delegate to another constructor


    이 컴파일 문제를 해결하기 위해 다음과 같은 구조 함수를 추가했지만 응답에서 값을 생성합니다 State.
    public record State(String name, String capital) {
        public State() {
            this(null,null);
        }
    }
    
    그리고 나는 IntelliJ의 특성을 빌려 이 기록 클래스에 구조 함수를 생성했다.그것은 나에게 다음과 같은 옵션을 제공했다.

    나는 이런 선택을 시도했지만 같은 결과를 얻었다.나는 이미 이 옵션들이 통하지 않는다는 것을 알았지만, 나는 나의 운을 시험해 보았다. 이것은 나로 하여금 어떻게 사용하는지 null 의 기록을 알고 싶다. 나는 아직 답이 없지만, 나는 더욱 발굴할 것이다.코드에 문제가 있거나 더 좋은 답이 있는 것을 발견하면 저에게 알려 주십시오.
    업데이트: - 이 이상을 Spring Boot Gitter 채팅에 올렸는데 이 답을 얻었습니다.

    BeanPropertyRowMapper can't be used with records since it consists of creating an instance of a Java Bean with its no-arg constructor and then calling its setters to populate the bean. But records don't have a no-arg constructor and are immutable and thus don't have setters. So, either use a traditional Java Bean or use records, but then don't use BeanPropertyRowMapper.


    공평합니다.분명히 BeanPropertyRowMapper.는 기록에 사용할 수 없다.
    이제 끝이야.즐거움 코드.

    결론


    본고에서, 당신은 기록이 변할 수 없는 데이터 캐리어 클래스라는 것을 알았습니다. 이것은 우리가 작성한 대량의 샘플 코드를 감소시켰습니다.그리고 우리는 기록 클래스의 내부 구조를 살펴보았는데hashCode (), equals (), toString (), 구조 함수는 컴파일러가 은밀하게 생성한 것을 발견했다.그리고 우리는 당신이 정말로 Lombok과 같은 외부 라이브러리로 기록을 비교하거나 교체해서는 안 된다는 것을 알게 되었다. 왜냐하면 이 두 라이브러리는 서로 다른 일에 대해 서로 다른 도구이기 때문이다.
    마지막 절에서 데이터베이스(또는 일부 외부 서비스)에서 데이터를 가져온 경우 Spring Boot 응용 프로그램 예제에 대한 기록이 잘 되어 있음을 알 수 있습니다.우리는 BeanPropertyRowMapper를 사용할 때도 몇 가지 문제점을 발견했고 이를 기록에 사용할 수 없다는 결론을 얻었다.

    나를 지지하다


    만약 당신이 방금 읽은 내용을 좋아한다면 다음 그림의 링크를 클릭하여 나에게 커피 한 잔을 사 줄 수 있다.

    좋은 웹페이지 즐겨찾기