자바에는 언어 차원에서 제공하는 수많은 예외들이 있다 언어 자체에서 제공되므로 잘 작성되어 있고 네이밍도 적절하며 문서화도 잘 되어있다 그런데도 불구하고 구글링을 하다 보면 커스텀 예외를 사용하는 경우들이 적지 않게 있다 어설픈 경우 다음과 같은 형태를 가질 것이고 이런 경우에는 커스텀한 이름을 붙인 것 외에 아무런 장점이 없다 토이 프로젝트를 진행하던 당시에는 이런 예외를 사용했으나 이제 와서 생각해 보면 어설프다고 밖에 할 수 없다 public class TokenException extends AuthenticationException { public TokenException(String message) { super(message); } public TokenException(String msg..
Item71에서는 필요 없는 Checked Exception 사용을 피하라 말한다 앞선 Item70에서 신나게 단점에 대해 얘기했으니 Checked Exception의 장점을 알아보고자 한다 다음 질문을 참고해 보자 In Java, what are checked exceptions good for? Java's checked exceptions have gotten some bad press over the years. A telling sign is that it's literally the only language in the world that has them (not even other JVM languages like Groovy and... softwareengineering.stackexch..
Item70에서는 복구할 수 있는 예외는 checked-exception, 프로그래밍 오류는 unchecked-exception을 사용하라 말한다 옛날 글이지만 지금 봐도 좋은 checked-exception 관련된 글을 찾았다 C# Lead Architect가 checked-exception 개념을 왜 C#에서 빼버렸는지에 대한 인터뷰 글이다 artima - The Trouble with Checked Exceptions Artima provides consulting and training services to help you make the most of Scala, reactive and functional programming, enterprise systems, big data, and tes..
Item69에서 예외는 진짜 예외 상황에서만 사용하라 말한다. 너무나 당연한 얘기를 왜 한 장에 할당해 설명했을까? 바로 다음과 같은 해괴한 방식으로 작성하는 녀석들이 있기 때문이다 try { int i = 0 ; while (true) { System.out.println(array[i++]); } } catch (ArrayIndexOutOfBoundsException e) { // doSomething... } 위 코드의 의도는 array로 선언한 배열의 인덱스를 하나씩 늘려가며 출력하는 것인데 배열의 마지막 요소까지 출력하기 위해 범위를 넘어갈 때 (즉 ArrayIndexOutOfBoundsException이 발생할 때) catch 블록에서 잡아서 별도의 처리를 하거나 하지 않거나 하는 방식으로 작..
Item68에서는 일반적으로 통용되는 명명 규칙을 따르라 말한다 자바 언어 자체의 네이밍 규칙은 첫 글자로 $, _, 문자만 올 수 있으며 그 이후로는 어떠한 Unicode 문자든지 올 수 있다는 단순한 규칙으로 이루어져 있다 다만 언어의 규칙(Rule)과 관습(Convention)은 다르며 관습이 조금 더 제한적인 형태로 나타난다 규칙과 관습에 대해 더 자세히 알아보고 싶다면 아래 두 글을 참고하자 1. https://www.theserverside.com/feature/Java-naming-conventions-explained 2. https://www.oracle.com/java/technologies/javase/codeconventions-namingconventions.html 네이밍의 대표..
Item67에서는 최적화를 신중히 하라 말한다 덧붙여 최적화 격언 세 개를 소개하는데 모두 섣부른 최적화는 안 하는 것보다 못하다는 의미를 전달한다 섣부른 최적화라 부를 수 있는 것의 사전 조건은 잘 짜둔 구조를 헤쳐가면서 최적화를 하는 것을 의미한다 최적화라는 것은 성능 뿐만 아니라 리소스도 포함하므로 더 방대한 영역을 다룬다 최적화에 발이라도 담가보려면 자바 언어 자체의 동작 원리, JDK 버전이 올라가면서 달라져야 하는 코드 작성 방식, JVM의 메모리 구조 + 라이브러리 + GC 등등 선제 지식이 너무 많이 필요하다 자바를 사용해서 개발 하는 것조차 쉬운 일이 아니건만 최적화를 하려면 더 깊고 넓은 지식에다가 로우 레벨까지 빠삭해야 하니 웬만한 대기업이 아니고서야 최적화에 신경 쓸 여력도 별로 없..
Item66에서 네이티브 메서드는 신중히 사용하라 말한다 네이티브 메서드란 무엇이고 언제 사용하는가? 오라클의 문서를 보자 자바만으로는 프로그램을 작성할 수 없는 경우에 사용한다고 하는데 JNI가 필요한 상황은 다음과 같다 1. 언어 자체가 특정 기능을 지원하지 않는 경우 2. 다른 언어로 된 라이브러리를 사용하고 싶은 경우 3. C, C++에 비해 구린 성능 내 경험에서만 비추어보자면 일반적인 개발자가 JNI를 사용할 일은 거의 없을 것 같다 platform-dependent한 레벨까지 내려갈 일이 없다 메서드 선언 부에 native 키워드를 가지고 있는 놈들이 네이티브 메서드인데 많은 라이브러리를 뒤져봐도 흔히 보이지 않는다 또한 책에서 나온 GNU 다중 정밀 연산 라이브러리 같이 정말 특별한 라이브..
Item65에서는 리플렉션보다는 인터페이스를 사용하라 말한다 이유는 간단하다 메서드를 직접 호출하면 컴파일된 코드를 실행하는데 반해 리플렉션은 bytecode에서 metadata를 찾아야 하기 때문이다 책에서는 리플렉션을 사용할 때의 단점을 나열하는데 다음과 같다 1. 컴파일 타입 검사 불가 2. 장황한 코드 3. 성능 저하 단점들을 보니 리플렉션을 쓰지 말아야 할 이유만 생기는 것 같다 컴파일 타입 검사 불가는 정적 타입 언어를 사용하는 이유를 무색하게 하고 장황한 코드는 안 그래도 지저분한 자바를 더 지저분하게 만들며 C, C++에 비해 구린 성능의 자바를 더욱 구리게 만든다 위 사진에 달린 링크를 따라가 보면 현실에서 리플렉션이 유용한 단 하나의 이유는 프레임워크에서의 사용이라 한다 즉 자신이 만들..
Item64에서 객체는 인터페이스를 사용해 참조하라 말한다 프로그래밍 입문 단계에서도 흔히 접할 수 있는 말인데 그때 당시에는 왜 명확한 타입을 두고 상위 타입으로 뭉뚱그려 받을까라는 생각이 있었다 이제는 바로 그 점 때문에 사용한다는 걸 알지만 처음 들어서는 쉽게 이해할 수 없었다 인터페이스란 용어가 낯설어서 그러지 않았나 생각이 든다 좋은 책들을 보면 명확한 설명이 되어있긴 한데 확 와닿지는 않는다 이해하고 나면 그 책들만큼 정확하고 이해하기 쉬운 설명이 없는데 이해하기 까지가 어려운 게 문제다 이럴 땐 명확하지 않고, 올바르지 않은 의미더라도 자기만의 언어로 풀어서 생각해보는게 좋다 내가 쉽게 이해해보려 생각한 인터페이스란 최소의 기능을 담은 껍데기다 구현체의 표면에 인터페이스라는 껍데기를 덧씌우면..
Item63에서는 문자열 연결은 느리니 주의하라 말한다 String의 작동 방식을 이해하기란 쉽지 않고 제대로 이해하려면 로우 레벨까지 파봐야 하니 이 글에서는 깊게 다루지는 않고 수박 겉핥기 정도로만 다뤄보려 한다 모든 내용은 이 글을 참고한다, 본 글은 간략하게 정리하기 위함이고 제대로 알아보려면 첨부한 링크를 보는 걸 추천한다 문자열 연산을 알아보기 전에 선행해서 생각해볼 점으로 가독성과 성능이 있다 기본 루프를 사용할 것이냐 스트림을 사용할 것이냐 처럼 가독성과 성능 둘 사이의 트레이드오프를 이해하고 상황에 맞는 방식을 사용해야 한다 자바에서 문자열 연결 시에 사용할 수 있는 방법은 + 연산자 외에도 꽤 많다 연결해야 하는 인자가 적다면 아무래도 + 연산자가 제일 가독성이 좋을 테고 StringB..
Item62에서는 적절한 타입이 있다면 문자열 사용을 피하라 말한다 책에서는 예제로 ThreadLocal을 들었고, 제네릭을 버무려 type-safe한 모습으로 만들어냈다 이 보다 더 와닿을 예제로 웹개발 시에 모든 값을 타입과 상관없이 String 타입으로 받아버리는 것이 있다 자바 스프링을 사용한다면 ConversionService에 의해 대부분의 타입이 변환이 되는데도 불구하고 String으로 받아버리고 필요하다면 개발자가 직접 형변환을 때려주는 코드를 본 적이 있다 상당한 레거시 프로젝트였는데 자바17까지 깔짝이며 최첨단으로 공부하던 신입 개발자 눈에는 당최 이해할 수가 없는 형태였다 ConversionService 문서를 보면 3.0부터 지원이 됐다고 하는데 그럼에도 안 쓴 이유를 추측해보자면 ..
Item61에서는 wrapper 타입보다 primtivie 타입을 사용하라 말한다 책에 나온 아래 예시보다 눈에 확 들어오게 간단한 예시로 박싱 된 기본 타입을 쓰지 말아야 할 이유를 살펴보자 Comparator naturalOrder = (i, j) -> (i, j) ? -1 : (i == j ? 0 : 1); 자바에서 범용성을 높이기 위해 Generic type으로 다루려면 반드시 reference type이어야 한다 이 것이 wrapper 타입의 존재 이유다 그렇다면 wrapper만 두고 모든 것을 객체로 다뤄버리면 되지 않을까 싶지만 성능 상의 이유로 그러기는 또 쉽지 않단다 아래는 int의 wrapper type인 Integer로 값을 비교하는 경우를 나타낸 예시다 public static vo..
Item60에서는 정확한 계산을 할 때에는 float과 double을 피하라 말한다 대표적인 예로 금융과 관련된 계산을 할 때는 아래 세 경우를 고려해야 한다 1. 최대 21억 근사치까지 사용한다면 메모리 리소스까지 고려하여 int 사용 2. 약 1800경까지의 값이 필요하다면 long 사용 3. 이 마저도 초과한다면 성능을 깎아먹더라도 정확성을 위해 BigDecimal 사용 처음 단정밀도, 배정밀도 실수에 대해 봤을 때 단순하게 float은 정밀도가 6~7이고 double은 약 15~17 정도 구만 하고 넘어갔는데 최근에 컴퓨터 구조를 공부하면서 호기심이 생겨 좀 더 찾아봤다 1. 단정밀도 https://bahasa.wiki/ko/Single-precision_floating-point_format 2..
Item59에서는 라이브러리를 익히고 사용하라 말한다 예시로 Java의 Random 클래스의 random 메서드를 들었는데 내부 구현의 허점으로 이상적으로 동작하지 않는다고 한다 약 2/3 정도가 중간 값보다 낮은 쪽으로 쏠린다고 한다 다행히도 Random.nextInt() 메서드는 이를 보완해서 나왔고 일반적인 상황에서는 충분히 사용 가능하다 더 나아가 자바7 이상부터는 ThreadLocalRandom을 사용하라 한다 ThreadLocalRandom은 ThreadLocal과 Random을 짬뽕해 만들었다고 하고 Random보다 더 나은 성능을 보인다고 한다 또한 Fork-Join Pool을 사용해 병렬 처리를 할 때는 SplittableRandom을 사용하라 한다 그럼 ThreadLocalRandom ..
item58에서는 fori 보다 iter를 사용하라 말한다 fori는 무엇인가, fori를 치면 생성되는 좌측의 코드 블록을 의미한다, 전통적인 for문 / for-loop라고 한다 iter는 무엇인가? iter를 치면 생성되는 우측의 코드 블록을 의미한다, 향상된 for문 / foreach-loop라고 한다 향상된 for문이라 부르는 이유는 성능 측면이 아닌 가독성 측면에서의 향상을 의미한다 특별한 이유가 있거나 학습의 목적이 아니라면 iterator()를 얻어서 iterator.next()로 순회하는 코드를 작성할 일은 거의 없으니 패스하자 for-loop과 foreach-loop는 반복 형태의 구조를 다룬다는 점에서 동일하다 가장 큰 차이는 for-loop은 외부에서 인덱스를 가지고 조작한다는 점에..
Item57에서는 지역변수의 범위를 최소화하라 말한다 왜일까? 변수의 범위를 줄이면 가독성과 유지보수성이 좋아지기 때문이란다 이 조언을 정면으로 들이박는 형태가 있는데 메서드나 코드 블록에서 변수를 한 무더기 선언해놓고 그 아래에서 선언한 변수를 사용하는 방식을 옛날 옛적 C를 사용할 때 그렇게 했었다고 한다 다행히도 아직까지는 실무에서 변수촌을 만들어놓고 아무데서나 막 가져다 쓰는 코드는 보지 못 했다 이펙티브 자바의 예는 약간 극단적이라 갸우뚱하긴 하다, iterator()로 직접 돌리는 코드도 본 적이 없고 자바8 이후로 성능이 정말 중요한 경우가 아니고서야 enhanced-for도 stream으로 대체 가능하니 더욱 그렇다 자바8의 stream, Function 등을 배우고 나면 기존의 코드를 싹..
Item56에서는 공개된 API 요소에는 항상 문서화 주석을 작성하라 말한다 사실 언어나 프레임워크, 공개 라이브러리 작성자가 아니라면 지키지 않아도 될 조언이긴 하다 다만 구멍가게를 벗어나 네이버와 같이 하나의 회사지만 여러 계열사로 나뉘고 그 안에서 공통적으로 사용할 모듈을 개발한다면 의무는 아니어도 javadoc 형태로 작성해두면 사용하는 이들에게 좋다 나는 수습 과제로 만든 작은 사이드 프로젝트에 주석을 적어놓기도 했다 클린 코드에 미친 사람이라면 주석 자체가 쓰레기 같겠지만 분명한 건 코드를 짜는 순간부터 레거시가 되고 자신이 평생 유지보수할 수는 없다는 것이다 그렇다면 다음 사람이 이를 맡아서 유지보수를 해야 하는데 도메인 지식이라고도 하고, 배경지식이라고도 하는 특정 비지니스 로직을 모르고 ..
Item55에서는 옵셔널 반환을 신중히 하라 말한다 참고 글에서는 옵셔널이 보기만큼 쉬운 녀석이 아니라고 하며 무언가를 사용할 때 왜 만들어졌는지, 어떤 방식으로 테스트되었는지를 반드시 확인하라 한다 위 글에는 Optional의 여러 API들을 사용하는 방법과 best-practice를 안내하고 있으니 시간이 있다면 읽어보자 Optional에 대해 자바 설계자 브라이언 고츠는 아래와 같이 정의한다 많은 이가 사용하는 라이브러리 메서드는 값이 없는 경우 null을 반환하면 에러 발생 가능성이 높아지니 대안으로 값이 없다는 것을 제한된 방식으로 나타내기 위해 만들어졌다고 한다 Optional이라는 컨테이너를 만들고 그 안에 값이 있든 없든 반환하고 클라이언트 쪽에서 값이 있는 경우와 없는 경우를 고려해 사용..
Item54에서는 null이 아닌 빈 컬렉션이나 배열을 반환하라 말한다 생각해보면 어떤 객체든 값이 없는 경우 null 반환 때리면 간단한데 왜 하지 말라는 걸까? null 만든 사람조차 10억 달러짜리 실수라 말했기 때문이다 어떤 메서드든 null을 반환하면 클라이언트 측에서 null check가 필요하다 만약 something 객체가 인스턴스 변수로 참조 타입을 가지고 있고 그 참조를 사용하려 한다면 null check 한방 더 들어간다 if (something != null) // 로직 수행 if (something == null) throw new 어쩌구Exception(); null check로 콜백 지옥과 같은 형태로 뎁스가 쭉쭉 늘어나 진짜 중요한 비즈니스 로직을 가리게 될 수 있고 실수로 ..
Item53에서는 가변 인수는 신중히 사용하라 말한다 가변 인수를 사용할 때 주의점은 아래 글을 참고하자 [Item32] varargs는 신중히 varargs란 메서드 인수의 개수를 클라이언트 측에서 결정할 수 있다는 점에서 개꿀이다 인수를 여러 개 넘기면 내부적으로는 배열을 만들어 담아두고 사용한다 바로 이 부분에서 문제가 되는데 ryumodrn.tistory.com 가변 인수를 사용하면 매개변수의 개수가 정해지지 않은 상태로 클라이언트에게 매개변수를 몇 개 넘길지에 대한 책임을 넘겨 클라이언트가 필요한 만큼 넘길 수 있도록 한다는 점에서 유연한 API 설계가 가능하다 다만 varargs는 위험하다, 가변인수를 받는 메서드는 런타임에 새로운 배열이 생성되어 인수를 처리한다 어차피 사용하고 GC로 처리되..