Dev/JAVA 63

[Effective JAVA] 추상클래스보다는 인터페이스를 우선하라 (아이템20)

추상클래스는 단일 상속만 지원한다. 인터페이스는 선언한 메서드를 모두 정의하고 일반 규약을 잘 지킨 클래스라면 다중 상속이 가능하다. A클래스가 인터페이스를 구현하는 것은 쉽지만 추상클래스를 상속하는 것은 어렵다. 기존클래스가 무엇인가를 상속하고 있다면 단일 상속만 지원하는 JAVA 특성상 새로운 추상클래스를 상속하여 구현하기 어렵기 때문이다. 믹스인(믹스인 인터페이스) 구조는 주된 기능 + 선택 기능을 혼합한 형태이다. 인터페이스는 계층구조없이 다중상속이 가능하여 믹스인에 적합하다. 노래(인터페이스) + 작곡(인터페이스) -> 싱어송라이터 아직 이해는 잘 안되지만 여기까지 자세하게 할 필요는 없을 거같아 ( 면접대비로 )

Dev/JAVA 2024.03.21

[Effective JAVA] 상속보다는 컴포지션을 사용하라. ( 아이템 18 )

외부 패키지에 있는 구체 클래스를 상속하는 일은 위험하다. 통제권 밖에 있는 클래스는 언제 어떻게 변경될지 모르기 때문이다. 자식클래스는 부모클래스의 영향을 받을 수 밖에 없다. 메소드 호출과 달리 상속은 캡슐화를 깨뜨린다. 상위 클래스의 구현에 따라 하위 클래스가 위험해질 수 있다. 그러므로 상속은 반드시 is-a 관계일 때만, 진짜 하위타입인 경우에만 사용해야 한다. 특정한 기능을 하는 Set 클래스(새로운 클래스)가 직접 HashSet을 상속하기 보다는 HashSet을 새로운 클래스의 멤버변수로 구성하는 것이 더 좋은 접근 방식이다. 새로운 클래스는 HashSet의 모든 정보가 필요없는데, 상속을 하게 되면 불필요하게 모든 내부 구현을 새로운 클래스에 노출하게 된다. 그러므로 특정한 기능만 필요한 ..

Dev/JAVA 2024.03.21

[Effective JAVA] 변경가능성을 최소화 하라. ( 아이템 17 )

불변 인스턴스에 간직된 정보는 고정되어 객체가 파괴되는 순간까지 절대 달라지지 않는다. 불변을 만드는 다섯 가지 규칙 1) 객체의 상태를 변경하는 메소드를 제공하지 않는다. 2) 클래스를 확장할 수 없도록 한다. ( 클래스를 final로 선언 , 생성자 private 선언 후 정적 팩토리 메소드 제공 ) 3) 모든 필드를 final로 선언한다. ( 런타임 중 변경 X ) 4) 모든 필드를 private로 선언한다. ( 외부에서 접근 불가능 ) 5) 클래스가 가변객체를 참조한다면 외부 클라이언트가 해당 가변 객체의 참조를 얻을 수 없도록 해야한다. 불변객체는 생성된 시점의 상태를 파괴 될 때까지 유지한다. 불변객체는 스레드에 안전하여 동기화가 필요없다. 여러 스레드가 동시에 사용해도 훼손되지 않는다. 1)..

Dev/JAVA 2024.03.21

[Effective JAVA] 클래스와 멤버의 접근권한을 최소화하라. ( 아이템15 )

잘 설계된 컴포넌트는 내부 데이터와 구현정보를 외부 컴포넌트로 부터 잘 숨기고 오로지 API를 통해서만 통신해야 한다. 이를 캡슐화(정보은닉)이라 부른다. 캡슐화가 잘 되어 있으면 여러 컴포넌트를 병렬로 개발할 수 있고 컴포넌트 교체에 부담이 가지 않아 성능 향상에 일조하고 작은 컴포넌트부터 하나씩 개발하여 시스템 제작난이도를 낮추어 준다. 접근제어자를 잘 사용하는 것이 정보 은닉의 핵심이다. 톱레벨 클레스 ( 가장 바깥 클래스 ) 와 인터페이스 private : 톱레벨 클래스에서만 접근 가능 ( 중첩된 클래스 ) public : 외부 패키지에서 접근가능, 해당 클래스를 상속하는 외부 패키지 ( 하위호환 )을 관리해야 함 package-private : 패키지 내부의 모든 클래스가 접근 가능, 내부 구현..

Dev/JAVA 2024.03.20

[Effective JAVA] 불필요한 객체 생성을 피하라 ( 아이템6 )

똑같은 기능의 객체를 매번 새롭게 생성하는 것보다 불변 객체를 만들어 사용하는 것이 좋다. new String으로 매번 문자열 객체를 사용하는 것보다 리터럴 문자열을 사용하는 것이 좋다. JAVA는 문자열 상수 풀을 Heap 메모리에서 관리하는데, 리터럴 문자열 객체를 불변객체로 관리한다. 불필요한 객체생성을 막으려면 생성자는 private로 막고 정적 팩터리 메서드로 객체를 반환하는 방식이 좋다. 생성자는 new 연산자로 호출할 때마다 생성되지만 정적팩토리 메서드는 전혀 그렇지 않다. 메서드가 호출 될 때마다 객체를 생성하지 말고 정적메서드로 불변객체 하나만 사용하면 된다. 래퍼클래스에 의한 오토박싱은 필요한 기능이지만 잘못사용하면 무분별한 객체생성으로 이어질 수 있다. 그러나 요즘 JVM 성능이 좋아..

Dev/JAVA 2024.03.20

[Effective JAVA] 자원을 직접 명시하지 말고 의존객체 주입을 사용하라. ( 아이템5 )

싱글톤 패턴은 final로 선언된 멤버변수에 미리 인스턴스를 생성해놓는다. 그러나 이 방식은 유연하지 못하다. 스펠링을 체크하는 클래스가 있다. 스펠링을 체크 클래스는 사전에 의존한다. 싱글톤 방식은 멤버변수에 인스턴스를 미리 생성해 놓으므로 사전A, 사전B와 같이 구체적인 클래스에 결합하게 된다. 그렇다고 final을 지우고 setter 함수를 만들어사전A, 사전B를 번갈아 설정 가능하게 한다면 멀티스레드 환경에서 동시성 오류가 발생할 수 있다. 그러므로 final을 유지하면서 환경에 따라 적절한 인스턴스를 유연하게 의존할 수 있는 방법을 선택해야 한다. 그것이 바로, 의존객체 주입이다. 생성자 주입 방식을 사용하면 객체가 생성되는 시점에 멤버변수가 초기화 되므로 final을 유지할 수 있다.

Dev/JAVA 2024.03.20

[Effective JAVA] 인스턴스화를 막으려거든 private 생성자를 사용하라. ( 아이템 4 )

정적 클래스나 정적메소드만 사용하는 클래스는 public 생성자를 두어 외부접근을 허용할 위험을 가질 필요가 없다. 생성자를 정의하지 않으면 컴파일러가 자동으로 기본생성자를 public으로 만들어준다. 그렇다고 추상클래스를 만들면 안된다. 추상클래스를 상속하는 하위 객체가 생성될 때 추상클래스의 인스턴스도 생성되기 때문이다. 그러므로 클래스의 인스턴스화를 막으려면 private으로 선언된 생성자를 두면 된다. private으로 선언하면 외부에서 접근이 불가능하고 상속도 되지 않는다. 하위 객체가 부모객체를 생성하지 못하기 때문이다.

Dev/JAVA 2024.03.20

[Effective JAVA] private 생성자나 열거타입으로 싱글턴임을 보증하라. ( 아이템 3 )

싱글턴 객체를 만드는 방식을 둘 중 하나이다. 1) 필드 멤버 모든 생성자를 private으로 감추어 객체 생성을 불가능하게 만들고, public static final로 선언된 멤버만 외부로 노출한다. 권한이 있는 클라이언트는 reflection으로 private 생성자를 호출하여 객체를 생성할 수 있으나, 두 번째 객체가 생성될 때 예외를 발생시키는 것으로 방지할 수 있다. 2) 정적 팩터리 private static final로 선언된 멤버변수에 객체를 생성하고 정적 메소드로만 해당 상수를 return하는 방식이다. 정적 팩터리 방식은 정적 메소드를 이용한 방식이다. 장점1) 싱글톤 객체는 final로 선언된 변수를 참조하므로, 동적으로 테스트가 쉽지 않다. 메소드 로직으로 스레드 종류에 따라 다른..

Dev/JAVA 2024.03.20

[Effective JAVA] 생성자 대신 정적 팩터리 메서드를 고려하라. ( 아이템 1 )

클라이언트가 특정 클래스의 인스턴스를 얻으려면 new 연산자로 public 생성자를 호출하면 된다. 하지만 이는 많은 단점을 가지고 있다. 1) 생성자는 오버로딩되어 파라미터에 따라 다양한 형태가 존재하는데, 생성자는 모두 동일한 이름이라 어떤 생성자가 어떤 종류의 인스턴스를 생성하는지 알 수 없다. 2) new 연산을 할 때마다 객체가 하나씩 생성되므로, 호출이 잦은 객체인 경우 쓸데없이 많은 객체가 생성될 수 있다. 3) 자기 자신의 인스턴스만 생성 가능하다. 4) 클라이언트와 생성하려는 클래스의 생성자를 참조하가 위해 클래스를 import 해야하므로 결합도가 올라간다. 이는 정적 팩터리 메서드로 해결 가능하다. 1) 생성자는 오버로딩되어 파라미터에 따라 다양한 형태가 존재하는데, 생성자는 모두 동일..

Dev/JAVA 2024.03.20

[ModernJAVA] Stream이 필요한 이유

컬렉션(Collection)은 데이터를 그룹화시켜 처리할 수 있도록 도와주는 자료구조이다. JAVA는 자료구조에 저장된 데이터를 조작할 수 있도록 Collection 인터페이스를 제공한다. 그러나 문제가 있다. 멀티코어 환경이 대중화 되면서 병렬 프로세스가 중요해졌다. 컬렉션에 저장된 데이터를 여러 스레드에 분산처리하면 높은 성능을 낼 수 있기 때문이다. 그러나 그 과정을 코드로 구현하기란 여간 복잡한 것이 아니다. JAVA는 명령형 프로그래밍이기에, 과정을 하나하나 코드로 구현해야만 한다. 음식 컬렉션을 세 가지 과정을 거쳐 조작해보자. 1) 400 칼로리 이하인 음식으로 필터링 한다. 2) 칼로리가 낮은 순으로 정렬한다. 3) 음식의 이름만 추출한다. 세 가지 과정을 명령형 프로그래밍으로 개발하면 아..

Dev/JAVA 2024.03.05