분류 전체보기
[Item 33] 타입 안전 이종 컨테이너를 고려하라
class 리터럴의 타입은 Class가 아닌 Class 다. String.class 는 Class Integer.class 는 Class 컴파일타임 타입 정보와 런타임 타입 정보를 알아내기 위해 메서드들이 주고 받는 class 리터럴을 타입 토큰(type token) 이라 한다. 타입 안전 이종 컨테이너 패턴(type safe heterogeneous container pattern) 컨테이너 대신 키를 매개변수화한 다음, 컨테이너에 값을 넣거나 뺄 때 매개변수화한 키를 함계 제공 하는 패턴 이종 컨테이너 패턴 예제 코드 public class Favorites { public void putFavorites(Class type, T instance); public T getFavorites(Class ..
[Item 32] 제네릭과 가변인수를 함께 쓸 때는 신중하라
가변인수 메서드를 호출하면 가변인수를 담기 위해 배열이 자동으로 하나 만들어진다. 내부에서 사용하는 배열이 클라이언트에게 노출되는 문제점이 있다. 제네릭이나 매개변수화 타입을 포함한 가변 인수 메서드를 호출하면 컴파일러가 경고를 보낼것이다. 매개 변수화된 Vararg 유형으로 인한 힙 오염 가능성으로 경고가 발생한다고 확인 할 수 있다. 제네릭과 가변인수를 같이 사용하면 타입 안정성이 깨진다. public static void test1(List...stringLists){ List intList = List.of(42); Object[] objects = stringLists; objects[0] = intList; // 힙오염 발생 String s = stringLists[0].get(0); // C..
[Item 31] 한정적 와일드카드를 사용해 API 유연성을 높이라
제네릭 타입 즉, 매개변수화 타입은 불공변(invariant)이다. 아이템 28에서 살펴봤을 것이다. 하지만 불공변 방식보다 유연한 무언가가 필요하다. 아래와 같은 스택 구조가 있다고 가정해보자. public class Stack { private Object[] objects; private int index; private int top = -1; public Stack(int size) { this.objects = new Object[size]; } public void push(E e) { this.objects[index] = e; index++; } @SuppressWarnings("unchecked") public E pop() { E element = (E) this.objects[ind..
[Item 30] 이왕이면 제네릭 메서드로 만들라
클래스를 제네릭 클래스를 만들수 있고 메서드도 제네릭 메서드로 만들수 있다. 메개변수화 타입을 받는 정적 유틸리티 메서드는 보통 제네릭이다. 예를 들어 Collections 클래스의 sort를 보면 제네릭으로 구성 되어있다. 제네릭 메서드 작성법 로타입 사용 - 수용 불가 → 경고 발생 public static Set union(Set s1, Set s2) { Set result = new HashSet(s1); result.addAll(s2); return result; } 경고를 없애려면 타입 안전하게 만들어야 한다. 타입 매개변수 목록은 메서드의 제한자와 반환 타입 사이에 온다. 제네릭 메서드로 수정 public static Set union(Set s1, Set s2) { Set result = ..
[Jpa] 테스트는 어느 부분까지 해야할까?
웹 서비스를 만드는데 항상 CRUD를 접한다. 기존 레거시 코드에서는 DAO 를 직접 작성을 해서 테스트는 진행하지만 안정성을 보장해 줄 수 없다. 하지만 Spring data JPA 를 사용하여 우리는 CRUD를 정말 편하게 작성할 수 있다. Spring이 Bean으로 등록된 객체들을 관리하여 DI 를 직접 해주고 아주 편리해졌다. 오늘은 이 부분에 대해 테스트를 어디까지 진행해야 할 까? 라는 주제를 정해 글을 써보겠습니다. DAO 테스트 작성은 간단하다 하지만 귀찮다! DAO를 작성하여 직접 사용하시는 분은 CRUD를 가지고 테스트 하시는 일은 매우 간단한 일이다. 테스트도 매우 간단하게 할 것이다. 저장이라는 행위를 테스트 한다고 가정해보면 해당 엔티티 데이터를 생성하여 데이터베이스에 접근하고 데..
[Clean code] Clean code function 원칙을 지켜가며 나만의 코드 리팩터링하기
이 글은 클린 코드 강의를 보며 나만의 코드를 리팩토링 하는 글입니다. 클린 코드 중 함수의 원칙 한가지 일만 해야 한다. 함수의 크기는 작아야 한다. indentation, while, nested if 등은 없어야 한다 잘 지어진 서술적인 긴 이름을 갖는 많은/작은 함수들로 유지해야 한다. 원칙을 지키면서 리팩터링 진행해보는 글을 써보겠습니다. 아래의 코드는 주로 미니 프로젝트를 진행하면서 많이 보는 코드이다. 주석을 보면 멤버 조회 아이템 조회 배송정보 생성 주문상품 생성 주문 생성 주문 저장 6가지 행위들이 있다. 주석이 없으면 이해하는데 시간이 걸리는 코드이고 OrderService에서의 책임이 아닌 행위들이 많아 안티 패턴으로 보인다. 그러면 코드를 어떻게 리팩터링하면 좋을까? 먼저 책임과 역..
[Clean code] OOP에서 재사용이 뭔가?
클린 코드 강의를 듣고 내용을 정리한 글이니 아래 참조 링크를 참고하시기 바랍니다. 책임과 역할을 잘 알고 분류해야 한다. 예로는 UserService 라는 서비스 클래스가 어떠한 역할을 하는지 알아야 한다. 대부분 crud라는 기능이 있을 것인데, 분류를 해보면 Read와 Write 라는 책임과 역할이 있다. 이러한 책임과 역할을 따로 빼면 UserReadService와 UserWriteService라는 두 클래스로 뽑아 낼 수 있다. 구현 상속이 객체 지향에서의 재사용이 절대 아니다! 상속은 객체에게 다형성을 제공한다. 구현 상속 상위 타입의 구현을 재사용 인터페이스 상속 타입 정의만 상속 구현 상속 복잡한 상속 관계에 있는 클래스를 재사용하는 것이 아니고 공통적인 기능을 뽑아 하나로 만들어 공통 기..
[Jpa] 단일 테이블 전략의 상속 관계 매핑 이슈
Item 테이블을 단일 테이블 전략으로 만들어 발생한 이슈에 대해 포스팅 해보겠습니다. Book, Movie, Album 이라는 엔티티의 공통 속성을 뽑아 Item 이라는 엔티티를 상위 타입으로 만들었다. 여기서 save() 를 하는 코드에서 문제가 발생한다. Item이 상위 타입이므로 하위 타입이 들어와도 저장이 되지만 web 계층에서 dto를 보내어 저장할 때가 애매모호 하다. 처음 구현 한 코드는 아래와 같다. 각각의 아이템 마다 조건문으로 타입 체크를 하고 dto에서 엔티티로 변환하여 save() 하는 코드이다. 해당 아이템의 타입 체크를 하여 타입에는 문제가 되지 않는다. 하지만 아이템 종류들이 추가 될 때 마다 saveItem() 안에 조건문과 save() 메소드가 추가 되어야 한다. 아이템의..
[Item 29] 이왕이면 제네릭 타입으로 만들라
책에는 Stack 클래스를 예로 들었는데 이 글은 stack클래스를 모방한 Cage 클래스로 예를 들겠습니다. public class Cage { private Object[] cages; private int size; private static intDEFAULT_SIZE= 10; public Cage() { this.cages = new Object[DEFAULT_SIZE]; } public void push(Object o) { checkCapacity(); this.cages[size++] = o; } public Object pop() { if (size == 0) { throw new EmptyStackException(); } Object result = cages[--size]; cage..
[Item 28] 배열보다는 리스트를 사용하라
배열과 제네릭 타입의 차이 1. 공변과 불공변 배열은 공변이다 sub가 super의 하위 타입이라면 sub[]는 배열 super[]의 하위 타입이 된다. Object[] objectArray = new Long[1]; objectArray[0] = "어떤 타입이든 저장할 수 있는데.........."; // ArrayStoreException 던짐 배열은 런타임에도 자신이 담기로 한 원소의 타입을 인지하고 확인한다. 그래서 컴파일에는 아무런 영향을 끼치지 않지만 런타임 시 ArrayStoreException을 던진다. 제네릭은 불공변이다. 서로 다른 타입 type1과 type2가 있을 때 List 은 List 의 상위 타입도 아니고 하위 타입도 아니다. // 컴파일 시 예외 List list = new ..
[Java] 지네릭 변성
최범균님의 강의를 듣고 정리한 내용입니다. 참조 : https://www.youtube.com/watch?v=PtM44sO-A6g&list=PLwouWTPuIjUg0dmHoxgqNXyx3Acy7BNCz&index=18&ab_channel=최범균 강의 내용이 유익하고 Generic 개념을 다시 정리해보자 글을 포스팅하려고 합니다. 좋은 강의가 많으니 한번 보시면 좋을 거 같습니다. 들어가기전. 지네릭은 컴파일러에게 타입을 알려주고 해당 타입의 안정성을 주는 장점이 있습니다. 프로그래밍에서 변성, 무변성, 공변, 반공변 등의 특징들을 많이 들어보셨을 겁니다. 이러한 특징들을 지네릭이 가지고 있어 문제점과 문제점의 개선 방법 등을 적어 보겠습니다. 지네릭과 하위 타입 public class Student ex..
[Jpa] 대댓글 계층구조 연관관계 메소드 이슈
게시판 대댓글을 구현하는데 @OneToMany와 @ManyToOne 을 사용하여 양방향 매핑을 하여 구현하는 것을 적어보려 합니다. 먼저 대댓글의 구조는 아래와 같을 것이다. - 댓글 |- 댓글 |- 댓글 |- 댓글 |- 댓글 |- 댓글 |- 댓글 |- 댓글 이러한 계층 구조로 구현을 해야 한다. 처음 구현한 방법은 아래와 같다. @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "PARENT_ID") private Comment parent; @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval..
[Spring boot] 순환 참조 이슈
@ManyToOne 과 @OneToMany 의 양방향 관계 매핑을 하여 대댓글을 구현하는데 만난 이슈를 적어보려합니다. 먼저 클라이언트에서 서버로 데이터를 주고 받을 수 있는 방법은 직렬화를 통해서 데이터를 주고 받고 한다. spring에선 jackson 라이브러리를 활용하여 json으로 통신이 가능하다. jackson은 공개 필드에 관해서만 직렬화를 가능하게 해준다. 비공개 필드는 Getter을 활용하고 Setter로 접근하여 역직렬화를 시도한다. 참조: https://www.baeldung.com/jackson-field-serializable-deserializable-or-not 이슈의 과정을 살펴보자. 대댓글과 같은 계층 구조를 아래와 같이 연관관계 설정을 하였다. @ManyToOne(fetch..
[Jpa] Cascade
Cascade 개념 보통 엔티티 관계는 다른 엔티티의 존재에 의존한다. 대상 엔티티에 대해 일부 작업을 수행하면 연결된 엔티티에 동일한 작업이 적용된다. 즉 , 한쪽이 삭제가되면 해당 엔티티를 의존한 엔티티도 삭제가 되어야 한다. JPA Cascade 유형 all persist merge remove refresh detach CascadeType.ALL 모든 작업을 부모 엔티티에서 자식 엔티티로 전파한다. 예제 코드 연관관계 설정은 아래와 같이 하였다. Review @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "MEMBERS_ID") @ToString.Exclude private Member member; Member Member 엔티티의 pk 값을 ..
[Item 27] 비검사 경고를 제거하라
제네릭을 사용하기 시작하면 수많은 컴파일러 경고들을 마주치게 되는데 이러한 경고들은 가능한 많이 제거하는 것이 좋다. 경고들을 모두 제거 한다면, 그 코드는 타입의 안정성이 보장된다. 비검사 경고는 쉽게 제거할 수 있다. List list = new ArrayList(); 컴파일 경고가 나오는 코드다. List list = new ArrayList(); 제네릭 타입으로 인스턴스를 생성하고 뒤에 다이아몬드 연산자를 생성해야 한다. 경고를 제거할 수 없지만 타입이 안전하다고 보장되면 경고를 숨겨라 @SuppressWarnings("unchecked")으로 경고를 숨기자. 단, 타입 안정성을 검증하지 않고 경고를 숨기면 절대 안된다. 해당 코드는 경고 없이 컴파일되지만, 런타임 시 여전히 ClassCastEx..