Item44는 표준 함수형 인터페이스를 사용하라 말한다 람다 등장 이전에 구현체마다 다른 행동을 지정하기 위해 사용하는 방법으로 템플릿 메서드 패턴이 있었다 상위 클래스의 메서드를 오버라이딩해 동작을 변경할 수 있는데 아래와 같은 형태다 public abstract class Animal { void yahoo() { System.out.println("YAHOO"); } } public class Cat extends Animal { @Override void yahoo() { System.out.println("CAT YAHOO"); } } public static void main(String[] args) { Animal animal = new Cat(); animal.yahoo(); } 실제 동..
Item43에서는 람다보다 메서드 참조를 사용하라 말한다 메서드 참조를 사용하는 이유는 간결함 때문이다 람다를 사용해 익명 함수를 대체하고 간결하게 표현하기로 한 거 끝까지 가보자는 것이다 메서드 참조를 사용하는 방법은 네 가지가 있다 1. static method reference 형태로 참조한다 2. instance method reference (bound receiver) 형태로 참조한다 3. instance method reference (unbound receiver) 메서드 형태로 참조한다 4. constructor reference 연산자 형태로 참조한다 이 중 한정적과 비한정적의 차이가 확 와닿지 않아서 좀 더 찾아봤다 책에서는 수신 객체를 특정하느냐 아니냐로 한정적과 비한정적 메서드 참..
Item42에서는 익명 클래스보다 람다를 사용하라 말한다 lambda expression은 자바 8부터 등장해 자바에서도 함수형 프로그래밍이 가능해지도록 본격적인 FP의 장을 열었다 자바8 이전에는 FP가 불가능했느냐 하면 그건 아니지만 욕먹어도 쌀 수준의 코드를 작성해야 했다 람다는 왜 나왔을까? 구현해야 할 코드가 단순하더라도 익명 클래스를 직접 구현하는 그 과정이 아주 지독하기 때문이란다 아래 코드에서 JDK 1.8 이전 방식을 보면 절로 한숨이 나온다 // JDK 1.8 이전 방식 Collections.sort(words, new Comparator() { @Override public int compare(String o1, String o2) { return Integer.compare(o1...
REST API 형태로 프로그램을 작성 중이라면 문서화에 Restdocs 혹은 Swagger2를 이용할 수 있다 개인적인 생각으로는 Swagger-ui가 훨씬 더 사용하기 쉽고 UI, UX가 좋지만 코드에 침투적이라는 이유 하나만으로도 싫다 다만 Restdocs를 사용해 본 경험이 있어 진행 중인 프로젝트에 학습 목적으로 Swagger2를 도입했다 오늘 만난 에러는 Springboot 2.6.x 이상의 버전을 사용한다면 마주칠 수 있는 문제다 난 부트 2.6.3, swagger는 3.0.0을 사용 중이다 plugins { id 'org.springframework.boot' version '2.6.3' } dependencies { implementation 'io.springfox:springfox-b..
오랜만에 읽고 시작하자 https://www.baeldung.com/java-marker-interfaces 마커 인터페이스는 메서드나 상수 없이 런타임에 정보를 제공하기 위해 사용한다 컴파일러나 JVM이 그 정보를 바탕으로 특정 작업을 수행한다 이렇게만 들으면 이걸 어따 써? 싶은 생각이 드는데 실제적인 예로 마커 애노테이션의 대표로는 JUnit에서 사용하는 @Test, 마커 인터페이스는 Serializable, Closeable, Cloneable 등이 있다 마커 인터페이스의 유용성은 특정 작업을 수행하는 메서드 시그니처를 제대로 선언했을 때만 의미가 있다 ObjectOutputStream의 writeObject 메서드는 Object 타입의 인자를 받을 수 있게 작성되었다 런타임에 터질 에러를 컴파일..
Item40의 핵심은 @Override를 붙일 수 있는 상황에는 반드시 붙이라는 것이다 책에서는 equals 메서드를 재정의하면서 발생할 수 있는 오묘한 실수를 예로 들었다 면접 단골 질문이기도 한 Override와 Overload의 차이점을 체화하고 있다면 저지르지 않을 실수지만 때로는 알고 있어도 틀릴 때가 있으니 제약이 필요하다, 그 제약이 바로 @Override다 재정의와 다중 정의를 간단하게 짚고 넘어가자 - Override 시그니처가 완전히 같되, 공변 반환을 지원하기 때문에 반환 타입은 달라질 수 있다 - Overload 메서드 반환 타입, 이름은 같되 매개변수를 다르게 받아 같은 이름으로 다른 타입, 개수의 인자를 받을 수 있다 현대적인 IDE를 쓰고 있다면 애노테이션은 색 자체가 달라 애..
Item39는 명명 패턴보다 애노테이션을 사용하라 말한다 좁게 보면 명명 패턴에 해당하는 내용이지만 넓게 보면 직접 지정하지 말고 책임을 갖고 있는 도구에게 위임하라는 것이다 JUnit4 이전까지는 테스트 코드를 작성할 때 테스트 돌릴 메서드의 이름을 testXX처럼 지어야 했다고 한다 test로 시작한다고 해서 특별히 힘든 것은 아니다 다만 test로 시작하지 않으면 테스트가 돌아가지 않는 것이 문제다 JUnit4는 이 문제를 @Test 애노테이션으로 해결한다 @Test는 테스트용임을 표시하는 marker annotation이고 이를 처리하는 annotation processor가 따로 있다 애노테이션 프로세서가 없다면 무용지물이니 IDE 세팅에서 활성화 시키는 것이 필요하다 gradle을 사용하고 있..
자바의 enum은 타입 안전한 상수를 선언하기 위한 야무진 도구다 Java1.5부터 등장했고 상수 집합을 나타내는 특별한 데이터 타입이다 다만 모든 것이 일장일단이 있듯 enum도 상속할 수 없다는 단점이 존재한다 우선 왜 enum은 상속할 수 없는지 그 이유부터 알아보자 가능한 값들의 닫힌 집합을 만들기 위해서다 닫힌 집합이란 컴파일 시점에 가능한 값들을 모두 알기 위해서고 이 방식이 개발자나 컴파일러 모두에게 이롭다고 한다 확장이 가능하다면 메서드의 인자로 A라는 enum을 받는 경우 리스코프 치환 원칙에 따라 A를 상속한 B라는 enum도 받을 수 있어야 한다 이런 경우 switch-case에서 사용할 수 없다 - switch(A) 라고 선언했는데 런타임에 B가 들어올 수 있다면 모든 case에 대..
Item37은 enum에서 ordinal 사용을 자제하고 컬렉션을 이용하라는 것의 확장판이다 책에서 상전이를 예로 들었는데 OrdinalTransition은 가장 간단하게 생각할 수 있는 코드로 작성됐다 ordinal을 사용해 2차원 배열로 만들었고 예제에서는 상전이가 일어나지 않았을 때 null을 넣어줬지만 살짝 변경해서 NONE을 추가하고 null을 대체했다 반면 Transition은 Item37의 조언을 따라 ordinal을 사용하지 않고 코드가 꽤나 복잡해졌지만 enum의 values()를 이용하기 때문에 타입 안전하며 Collectors.groupingBy()와 중첩 맵을 활용 해 상전이를 나타냈다 뭐든 간에 depth가 깊어질수록 이해하기 쉽지 않은데 TRANSITION_MAP은 난해하기 그지..
Item36에서는 비트 필드 대신 EnumSet을 사용하라는데 그전에 비트 필드는 무엇일까? 메모리를 직접 다루지 않는 자바에서는 비트 연산을 수행할 일이 많지 않다 특히나 고수준 API를 사용하는 웹 개발이라면 더욱 그렇다 '아 요런 것이 있구나'와 '이게 뭔데'는 하늘과 땅 차이니 세부 구현까지는 아니더라도 요런 것이 있구나 수준까지는 알아보자 비트 필드에 대한 상세한 설명이 담긴 좋은 글을 찾았다 깊게 알아보고 싶다면 꼭 읽어보자, 한 번에 빡 이해하기는 힘들것 같고 주기적으로 봐줘야겠다 Bit Fields - Java - Languages - Programming - Computers Bit Fields A bit field is a memory-saving tool that was develop..
진행 중인 프로젝트에서 OAuth2 검증 필터로 OncePerRequestFilter를 상속 받고 빈으로 등록해 사용 중이다 OncePerRequestFilter가 무엇인지는 밸덩을 참고하자 일반 필터와 다르게 이름 그대로 단일 요청에 대해 필터를 단 한번만 타게끔 해주는 녀석이다 OAuth2 검증 필터 흐름은 아래와 같다 1. 사용자의 쿠키에서 ID 토큰을 꺼내와 JWT 파싱 후, issuer를 확인해 구글 토큰인지 확인한다 2-1. 구글 토큰이 아닐 시 필터 체인에 태워 넘긴다 2-2. 구글 토큰일 시 파싱한 정보를 바탕으로 authentication을 만들어 SecurityContextHolder에 넣어준다 3. 만약 토큰의 만료 시간이 지났다면 갱신 url로 forward를 이용해 넘긴다 - 이 ..
책에 나온 enum 사용의 안 좋은 예시를 가져왔다 public enum Ensemble { SOLO, DUET, TRIO, QUARTET, QUINTET, SEXTET, SEPTET, OCTET, NONET, DECTET; public int numberOfMusicians() { return ordinal() + 1; } } 왜 안 좋은 것인가? 열거 타입 상수와 연결된 위치 값을 반환하는 ordinal() 메서드를 사용하기 때문이란다 코드는 멋들어진 API를 사용해 걸작을 만들어내는 것보다 모르는 사람이 봐도 이해할 수 있도록 만드는 게 어렵다 numberOfMusicians() 메서드를 이해하기 위해서는 위치값에 1을 더해 반환하는데 ordinal()이 위치 값을 반환한다는 사실도 알아야 하고, ..
프로그래밍 세계에는 매직 넘버를 피하라는 격언이 있다 위 격언을 지키기 위해 Config 같은 설정 클래스에서 초기화 과정에 값을 넣어주는 경우를 제외하고, 재사용 가능성이 있는 상수라면 흔히들 아래와 같이 작성하기도 한다 public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int ORANGE_FUJI = 0; public static final int ORANGE_PIPPIN = 0; 위처럼 표현할 시, 반복되는 prefix가 존재하고 더 심각한 문제는 타입 안전성이 보장되지 않는 것이다 위의 예시는 두 단어로 이어졌을 뿐이기에 가독성도 나쁘지 않고 그럭저럭 쓸 만 하지만 ..
Item33에서는 type safe heterogeneous container pattern에 대해 알아보는데 Parameterized Type Key를 넣는 게 과연 무슨 의미인가 궁금해졌다 너무 복잡한데 비해 실제로 만들어 본 상황이 거의 없으니 이걸 왜 쓰지? 라는 생각이 들었다 읽다보니 동적 형 변환에도 타입 안전성을 보장하기 위함이고 jackson과 같은 라이브러리에서 요긴하게 쓰고 있는 것 같다 기본적인 것들은 모두 이해했다고 가정하고 책의 예시에서 등장한 Favorites 클래스의 두 번째 제약에 대해 더 알아보려 한다 List과 같은 제네릭 타입은 실체화 불가 타입이다 즉 List.class 와 같이 쓸 수 없고 타입 안전 이종 컨테이너를 만들더라도 제네릭 타입은 사용 불가하다는 얘기다 이..
개인 프로젝트에서 템플릿 엔진으로 thymeleaf를 선택해 사용 중이다 spring-security와 엮어서 사용할 필요가 있었고 thymeleaf-extras-springsecurity 라이브러리를 추가하면 간단하게 사용 가능하다 다만 최신 릴리즈인 3.0.4.RELEASE는 2018년 10월에 나왔기에 나온지 좀 됐고 그 때문에 보안 취약점들이 몇개 걸린 상태다 2022년 1월에 따끈따끈한 보안 패치 버전이 나왔으나 정식 버전이 아닌 Milestone 버전이다 모험가 정신이 투철한 나는 참을 수 없이 M1 버전을 라이브러리에 넣고 돌렸더니 굉장히 장황한 NoSuchMethodError가 뜨는 것이 아닌가 내 눈을 믿을 수 없어 서버 재시동 후 몇번 더 시도했지만 같은 에러를 뿜었다 마음을 가다듬고 ..
varargs란 메서드 인수의 개수를 클라이언트 측에서 결정할 수 있다는 점에서 개꿀이다 인수를 여러 개 넘기면 내부적으로는 배열을 만들어 담아두고 사용한다 바로 이 부분에서 문제가 되는데 가변 인수를 제네릭 타입으로 넘긴다면 실체화되지 않는 타입으로 배열을 만들기 때문에 타입 안전성이 보장되지 않아 possible heap pollution 경고가 뜬다 매개변수 타입을 변환하지 않고 사용한다면 문제없을 수 있으나 만약 얘를 메서드 내부에서 형 변환하거나 다른 타입을 참조하는 경우엔 ClassCastException이 터지게 된다 힙 오염의 의미는 아래 블로그 글을 참고해보자 아래의 예시는 로 선언해놓고 Double 타입의 요소를 갖고 있어 힙 오염이 발생했다 이 전에 제네릭과 배열을 언급했을 때는 아예..
Generics를 사용하면서 재사용성을 높이기 위한 방법으로 이름조차 버거운 한정적 와일드카드 타입이 있다 한정적 와일드카드 타입을 이해하기에 앞서 Generics의 불공변을 이해하기 위해 List과 List을 살펴보자, 둘은 어떠한 관계도 없는 다른 타입이다 List에는 기본형을 제외한 모든 객체 타입을 넣을 수 있는데 List에는 오직 String 타입만 넣을 수 있다 책에서는 상하위 관계에서 지켜져야 할 리스코프 치환 원칙을 지키지 않기 때문에 둘은 다른 타입이라 말한다 따라서 논리적으로도 맞고 타입 안전한 개발이 가능하지만 아쉬운 점이 있다 Generics은 정말 좋지만 타입 매개변수에 직접 타입을 지정해버리면 그 타입에 한정되어 굳어버린다 사용하려는 매개변수 타입 개수 만큼의 메서드를 만들어야 ..
객체지향의 핵심은 캡상추다로 요약된다고 말한 적이 있다 캡슐화로 내부 구현을 감추어 외부에서 내부 구현에 얽매이지 않게 하고 추상화를 통해 OCP를 준수해 변경에는 닫혀있고 확장에는 열린 포인트를 만들어준다 sub-class가 아닌 sub-typing을 통해 타입 계층을 만들어 전략 패턴 사용이 가능하게 하여 다형성을 이루어낸다 결국 객체지향의 최종 목표는 재사용성 향상과 유지보수성 향상을 위함이다 객체지향의 목표를 이루려면 클래스 설계, 컴포넌트 설계뿐만 아니라 메서드 단위에서의 재사용성도 중요하다 쉽게 말해 범용적인 메서드를 만들어야 여러 곳에서 활용이 가능하다는 말이다 정렬 메서드나 컬렉션 두 개를 합쳐주는 메서드를 사용할 때 하나의 메서드로 여러 곳에서 활용할 수 있다면 편리할 것이다 이런 상황에..
무료인 이클립스를 두고 인텔리제이를 써야 할 이유가 있을까? 1. 이쁘다 2. 훨씬 이쁘다 3. 기분 탓 일지 모르지만 더 가벼운 느낌이다 4. 인텔리제이에는 개꿀 플러그인들이 많다 구글에 인텔리제이 플러그인을 검색할 때 rainbow bracket, code glance, git toolbox 등등 야무진 녀석들이 많이 나오는데 그 외에도 아주 신묘한 녀석이 있어 소개하려 한다 이 녀석은 code metrics라는 놈으로 코드의 복잡성을 보여준다 이와 비슷한 기능을 하는 걸로 sonarlint가 있지만 그놈보다 훨씬 직관적이고 단순히 박스를 클릭하는 것만으로 어디에서 복잡도가 올라갔는지도 보여준다 설치하면 왼쪽과 같은 형태로 클래스, 메서드에 복잡도가 나타나며 Complexity를 클릭하면 복잡도가 올..
개발자라면 응당 '이왕이면 다홍치마' 대신 '이왕이면 제네릭이다'라고 말해야 한다 왜 제네릭인가? 런타임에 터질 ClassCastException을 컴파일 시점에 에러로 띄워주기 때문이다 일반 클래스를 type-safe 하도록 제네릭 클래스를 만들려면 타입 매개변수를 주면 된다, Stack -> Stack 단 이 클래스 내에서 배열을 사용한다면 컴파일 에러나 비검사 형 변환 경고가 뜨는데 이를 막기 위한 방법으로 두 가지가 있다 1. 주어진 타입으로 배열을 만드려고 할 때 Object[]로 만들고 그 후에 타입을 사용해 명시적인 형 변환을 때려준다 단 컴파일러는 런타임에 해당 라인이 안전함을 보장할 수 없기 때문에 개발자가 안전함을 확실하게 알 때만 사용해야 한다 이를 무시하면 런타임에 터질 에러를 막아..