Language
-
[Effective Java] 아이템27: 비검사 경고를 제거하라Language/Java 2022. 7. 29. 19:08
✔️ 할 수 있는 한 모든 비검사 경고를 제거하라. 모두 제거한다면 그 코드는 타입 안전성이 보장된다. 즉, 런타임에 ClassCastException이 발생할 일이 없다. ✔️ 경고를 제거할 수는 없지만 타입 안전하다고 확신할 수 있다면 @SuppressWarning("unchecked") 애너테이션을 달아 경고를 숨기자. 안전하다고 검증된 비검사 경고를 숨기지 않고 그대로 두면, 진짜 문제를 알리는 새로운 경고가 나와도 눈치채지 못할 수 있다. 단, 경고를 무시해도 안전한 이유를 항상 주석으로 남겨야 한다. ✔️ @SuppressWarning 애너테이션은 항상 가능한 한 좁은 범위에 적용하자. @SuppressWarning 애너테이션은 개별 지역변수 선언부터 클래스 전체까지 어떤 선언에도 달 수 있다..
-
[Effective Java] 아이템26: 로 타입(raw type)은 사용하지 말라Language/Java 2022. 7. 29. 16:29
✔️ 제네릭 타입과 로 타입 클래스와 인터페이스 선언에 타입 매개변수가 쓰이면 제네릭 클래스 혹은 제네릭 인터페이스라고 하며, 두 가지를 통틀어 제네릭 타입(generic type)이라고 한다. 로 타입(raw type)이란 타입 매개변수가 없는 제네릭 타입을 말한다. 예를 들어, List의 로 타입은 List다. 로 타입은 타입 선언에서 제네릭 타입 정보를 전부 지워진 것처럼 동작하는데, 제네릭이 도래하기 전 코드와 호환되도록 하기 위한 궁여지책이라 할 수 있다. ✔️ 컬렉션의 로 타입 컬렉션 로 타입을 사용할 경우, 엉뚱한 타입을 넣어도 오류 없이 컴파일되고 실행될 수 있다. 이 경우, 형변환 시 ClassCastException을 던지게 된다. 📍 컬렉션의 로 타입 → 좋지 않은 예! private..
-
[Effective Java] 아이템25: 톱레벨 클래스는 한 파일에 하나만 담으라Language/Java 2022. 7. 23. 00:06
소스 파일 하나에 여러 개의 톱레벨 클래스를 선언하더라도 자바 컴파일러는 불평하지 않는다. 하지만 아무런 득이 없을 뿐더러 심각한 위험을 감수해야 한다. 한 클래스를 여러 가지로 정의할 수 있으며, 그 중 어느 것을 사용할지는 어느 소스 파일을 먼저 컴파일하느냐에 따라 달라지기 때문이다. 💡 예제 Main.java public class Main { public static void main(String[] args) { System.out.println(Utensil.NAME + Dessert.NAME); } } Utensil.java // 두 클래스가 한 파일(Utensil.java)에 정의되었다. - 따라 하지 말 것! class Utensil { static final String NAME = "..
-
[Effective Java] 아이템24: 멤버 클래스는 되도록 static으로 만들라Language/Java 2022. 7. 22. 23:42
✔️ 중첩 클래스(nested class)란? 중첩 클래스는 '다른 클래스 안에 정의된 클래스'를 말한다. 자신을 감싼 바깥 클래스에서만 사용되어야 하며, 그 외의 쓰임새가 있다면 톱레벨 클래스로 만들어야 한다. 💡 종류 (4가지) 정적 멤버 클래스 비정적 멤버 클래스 익명 클래스 지역 클래스 첫 번째를 제외한 나머지(비정적 멤버 클래스, 익명 클래스, 지역 클래스)는 모두 내부 클래스(inner class)에 해당한다. ✔️ 정적 멤버 클래스 다른 클래스 안에 선언되고, 바깥 클래스의 private 멤버에도 접근할 수 있다. 흔히 바깥 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스로 쓰인다. private 정적 멤버 클래스는 흔히 바깥 클래스가 표현하는 객체의 한 부분, 즉 구성요소로 나타..
-
[Effective Java] 아이템23: 태그 달린 클래스보다는 클래스 계층구조를 활용하라Language/Java 2022. 7. 18. 12:10
✔️ 태그 달린 클래스 📍 예시 class Figure { enum Shape { RECTANGLE, CIRCLE }; // 태그 필드 - 현재 모양을 나타낸다. final Shape shape; // 다음 필드들은 모양이 사각형(RECTANGLE)일 때만 쓰인다. double length; double width; // 다음 필드는 모양이 원(CIRCLE)일 때만 쓰인다. double radius; // 원용 생성자 Figure(double radius) { shape = Shape.CIRCLE; this.radius = radius; } // 사각형용 생성자 Figure(double length, double width) { shape = Shape.RECTANGLE; this.length = len..
-
[Effective Java] 아이템22: 인터페이스는 타입을 정의하는 용도로만 사용하라Language/Java 2022. 7. 16. 01:10
인터페이스는 자신을 구현할 클래스의 인스턴스를 참조할 수 있는 타입 역할을 한다. 인터페이스는 오직 이 용도로만 사용해야 한다. ✔️ 상수 인터페이스 - 잘못된 사용 예시 인터페이스를 타입을 정의하는 용도로 사용하지 않은 대표적인 예로 상수 인터페이스를 들 수 있다. 상수 인터페이스란, 메서드 없이 상수를 뜻하는 static final 필드로만 가득 찬 인터페이스를 말한다. 📍 상수 인터페이스 안티패턴 // 상수 인터페이스 안티패턴 - 사용금지! public interface PhysicalConstants { // 아보가드로 수 (1/몰) static final double AVOGADROS_NUMBER = 6.022_140_857e23; // 볼츠만 상수 (J/K) static final double..
-
[Effective Java] 아이템21: 인터페이스는 구현하는 쪽을 생각해 설계하라Language/Java 2022. 7. 14. 15:47
자바 8 전에는 기존 구현체를 깨뜨리지 않고는 인터페이스에 메서드를 추가할 방법이 없었으나,자바 8 부터는 디폴트 메서드가 소개되면서 기존 인터페이스에 메서드를 추가할 수 있게 되었다. 그러나 이렇게 추가된 디폴트 메서드가 모든 기존 구현체들과 매끄럽게 연동되리라는 보장은 없다. ✔️ 디폴트 메서드 추가 시 주의사항 1️⃣ 디폴트 메서드는 컴파일에 성공하더라도 기존 구현체에 런타임 오류를 일으킬 수 있다. 흔한 일은 아니지만, 일어나지 않으리라는 보장도 없다. 2️⃣ 기존 인터페이스에 디폴트 메서드로 새 메서드를 추가하는 일은 꼭 필요한 경우가 아니면 피해야 한다. 추가하려는 디폴트 메서드가 기존 구현체들과 충돌하지 않을지 심사숙고해야 한다. 또한, 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 ..
-
[Effective Java] 아이템20: 추상 클래스보다는 인터페이스를 우선하라Language/Java 2022. 7. 9. 09:02
✔️ 인터페이스 vs 추상 클래스 자바가 제공하는 다중 구현 메커니즘은 인터페이스와 추상 클래스 2가지다. 두 메커니즘 모두 인스턴스 메서드를 구현 형태로 제공할 수 있다. 둘의 가장 큰 차이는 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다. 자바는 단일 상속만을 지원하므로, 추상 클래스 방식은 새로운 타입을 정의하는 데 커다란 제약을 안겨준다. 반면 인터페이스가 선언한 메서드를 모두 정의하고 그 일반 규약을 잘 지킨 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급된다. 또한 기존 클래스에도 손쉽게 새로운 인터페이스를 구현해넣을 수 있다. (인터페이스가 요구하는 메서드를 추가하고, 클래스 선언에 implements 구문을 추가하기만 하면..