연산자
산술, 비교, 논리, 대입, 기타(형변환, 삼항, instanceOf 등)
조건문
if, if-else, switch
반복문
for , 향상된 for문, while, do-while
배열
배열 기초, String 배열, 다차원 배열 등
컬렉션
List, Set, Map, Queue, Deque 등
ArrayList<String> arrayList = new ArrayList<String>();
컬렉션은 꽤나 어려웠다. 선언문의 의미부터 혼란스러웠다. '<>' 각괄호 또는 앵글브래킷이라고 하는 녀석이었다.이 녀석은 제네릭 타입을 명시할 때 사용하는 표기이다.
제네릭 자체는 컬렉션 선언에서 필수는 아니다. 그러나 필수라 할 수 있을 정도로 제네릭 사용은 강력히 권장된다. 선언문에 제네릭을 사용하지 않으면, 컬렉션은 Object 타입의 객체를 저장하게 되는데, 이는 Object가 Java에서 모든 클래스의 최상위 클래스이기 때문에 의도하지 않은 타입의 객체도 저장될 수 있다. 그러나 제네릭을 사용하면 자바 컴파일러가 컴파일 단계에서 잘못된 타입이 사용되었는지 검사하기 때문에 런타임 때 발생할 문제를 미리 방지할 수 있다.
또한 제네릭을 사용하면, 컬렉션에서 객체를 꺼낼 때 일일히 형변환을 하는 수고로움을 덜 수 있다. 제네릭의 자동 형변환 기능을 통해 타입이 보장되기 때문이다.
이러한 이점을 가능하게 하는 제네릭의 타입소거 메커니즘에 대해서는 이후 제네릭을 배울 때 자세하게 검토해보는 것으로 한다.
배열은 초기화 시에 크기가 결정되며, 그 이후에는 크기를 변경할 수 없다. 또한, 모든 요소는 동일한 타입을 가져야 한다. 반면, 컬렉션은 런타임 동안 요소를 추가하거나 삭제함으로써 동적으로 크기를 조절할 수 있으며, 제네릭을 이용해 다양한 타입의 객체를 저장할 수 있다. 또한, 컬렉션 프레임워크는 List, Set, Map 등과 같이 데이터를 저장하고 조작하는 방식에 따라 다른 특성과 동작을 가지는 다양한 형태의 자료구조를 제공한다. 또한 컬렉션은 참조 타입의 데이터만을 저장한다.
그렇다. 배열은 String 배열 외에 다른 모든 참조 타입과 기본형 타입을 저장할 수 있다. 배열이 저장하는 요소의 타입에 따라 배열의 타입이 결정된다.
int[] array = new int[7]; // 기본형 배열
String[] array = new String[10]; // 참조형 배열
Fruit[] array = new Fruit[5]; // 참조형 배열 (Fruit 클래스가 있다고 가정)
참고로, 컬렉션은 기본형 타입을 직접 사용하지 못하고, 래퍼 클래스를 통해 박싱하여 간접적으로 사용할 수 있다. 컬렉션은 참조 타입만 저장 가능하다.
컬렉션 프레임워크를 이해하기 위해, 인터페이스라는 개념까지 같이 찾아보게 되었는데, 위계도를 작성하는 것이 이해에 도움이 돼 보인다.
컬렉션 프레임워크에서 우선 Collection 인터페이스가 다른 인터페이스들의 상위 인터페이스다. List, Set, Queue, Deque가 그 하위 인터페이스다. Map 인터페이스의 상위 인터페이스는 없다. Map 인터페이스는 컬렉션 프레임워크의 Collection 계층 구조에 속하지 않으며, 별도의 계층 구조로 구성된다.
다음은 오라클 자바 공식 문서에서 가져온 위계도이다. 구글에 검색해보면 위계도가 제각각이라 조심해야 한다.
상위 인터페이스 타입으로 객체를 구현하는 것이 유연한 객체 프로그래밍에 유리하다고 배웠다. 그런데 왜 Collection 타입의 객체 구현은 볼 수 없는 것일까?
일단은 저 방식은 유효하다. 부모 인터페이스로 참조 변수를 선언하면 다형성을 이용하여 여러 구현 클래스의 인스턴스를 참조할 수 있다. 그러나 부모 인터페이스로 객체를 구현하는 것은 다음과 같은 단점으로 인해 권장되지 않는다. 부모 인터페이스 타입으로 객체를 구현하면 자식 인터페이스에서 재정의된 메소드를 사용할 수 없다. 또한 부모 인터페이스에 선언되지 않은 자식 인터페이스의 메소드를 호출할 수 없습니다. 반대로, 자식 인터페이스 타입의 구현 객체에서는 부모 인터페이스의 디폴트 메소드, 정적 메소드를 호출할 수 있다.
자식 인터페이스 타입으로 구현하는 것이 중요하다고 생각하는 이유 중 가장 큰 이유는 가독성의 향상이다. 인터페이스 타입의 구현 클래스가 일치하면 가독성이 향상된다. 개발자는 협업능력이 중요하다. 남들이 내 코드를 봤을 때, 쉽게 이해할 수 있도록 직관적이어야 한다. 학생 때, 수학을 잘하는 사람은 풀이과정이 깔끔했다. 어떤 풀이과정은 경외롭기도 했다. 그런 것은 쉬우면서도 체계적이다. 그렇게 코딩하고 싶다.