728x90
오늘 배웠던 내용들은 프로젝트나 코딩테스트 문제를 풀면서 대충 훑어보기만 하고 제대로 공부한적 없던 내용들이 나와서 전체적으로 정리해보았습니다.
구분 | 설명 | 예시 |
Stream | 컬렉션 데이터를 선언형 방식으로 처리하는 API. 중간 연산(map, filter 등)과 최종 연산(forEach, sum 등) 구분 | list.stream().filter(...).map(...).forEach(...) |
내부 클래스 (Inner Class) | 클래스 안에 정의된 클래스 (다른 클래스에 종속) | 클래스 A 안에 클래스 B 정의 |
└ 인스턴스 내부 클래스 | 외부 클래스의 인스턴스가 있어야 생성 가능 | Outer outer = new Outer(); Outer.Inner in = outer.new Inner(); |
└ 정적 내부 클래스 (static) | 외부 클래스와 독립적으로 생성 가능 | Outer.StaticInner in = new Outer.StaticInner(); |
└ 지역 내부 클래스 | 메서드 내부에서 정의된 클래스. 해당 메서드 안에서만 사용 가능 | void method() { class Local { } } |
└ 익명 내부 클래스 | 이름 없이 일회용 구현. 보통 인터페이스/추상클래스 구현 시 사용 | new Runnable() { public void run() { ... } } |
스레드 (Thread) | 동시에 여러 작업을 처리하기 위한 실행 흐름 단위. Thread 클래스나 Runnable 인터페이스로 구현 | new Thread(() -> { ... }).start(); |
람다식 (Lambda) | 함수형 인터페이스를 간결하게 구현하는 문법. 익명 내부 클래스보다 짧고 읽기 쉬움 |
1. Stream (스트림)
개요
컬렉션 데이터를 반복문 없이 선언적 방식으로 처리하는 API. Java 8에 도입되었으며, 중간 연산과 최종 연산을 체이닝 형태로 구성한다.
기존 방식과의 차이
기존에는 for문이나 while문 등 명령형 방식으로 처리했지만, 스트림은 map, filter, reduce 등의 메서드 체이닝으로 데이터를 처리한다.
장점
- 코드 간결성 향상
- 병렬 처리 용이 (parallelStream())
- 지연 연산 지원 (lazy evaluation)
- 불변 객체 기반 처리 권장
단점 및 주의사항
- 한 번 소비한 스트림은 재사용 불가
- 디버깅이 어렵고, 복잡한 로직은 오히려 가독성이 떨어질 수 있음
- 소량 데이터는 일반 루프보다 오버헤드가 클 수 있음
List<String> names = Arrays.asList("Kim", "Lee", "Park");
names.stream()
.filter(s -> s.length() >= 3)
.sorted()
.forEach(System.out::println);
2. 내부 클래스 (Inner Class)
자바 클래스 내부에 정의된 클래스이며, 크게 4가지로 나뉜다.
2-1. 인스턴스 내부 클래스
- 외부 클래스의 인스턴스가 있어야 생성 가능
- 외부 클래스의 멤버에 자유롭게 접근 가능
- Outer outer = new Outer(); Outer.Inner in = outer.new Inner();
장점
- 외부 클래스와 밀접한 관계가 있는 경우 코드 구조화에 유리
주의사항
- 외부 인스턴스와 생명 주기를 공유하므로 메모리 누수 주의
2-2. 정적 내부 클래스 (static nested class)
- 외부 클래스와 독립적으로 생성 가능
- 외부 클래스의 정적 멤버만 접근 가능
- Outer.StaticInner inner = new Outer.StaticInner();
장점
- 메모리 효율적
- 유틸리티 클래스나 빌더 패턴 구현 시 적합
2-3. 지역 내부 클래스
- 메서드 내부에 선언되는 클래스
- 해당 메서드 내에서만 사용 가능
- 외부 변수는 final 또는 effectively final이어야 참조 가능
주의사항
- 수명이 짧고 지역 변수 접근 시 제약이 많아 가독성이 떨어질 수 있음
2-4. 익명 내부 클래스
- 이름 없이 일회성으로 인터페이스나 추상 클래스를 구현
- 이벤트 처리나 콜백 등에서 사용
장점
- 간단한 처리 로직에 적합
단점
- 재사용 불가
- 가독성 및 디버깅 불리
Runnable r = new Runnable() {
public void run() {
System.out.println("실행");
}
};
3. 스레드 (Thread)
개요
프로세스 내에서 독립적으로 실행되는 흐름 단위. 자바에서 병렬 처리를 위한 기본 단위다.
구현 방식
- Thread 클래스 상속
- Runnable 인터페이스 구현
- Java 8 이후에는 람다식을 통한 구현 가능
장점
- 병렬 처리를 통해 대기 시간 단축
- 사용자 응답성 향상
단점 및 주의사항
- 공유 자원 접근 시 동기화 필요 (synchronized)
- 스레드가 너무 많으면 오히려 성능 저하
- 생명 주기 관리 복잡 → ExecutorService 권장
new Thread(() -> {
System.out.println("작업 실행");
}).start();
4. 람다식 (Lambda Expression)
개요
함수형 인터페이스를 간단하게 구현할 수 있는 표현식. Java 8부터 도입.
기존 방식과 차이
기존에는 익명 내부 클래스로 구현했으나, 람다식은 훨씬 간결한 표현 가능
장점
- 코드 간결
- 불필요한 클래스 제거
- 가독성 향상
단점 및 주의사항
- 디버깅 어려움 (스택 트레이스 분석 힘듦)
- this는 익명 내부 클래스와 다르게 람다를 감싸는 외부 객체를 가리킴
- 상태 있는 객체 사용에 부적합 (가급적 순수 함수로 활용)
예시
java
복사편집
Comparator<Integer> comp = (a, b) -> Integer.compare(a, b);
5. 함수형 인터페이스 (Functional Interface)
개요
추상 메서드가 하나만 존재하는 인터페이스. 람다식의 대상이 되기 위해 필요
특징
- @FunctionalInterface 애노테이션 사용 가능 (선택사항이지만 권장)
- 디폴트 메서드는 여러 개 정의 가능하나 추상 메서드는 하나만 있어야 함
장점
- 람다식과 결합해 코드 간결성 극대화
- 콜백이나 일회성 작업 처리에 유용
주의사항
- 추상 메서드가 2개 이상이면 컴파일 오류 발생
- 인터페이스가 의도하지 않게 변경될 경우 람다식 사용 불가
자바 제공 주요 함수형 인터페이스
- Runnable - 매개변수 없음, 반환값 없음
- Consumer<T> - 매개변수 있음, 반환값 없음
- Supplier<T> - 매개변수 없음, 반환값 있음
- Function<T, R> - 매개변수 T, 반환값 R
- Predicate<T> - 조건 검사 (boolean 반환)
'TIL' 카테고리의 다른 글
[TIL] 2025-5-23 제약조건/정규화 (0) | 2025.05.28 |
---|---|
[TIL] 2025-5-22 자바 입출력 (0) | 2025.05.22 |
[TIL] 2025-5-20 링크드리스트 (0) | 2025.05.20 |
[TIL] 2025-5-19 자바 인터페이스, 예외 처리, 제네릭 (1) | 2025.05.20 |
[TIL] 2025-5-16 메소드 오버라이딩/메소드 오버로딩 차이점 (0) | 2025.05.16 |
댓글