equals는 일반 규약을 지켜 재정의하라 equals 메서드는 재정의하기 쉬워 보이지만 자칫하면 끔찍한 결과를 초래한다. 문제를 회피하는 가장 쉬운 길은 아예 재정의하지 않는 것이다. 그냥 두면 그 클래스의 인스턴스는 오직 자기 자신과만 같게 된다. 아래 중 하나에 해당한다면 재정의하지 않는 것이 최선이다. 재정의 하지 않는 것이 좋은 경우 각 인스턴스가 본질적으로 고유하다. 값을 표현하는게 아니라 동작하는 개체를 표현하는 클래스가 여기 해당한다. Thread가 좋은 예로, Object의 equals는 이러한 클래스에 맞게 구현되었다. 인스턴스의 논리적 동치성(logical equality)을 검사할 일이 없다. 예를 들어 java.util.regex.Pattern은 equals를 재정의해서 두 Pat..
Mockito를 사용하여 Service단 테스트 코드를 작성 중 doReturn(…).when(…) 과 when().thenReturn() 구문이 동일하게 동작하는 것으로 보여 무슨 차이가 있는지 찾아보았다. //순서만 다를 뿐 동작은 같다. //when().thenReturn() when(projectRepository.findById(any(Long.class))).thenReturn(Optional.empty()); //doReturn().when() doReturn(Optional.empty()).when(projectRepository.findById(any(Long.class))); 결론부터 얘기하자면 when().thenReturn()을 사용하는 것이 권장된다고 한다. //Mockito ja..
JPA 및 Hibernate의 1차 캐시 JPA(Hibernate)에서 엔티티 매니저를 사용해서 persist, merge, remove를 했을 때 엔티티의 상태는 변경(New, Managed, Removed,..)되지만, flush나 트랜잭션이 커밋될 때까지 데이터베이스에 동기화되지는 않는다. 트랜잭션이 커밋되었을 때 변경을 한 번에 데이터베이스에 반영하기 위해 JPA(Hibernate)의 영속성 컨텍스트 내부에는 엔티티를 저장하는 1차 캐시가 존재한다. 1차 캐시는 트랜잭션이 시작되고 종료될 때까지만 유효한 트랜잭션 단위의 캐시다. 애플리케이션 단위의 캐시를 사용하고 싶다면 2차 캐시를 활성화해야 한다. Hibernate의 1차 캐시 구현 내부적으로 Hibernate는 엔티티를 다음과 같은 Map에 ..
김영한님의 자바 ORM 표준 프로그래밍을 읽고 정리한 내용입니다. 지금껏 JPA를 사용해보며 영속성 컨텍스트에 대한 개념적인 이해는 하고 있었지만 엔티티의 생명주기까지 글로 정리해보면 더 기억에 남을 것 같아 작성하게 되었다. 영속성 컨텍스트란? JPA를 이해하는 데 가장 중요한 용어는 영속성 컨텍스트로 해석하자면 엔티티를 영구 저장하는 환경이라는 뜻이다. em.persist(member); 엔티티 매니저를 사용해서 위와 같은 코드를 실행했을 때, 단순히 회원 엔티티를 저장한다고 생각하지만 정확히는 엔티티 매니저를 사용해서 회원 엔티티를 영속성 컨텍스트에 저장하는 것이다. 영속성 컨텍스트는 엔티티 매니저를 생성할 때 하나가 만들어지고 엔티티 매니저를 통해 영속성 컨텍스트에 접근하고 관리할 수 있다. 엔티..
equals와 hashCode Java의 모든 클래스는 Object 클래스를 암시적으로 상속받고 있다. 모든 클래스의 조상인 Object 클래스에서는 모든 클래스가 공통적으로 포함하고 있어야 하는 기능을 제공한다. 그 중 오늘은 equals와 hashCode 메서드에 대해서 알아보려고 한다. 그 전에 객체의 동일성과 동등성에 대한 개념부터 짚고 넘어가야 한다. 객체의 동일성과 동등성 동일성(Identity) 동일성은 두 객체가 같은 메모리 주소 값을 가지는 경우를 의미한다. 같은 주소 값을 가지고 있기 때문에 두 변수가 모두 같은 객체를 가리킨다. 두 변수의 동일성은 == 연산자를 통해 확인할 수 있다. 또한 후술할 equals 메서드의 기본 구현도 == 연산자를 통해 이루어지기 때문에 동일성을 비교한다..
Querydsl을 사용하면서 CustomRepository를 만들고 테스트할 때, @DataJpaTest 에서 테스트 코드 실행 시 아래와 같은 오류가 발생할 수 있다. java.lang.IllegalStateException: Failed to load ApplicationContext ... Error creating bean with name 'projectRepositoryImpl' defined in file 이는 SpringBootTest에서는 모든 빈이 주입이 되기 때문에 문제가 없지만 DataJpaTest의 경우는 QueryFactory Bean이 주입되지 않아서 발생한다. 이를 해결하기 위해서는 TestConfiguration에서 테스트 환경을 위한 Bean을 생성해주면 된다. TestC..
Stream이란? 기존 Java에서 컬렉션 데이터를 처리할 때 for, foreach 반복문을 사용하며 컬렉션 요소들을 하나씩 다뤄야 했다. 이때 코드가 복잡해지는 문제점을 해결하기 위해 JDK 8부터 함수형 프로그래밍이 가능하도록 구현된 API로 데이터를 추상화하고 처리하는데 자주 사용되는 함수들이 정의되어 있다. Stream API를 사용하지 않는 경우와 Stream API를 사용한 경우의 코드를 비교해보도록 하겠다. 배열과 리스트를 정렬하는 코드에서 Stream API를 사용하지 않는 경우 아래와 같이 작성할 수 있다. Stream API 미사용 String[] fruitArr = {"banana", "apple", "grape", "orange"}; List fruitList = Arrays.as..
Optional이란? Java 8에 도입된 타입으로 NullPointException 예외를 방지하기 위해 등장했다. Optional 객체는 변수 또는 함수 호출의 반환 값을 래핑하며 다음 상태 중 하나일 수 있다. present - 래핑하는 데이터가 null이 아닌 경우 empty - 데이터가 null 값인 경우 래핑하는데 사용 Optional 클래스의 메서드 Optional 메서드를 코드 예제와 함께 알아보도록 하겠다. 아래 예제에서 Member에는 ‘Inwoo’라는 이름을 가진 Member는 존재하지만 ‘Donghun’이라는 멤버는 존재하지 않는다고 가정한다. 1. isPresent() isPresent()를 사용하여 옵셔널 객체의 상태를 확인할 수 있다. 옵셔널 객체가 비어 있으면 false를 반..