리플렉션 기능 리플렉션 기능을 이용하면 프로그램에서 임의의 클래스에 접근할 수 있다. Class 객체가 주어지면 그 클래스의 생성자, 메서드, 필드 인스턴스를 가져올 수 있고, 해당 인스턴스들로부터 클래스의 멤버 이름, 필드 타입, 메서드 시그니처 등을 가져올 수 있다. 나아가 각 인스턴스를 이용해 연결된 실제 생성자, 메서드, 필드를 조작할 수 있다. 이는 클래스의 인스턴스를 생성하거나, 메서드를 호출하고, 필드에 접근할 수 있음을 나타낸다. 리플렉션을 이용하면 컴파일 당시에 존재하지 않던 클래스도 이용할 수 있다. 리플렉션의 단점 1. 컴파일 타임 타입 검사가 주는 이점을 누릴 수 없다. 타입 검사나 예외 검사의 이점을 누릴 수 없다. 리플렉션 기능을 이용해 존재하지 않거나 접근할 수 없는 메서드를 ..
적합한 인터페이스만 있다면 매개변수뿐 아니라 반환 값, 변수, 필드를 전부 인터페이스 타입으로 선언하자. 실제 클래스를 사용해야 하는 상황은 생성할 때뿐이다. 인터페이스를 타입으로 선언하는 습관은 프로그램을 훨씬 유연하게 만들어 준다. 인터페이스를 타입으로 선언하자. // Good Set sonSet = new LinkedHashSet(); // Bad LinkedHashSet sonSet = new LinkedHashSet(); 위 예시에서 구현 클래스를 교체하고자 한다면 아래와 같이 변경할 수 있다. Set sonSet = new HashSet(); 이처럼 인터페이스를 타입으로 사용한 선언은 간단하게 새로운 구현 클래스로 교체할 수 있다. 주의사항 만약 인터페이스의 일반 규약 이외의 특별한 기능에 의..
문자열 연결 연산자(+)는 여러 문자열을 하나로 합쳐주는 편리한 수단이지만, 성능 저하가 상당하다. 문자열 연결 연산자로 문자열 n개를 잇는 작업은 n^2에 비례한다. 예시 청구서의 item을 전부 하나의 문자열로 연결하는 메서드가 있다. // 문자열 연결을 잘못 사용한 예 - 느리다! public String statement() { String result = ""; for (int i = 0; i < numItems(); i++) { result += lineForItem(i); } return result; } 각 item의 원소 개수만큼 문자열을 잇는다. 품목의 개수가 많아지면 많아질수록 성능 저하가 심해진다. 성능을 포기하고 싶지 않다면 String 대신 StringBuilder를 사용하자! ..
문자열은 텍스트를 표현하도록 설계되었다. 하지만 워낙 흔하고 자바가 잘 지원해주기 때문에 설계 의도와 다르게 사용될 때가 많다. 문자열을 쓰지 않아야 할 사례들 1. 문자열로 다른 값 타입을 대신하는 경우 받는 데이터가 수치를 나타낸다면 int, float, BigInteger 등을, Y / N을 나타낸다면 boolean을 사용하는 것이 적절하다. 즉, 기본 타입이든 참조 타입이든 알맞는 값 타입이 있다면 그것을 사용하고, 없다면 새로 만들어서 사용하자. 2. 문자열로 열거 타입을 대신하는 경우 아이템 34에서도 설명했듯, 상수를 열거할 때는 문자열보다 열거 타입을 사용하자. 3. 문자열로 혼합 타입을 표현하는 경우 혼합된 데이터를 하나의 문자열로 표현하는 것은 좋지 않은 생각이다. // 혼합 타입을 문..
자바의 데이터 타입은 크게 int, long, boolean과 같은 기본 타입과 String, List 같은 레퍼런스 타입으로 나눌 수 있다. 각각의 기본 타입에는 대응하는 레퍼런스 타입이 하나씩 존재하고, 이를 박싱 된 기본 타입(Integer, Long, Boolean 등)이라 한다. 오토 박싱과 오토 언박싱 덕분에 두 타입을 크게 구분하지 않고 사용할 수 있지만, 어떤 타입을 선택하고 사용하는지는 상당히 중요하다. 이 둘의 차이점을 명확히 파악하고 사용해야 발생하는 문제들을 최소화할 수 있다. 기본 타입과 박싱된 기본 타입의 차이점 1. 기본 타입은 값만 가지고 있으나, 박싱 된 기본 타입은 식별성도 가지고 있다. 박싱 된 기본 타입의 두 인스턴스는 값이 같아도 서로 다른 인스턴스로 인식될 수 있다..
float와 double 타입은 공학 계산용으로 설계되었다. 넓은 범위의 수를 빠르게, 정밀한 근사치로 계산하도록 설계되었다. 따라서 정확한 결과가 필요할 때는 사용하면 안 된다. 특히, 금융(돈) 관련 계산에는 float와 double 타입 사용을 피하자. 금융 계산에 부동소수 타입을 사용한 경우 public static void main(String[] args) { double funds = 1.00; int itemBought = 0; for(double price = 0.10; funds >= price; price += 0.10) { funds -= price; itemsBought++; } System.out.println(itemBought + "개 구입"); System.out.print..
Java 생태계에는 java.io, java.lang, java.util 등 자바 표준 라이브러리나 고품질의 서드파티 라이브러리 등 수많은 라이브러리들이 존재한다. 아주 특별한 나만의 기능이 아니라면 이미 누군가가 라이브러리 형태로 구현해놓았을 가능성이 크다. 이러한 라이브러리들은 일반적으로 코드의 품질이 좋고 지속해서 개선된다. 구현해야 할 기능이 라이브러리로 존재한다면 그것을 사용하자. 있는지 잘 모르겠다면 찾아보자. 우리는 그 라이브러리가 어떤 영역의 기능을 제공하는지 살펴보고, 익히고, 사용하면 된다. 표준 라이브러리를 잘 활용하지 못한 예제 아주 흔히 마주치는 문제로, 다음과 같은 메서드를 만들곤 한다. // 문제가 많은 코드! static Random rnd = new Random(); sta..
가능한 모든 곳에서 전통적인 for 문보다는 for-each 문을 사용하는 것이 좋다. 전통적인 for 문과 비교했을 때 for-each문은 명확하고, 유연할 뿐 아니라 버그를 예방해주는 효과가 있다. 또 성능 저하도 없다. // 전통적인 for 문 - 컬렉션 순회 for(Iterator i = c.iterator(); i.hasNext();) { Element e = i.next(); } // 전통적인 for 문 - 배열 순회 for (int i = 0; i < a.length; i++) { int z = a[i]; // a[i]로 무언가를 한다. } 전통적인 for 문은 while문 보다는 낫지만 가장 좋은 방법은 아니다. 우리에게 필요한 건 원소뿐인데 for 문 안의 반복자와 인덱스가 코드를 지저분..
클래스와 멤버의 접근 권한을 최소화하면 얻을 수 있는 이점이 많듯, 지역변수의 유효 범위를 최소로 줄이면 코드 가동성과 유지보수성을 높일 수 있고 오류 가능성을 낮출 수 있다. 지역변수 범위 최소화하기 1. 가장 처음 쓰일 때 선언하기 가장 강력한 기법은 역시 '가장 처음 쓰일 때 선언하기'이다. 변수를 미리 선언해두면 코드가 어수선해지고 가독성이 떨어진다. 또한, 의도한 범위 외에서 그 변수를 사용하면 오류 가능성이 높아진다. 2. 선언과 동시에 초기화 초기화에 필요한 정보가 충분하지 않다면 충분해질 때까지 선언을 미뤄야 한다. 단, try-catch 구문에서의 이 규칙은 예외이다. 3. 메서드를 작게 유지하고 한 가지 기능에 집중하기 하나의 메서드가 여러가지 역할을 가지는 경우 그중 한 기능과만 관련..