반응형
본 내용은 라울-게이브리얼 우르마, 마리오 푸스코, 앨런 마이크로프트의 "모던 자바 인 액션" 책을 보고 정리한 내용입니다. 저작권 보호를 위해 책의 내용은 요약되었습니다.
동작 파라미터화
- 함수형 프로그래밍의 핵심 개념으로 메서드의 동작을 다른 메서드로 전달할 수 있는 기능이다.
- 자주 변경되는 요구사항에 효과적으로 대응할 수 있다.
자바 8 이전
- 자바 8 이전에는 동작 파라미터화가 불가능하기에 변수를 파라미터화 시킨 동작으로 프로그램을 구현했다.
예시) 성별이 MEN인 Member와 나이가 25 이상인 Member를 출력한다.
package modernjavainaction.chap02;
import java.util.ArrayList;
import java.util.List;
public class FilteringMember {
// 메인 메서드
public static void main(String... args){
List<Member> memberList = new ArrayList<Member>();
memberList.add(new Member("sjmoon", Gender.MEN, 28));
memberList.add(new Member("jjmoon", Gender.MEN, 23));
memberList.add(new Member("hydong", Gender.WOMEN, 29));
memberList.add(new Member("sslee", Gender.WOMEN, 21));
// 성별이 MEN인 Member만 출력
List<Member> genderList = filterMemberByGender(memberList, Gender.MEN);
for (Member member : genderList) {
System.out.println("이름: " + member.getName() + ", 성별: " + member.getGender());
}
/*
이름: sjmoon, 성별: MEN
이름: jjmoon, 성별: MEN
*/
// 나이가 25이상인 Member만 출력
List<Member> ageList = filterMemberByAge(memberList, 25);
for (Member member : ageList) {
System.out.println("이름: " + member.getName() + ", 나이: " + member.getAge());
}
/*
이름: sjmoon, 나이: 28
이름: hydong, 나이: 29
*/
}
// 성별 기준
public static List<Member> filterMemberByGender(List<Member> members, Gender gender){
List<Member> list = new ArrayList<Member>();
for(Member member : members){
if(member.getGender().equals(gender)){
list.add(member);
}
}
return list;
}
// 나이 기준
public static List<Member> filterMemberByAge(List<Member> members, int age){
List<Member> list = new ArrayList<Member>();
for(Member member : members) {
if(member.getAge() >= age) {
list.add(member);
}
}
return list;
}
// 성별 Enum
enum Gender{
MEN, WOMEN
}
// Member 클래스
public static class Member {
String name;
Gender gender;
int age;
public Member(String name, Gender gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Gender getGender() {
return gender;
}
public void setGender(Gender gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}
1. 추상적 조건으로 필터링(전략 디자인 패턴)
- 전략 디자인 패턴은 각 알고리즘을 캡슐화하는 알고리즘을 미리 정의해두고, 런타임에 알고리즘을 선택하는 기법으로 조건에 따라 메서드가 다르게 동작하는 것을 말한다.
- Collection의 탐색 로직과 항목에 적용할 동작을 분리할 수 있다는 것이 강점이다.
예시)
// 메인 메서드
public static void main(String... args){
List<Member> memberList = new ArrayList<Member>();
memberList.add(new Member("sjmoon", Gender.MEN, 28));
memberList.add(new Member("jjmoon", Gender.MEN, 23));
memberList.add(new Member("hydong", Gender.WOMEN, 29));
memberList.add(new Member("sslee", Gender.WOMEN, 21));
// 성별이 MEN인 Member만 출력
List<Member> genderList = filterMembers(memberList, new MemberGenderPredicate());
for (Member member : genderList) {
System.out.println("이름: " + member.getName() + ", 성별: " + member.getGender());
}
/*
이름: sjmoon, 성별: MEN
이름: jjmoon, 성별: MEN
*/
// 나이가 25이상인 Member만 출력
List<Member> ageList = filterMembers(memberList, new MemberAgePredicate());
for (Member member : ageList) {
System.out.println("이름: " + member.getName() + ", 나이: " + member.getAge());
}
/*
이름: sjmoon, 나이: 28
이름: hydong, 나이: 29
*/
}
// Predicate 인터페이스
public interface MemberPredicate {
boolean test(Member member);
}
// 성별 기준
public static class MemberGenderPredicate implements MemberPredicate{
public boolean test(Member member){
return Gender.MEN.equals(member.getGender());
}
}
// 나이 기준
public static class MemberAgePredicate implements MemberPredicate{
public boolean test(Member member){
return member.getAge() > 25;
}
}
// MemberPredicate를 파라미터화
public static List<Member> filterMembers(List<Member> members, MemberPredicate predicate){
List<Member> list = new ArrayList<Member>();
for (Member member : members) {
if (predicate.test(member)) {
list.add(member);
}
}
return list;
}
2. 익명 클래스 사용
- 익명 클래스란 이름이 없는 클래스로, 주로 인터페이스나 추상 클래스를 구현하거나 확장하는 방식으로 사용한다.
- 자바의 지역 클래스와 비슷한 개념으로 클래스 선언과 인스턴스화를 동시에 사용하여 즉석에서 필요한 동작을 구현할 수 있다.
- 익명 클래스는 여전히 많은 공간을 차지하고 많은 프로그래머가 익명 클래스에 익숙하지 않다.
예시)
// 메인 메서드
public static void main(String... args){
List<Member> memberList = new ArrayList<Member>();
memberList.add(new Member("sjmoon", Gender.MEN, 28));
memberList.add(new Member("jjmoon", Gender.MEN, 23));
memberList.add(new Member("hydong", Gender.WOMEN, 29));
memberList.add(new Member("sslee", Gender.WOMEN, 21));
// 성별이 MEN인 Member만 출력
List<Member> genderList = filterMembers(memberList, new MemberFilter() {
@Override
public boolean test(Member member) {
return Gender.MEN.equals(member.getGender());
}
});
for (Member member : genderList) {
System.out.println("이름: " + member.getName() + ", 성별: " + member.getGender());
}
/*
이름: sjmoon, 성별: MEN
이름: jjmoon, 성별: MEN
*/
// 나이가 25이상인 Member만 출력
List<Member> ageList = filterMembers(memberList, new MemberFilter() {
@Override
public boolean test(Member member) {
return member.getAge() >= 25;
}
});
for (Member member : ageList) {
System.out.println("이름: " + member.getName() + ", 나이: " + member.getAge());
}
/*
이름: sjmoon, 나이: 28
이름: hydong, 나이: 29
*/
}
// 인터페이스를 활용한 익명 클래스
public interface MemberFilter {
boolean test(Member member);
}
// 공통적으로 사용되는 필터 메서드
public static List<Member> filterMembers(List<Member> members, MemberFilter filter) {
List<Member> list = new ArrayList<>();
for (Member member : members) {
if (filter.test(member)) {
list.add(member);
}
}
return list;
}
3. 람다 표현식 사용
- 람다 표현식은 함수형 프로그래밍 스타일을 자바에 도입하고 코드를 더 간결하게 작성할 수 있게 해준다.
예시)
// 메인 메서드
public static void main(String... args){
List<Member> memberList = new ArrayList<Member>();
memberList.add(new Member("sjmoon", Gender.MEN, 28));
memberList.add(new Member("jjmoon", Gender.MEN, 23));
memberList.add(new Member("hydong", Gender.WOMEN, 29));
memberList.add(new Member("sslee", Gender.WOMEN, 21));
// 성별이 MEN인 Member만 출력
List<Member> genderList = filterMembers(memberList, (Member member) -> Gender.MEN.equals(member.getGender()));
for (Member member : genderList) {
System.out.println("이름: " + member.getName() + ", 성별: " + member.getGender());
}
/*
이름: sjmoon, 성별: MEN
이름: jjmoon, 성별: MEN
*/
// 나이가 25이상인 Member만 출력
List<Member> ageList = filterMembers(memberList, (Member member) -> member.getAge() > 25);
for (Member member : ageList) {
System.out.println("이름: " + member.getName() + ", 나이: " + member.getAge());
}
/*
이름: sjmoon, 나이: 28
이름: hydong, 나이: 29
*/
}
// 인터페이스
public interface MemberFilter {
boolean test(Member member);
}
// 공통적으로 사용되는 필터 메서드
public static List<Member> filterMembers(List<Member> members, MemberFilter filter) {
List<Member> list = new ArrayList<>();
for (Member member : members) {
if (filter.test(member)) {
list.add(member);
}
}
return list;
}
4. 리스트 형식으로 추상화
- 리스트에 필터 메서드를 사용하여 Mebmer 뿐아니라 다른 클래스를 인자로 사용해도 된다.
예시)
// 메인 메서드
public static void main(String... args){
List<Member> memberList = new ArrayList<Member>();
memberList.add(new Member("sjmoon", Gender.MEN, 28));
memberList.add(new Member("jjmoon", Gender.MEN, 23));
memberList.add(new Member("hydong", Gender.WOMEN, 29));
memberList.add(new Member("sslee", Gender.WOMEN, 21));
// 성별이 MEN인 Member만 출력
List<Member> genderList = filter(memberList, (Member member) -> Gender.MEN.equals(member.getGender()));
for (Member member : genderList) {
System.out.println("이름: " + member.getName() + ", 성별: " + member.getGender());
}
/*
이름: sjmoon, 성별: MEN
이름: jjmoon, 성별: MEN
*/
// 나이가 25이상인 Member만 출력
List<Member> ageList = filter(memberList, (Member member) -> member.getAge() > 25);
for (Member member : ageList) {
System.out.println("이름: " + member.getName() + ", 나이: " + member.getAge());
}
/*
이름: sjmoon, 나이: 28
이름: hydong, 나이: 29
*/
}
// 인터페이스를 활용한 익명 클래스
public interface Predicate<T> {
boolean test(T t);
}
// 공통적으로 사용되는 필터 메서드
public static <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> result = new ArrayList<>();
for (T e : list) {
if (p.test(e)) {
result.add(e);
}
}
return result;
}
동작 파라미터 실전 예제
1. Comparator 정렬
예시) 익명 클래스 사용
// 메인 메서드
public static void main(String... args){
List<FilteringMember.Member> memberList = new ArrayList<FilteringMember.Member>();
memberList.add(new FilteringMember.Member("sjmoon", FilteringMember.Gender.MEN, 28));
memberList.add(new FilteringMember.Member("hydong", FilteringMember.Gender.WOMEN, 29));
memberList.add(new FilteringMember.Member("jjmoon", FilteringMember.Gender.MEN, 23));
memberList.add(new FilteringMember.Member("sslee", FilteringMember.Gender.WOMEN, 21));
memberList.sort(new Comparator<Member>() {
@Override
public int compare(Member m1, Member m2) {
return m1.getGender().compareTo(m2.getGender());
}
});
// 성별로 정렬
for (Member member : memberList) {
System.out.println("이름: " + member.getName() + ", 성별: " + member.getGender()+ ", 나이: " + member.getAge()+"살");
}
/*
이름: sjmoon, 성별: MEN, 나이: 28살
이름: jjmoon, 성별: MEN, 나이: 23살
이름: hydong, 성별: WOMEN, 나이: 29살
이름: sslee, 성별: WOMEN, 나이: 21살
*/
memberList.sort(new Comparator<Member>() {
@Override
public int compare(Member m1, Member m2) {
return Integer.compare(m1.getAge(), m2.getAge());
}
});
// 나이별로 정렬
for (Member member : memberList) {
System.out.println("이름: " + member.getName() + ", 성별: " + member.getGender()+ ", 나이: " + member.getAge()+"살");
}
/*
이름: sslee, 성별: WOMEN, 나이: 21살
이름: jjmoon, 성별: MEN, 나이: 23살
이름: sjmoon, 성별: MEN, 나이: 28살
이름: hydong, 성별: WOMEN, 나이: 29살
*/
}
예시) 람다 표현식 사용
public static void main(String... args){
List<FilteringMember.Member> memberList = new ArrayList<FilteringMember.Member>();
memberList.add(new FilteringMember.Member("sjmoon", FilteringMember.Gender.MEN, 28));
memberList.add(new FilteringMember.Member("hydong", FilteringMember.Gender.WOMEN, 29));
memberList.add(new FilteringMember.Member("jjmoon", FilteringMember.Gender.MEN, 23));
memberList.add(new FilteringMember.Member("sslee", FilteringMember.Gender.WOMEN, 21));
memberList.sort((m1, m2) -> m1.getGender().compareTo(m2.getGender()));
// 성별로 정렬
for (Member member : memberList) {
System.out.println("이름: " + member.getName() + ", 성별: " + member.getGender()+ ", 나이: " + member.getAge()+"살");
}
/*
이름: sjmoon, 성별: MEN, 나이: 28살
이름: jjmoon, 성별: MEN, 나이: 23살
이름: hydong, 성별: WOMEN, 나이: 29살
이름: sslee, 성별: WOMEN, 나이: 21살
*/
memberList.sort((m1, m2) -> Integer.compare(m1.getAge(), m2.getAge()));
// 나이별로 정렬
for (Member member : memberList) {
System.out.println("이름: " + member.getName() + ", 성별: " + member.getGender()+ ", 나이: " + member.getAge()+"살");
}
/*
이름: sslee, 성별: WOMEN, 나이: 21살
이름: jjmoon, 성별: MEN, 나이: 23살
이름: sjmoon, 성별: MEN, 나이: 28살
이름: hydong, 성별: WOMEN, 나이: 29살
*/
}
2. Runnable 코드 블록 실행
Runnalbe 인터페이스를 이용하여 실행할 코드 블록을 지정한다.
예시) 익명 클래스 사용
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Runnable 실행");
}
});
// 새로운 스레드 시작
t.start(); // Runnable 실행
예시) 람다 표현식 사용
Thread t = new Thread(() -> System.out.println("Runnable 실행"));
t.start(); // Runnable 실행
3. Callable을 결과로 반환
ExecutorSerivce 인터페이스는 테스크를 스레드 풀로 보내고 결과를 Future로 저장하여 테스크 제출과 실행 과정의 연관성을 끊어준다.
예시) 익명 클래스 사용
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> name = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return Thread.currentThread().getName();
}
});
// 결과를 얻을 때까지 대기하고 출력
String threadName = name.get();
System.out.println("스레드 이름: " + threadName); // 스레드 이름: pool-1-thread-1
// ExecutorService 종료
executorService.shutdown();
예시) 람다 표현식 사용
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> name = executorService.submit(() -> Thread.currentThread().getName());
// 결과를 얻을 때까지 대기하고 출력
String threadName = name.get();
System.out.println("스레드 이름: " + threadName); // 스레드 이름: pool-1-thread-1
// ExecutorService 종료
executorService.shutdown();
4. GUI 이벤트 처리
일반적으로 GUI 프로그래밍은 마우스 클릭 같은 이벤트로 동작하는데 이러한 GUI 프로그래밍도 변화에 대응할 수 있는 유연한 코드가 필요하기에 EventHandler를 파라미터로 전달할 수 있게 했다.
반응형
'Java' 카테고리의 다른 글
[자바 8] 함수형 인터페이스 (0) | 2023.09.24 |
---|---|
[자바 8] 람다 표현식 (0) | 2023.09.18 |
[자바] 자바 8 (0) | 2023.09.01 |
[자바] CompletableFuture (0) | 2023.07.02 |
[자바] Callable과 Future (0) | 2023.07.01 |