| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- JVM
- 메모리관리
- 코딩테스트
- 가비지컬렉션
- 개발자팁
- 프로그래머스
- 알고리즘공부
- 코딩테스트준비
- 알고리즘
- Java
- 코딩인터뷰
- 자료구조
- 백준
- 멀티스레드
- HashMap
- 코딩공부
- 자바기초
- 정렬
- 개발자취업
- 객체지향
- 클린코드
- 자바
- 파이썬
- 개발공부
- 예외처리
- 프로그래밍기초
- 자바공부
- 자바개발
- 코딩테스트팁
- 자바프로그래밍
- Today
- Total
코드 한 줄의 기록
Java 함수형 인터페이스와 메서드 레퍼런스 완벽 가이드 본문
자바 8이 출시된 지 꽤 시간이 지났지만, 여전히 함수형 인터페이스와 메서드 레퍼런스를 제대로 활용하지 못하는 개발자들이 많습니다. 저도 처음에는 이 개념들이 다소 낯설었는데요, 실무에서 사용하다보니 코드가 훨씬 간결해지고 가독성이 좋아지더라고요. 오늘은 제가 공부하면서 정리한 내용을 여러분과 공유하려고 합니다.
함수형 인터페이스란 무엇인가?
함수형 인터페이스는 딱 하나의 추상 메서드만 가지고 있는 인터페이스를 말합니다. Java 8부터 도입된 이 개념은 람다 표현식과 밀접한 관계가 있어요. 쉽게 말해서 함수를 마치 하나의 변수처럼 다룰 수 있게 해주는 도구라고 생각하면 됩니다.
@FunctionalInterface 어노테이션
함수형 인터페이스를 만들 때는 @FunctionalInterface 어노테이션을 붙여주는 게 좋습니다. 이 어노테이션은 필수는 아니지만, 컴파일러가 인터페이스가 함수형 인터페이스의 조건을 만족하는지 검사해주기 때문에 실수를 방지할 수 있습니다.
@FunctionalInterface
public interface MyFunction {
int calculate(int x, int y);
}
만약 이 인터페이스에 추상 메서드를 하나 더 추가하려고 하면 컴파일 에러가 발생합니다. 이런 식으로 개발자의 실수를 사전에 막아주는 거죠.
자바가 제공하는 주요 함수형 인터페이스
자바는 java.util.function 패키지에서 다양한 함수형 인터페이스를 기본으로 제공합니다. 매번 직접 만들 필요 없이 이미 만들어진 것들을 활용하면 되는 거예요.
1. Function<T, R>
Function은 타입 T를 받아서 타입 R을 반환하는 함수형 인터페이스입니다. 주요 메서드는 apply()이고, 변환 작업에 자주 사용됩니다.
Function<String, Integer> stringToLength = str -> str.length();
int length = stringToLength.apply("Hello"); // 5
2. BiFunction<T, U, R>
BiFunction<Integer, Integer, String> calculator = (a, b) -> {
int sum = a + b;
return "결과: " + sum;
};
String result = calculator.apply(10, 20); // "결과: 30"
3. Consumer<T>
Consumer<String> printer = message -> System.out.println(message);
printer.accept("Hello World!");
4. Supplier<T>
Supplier<Double> randomSupplier = () -> Math.random();
double randomValue = randomSupplier.get();
5. Predicate<T>
Predicate<Integer> isPositive = num -> num > 0;
boolean result = isPositive.test(5); // true
6. UnaryOperator와 BinaryOperator
UnaryOperator<Integer> doubleValue = x -> x * 2;
BinaryOperator<Integer> add = (a, b) -> a + b;
메서드 레퍼런스(Method Reference)
람다 표현식이 단순히 기존 메서드 하나만 호출하는 경우, 메서드 레퍼런스를 사용하면 코드를 훨씬 간결하게 만들 수 있습니다. "::" 이중 콜론을 사용합니다.
1. 정적 메서드 참조
Function<String, Integer> methodRef = Integer::parseInt;
int result = methodRef.apply("100"); // 100
2. 특정 객체의 인스턴스 메서드 참조
String prefix = "Hello, ";
Function<String, String> addPrefix = prefix::concat;
System.out.println(addPrefix.apply("World")); // "Hello, World"
3. 특정 타입의 임의 객체 인스턴스 메서드 참조
Function<String, Integer> methodRef = String::length;
int len = methodRef.apply("Hello"); // 5
4. 생성자 참조
Function<String, Person> personCreator = Person::new;
Person p = personCreator.apply("홍길동");
실무 예제
리스트 필터링
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Predicate<Integer> isEven = n -> n % 2 == 0;
Predicate<Integer> greaterThanFive = n -> n > 5;
List<Integer> result = numbers.stream()
.filter(isEven.and(greaterThanFive))
.collect(Collectors.toList());
// [6, 8, 10]
데이터 변환
List<String> names = Arrays.asList("alice", "bob", "charlie");
Function<String, String> format = s -> "Mr. " + s.toUpperCase();
List<String> result = names.stream().map(format).toList();
사용 시 주의사항
- 람다식 내부에서 외부 지역 변수는 final 또는 effectively final만 접근 가능
- Checked Exception은 직접 처리 필요
- 가독성이 떨어질 경우 메서드로 추출
함수형 인터페이스와 메서드 레퍼런스는 처음엔 어렵지만 익숙해지면 자바 코드가 훨씬 깔끔해집니다. Stream API와 함께 사용하면 복잡한 데이터 처리 로직을 간결하게 표현할 수 있습니다. 개념을 머리로 이해하는 것보다 실제로 손으로 코딩하면서 감을 익히는 게 가장 중요합니다.
Java 제네릭 완벽 가이드: 타입 파라미터부터 와일드카드까지 실전 총정리
최근에 자바 프로젝트를 진행하면서 제네릭에 대해 제대로 공부할 필요성을 느꼈습니다. 그동안 ArrayList 정도만 사용했는데, 실무 코드를 보니 나 같은 복잡한 문법이 자주 등장하더군요. 그래
byteandbit.tistory.com
'JAVA' 카테고리의 다른 글
| Java Optional로 NPE를 잡아보자 - 실무 활용 가이드 (0) | 2025.11.05 |
|---|---|
| Java 스트림 API 완벽 정리: 중간연산·최종연산·파이프라인 총정리 (0) | 2025.11.01 |
| Java 제네릭 완벽 가이드: 타입 파라미터부터 와일드카드까지 실전 총정리 (0) | 2025.10.28 |
| Java Iterator와 Fail-Fast, 컬렉션 수정 시 주의할 점들 (0) | 2025.10.27 |
| Java Comparable과 Comparator 완벽 가이드 - 정렬 전략 완전 정복 (0) | 2025.10.27 |