Java 8 Lambda 람다 #2

4 분 소요

Intro

Java 8에 새로 도입된 Lambda에 대해서 알아보자.
Java 8 Lambda 강좌 - Java Brains
연습예제 github

람다와 함께 지원되는 functional interfaces

별도의 인터페이스 생성없이 람다표현식을 쉽고 편리하게 사용가능하도록
Java 8 에서 여러 케이스의 functional interface들을 기본 지원해주는데요.
이와 관련해 내용이 잘 정리된 사이트가 있어 link를 아래 첨부합니다.

난파선 프로그래밍 블로그 - 표류중인 블로그

람다식에서의 Exception 처리

람다식에서 Exception 처리는 어떻게 할까요?
ExeptionExample.java 에서 람다식 호출부분에 Exception을 발생하는 코드를 작성합니다.

Exception 발생 코드

ExeptionExample.java

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
	int[] sumeNumbers = { 1, 2, 3, 4, 5 };
	int key = 2;

	process(sumeNumbers, key, (v, k) -> System.out.println(v / k));
}

private static void process(int[] sumeNumbers, int key, BiConsumer<Integer, Integer> consumer) {
	for (int i : sumeNumbers) {
		consumer.accept(i, key);
	}

}
  • 결과값
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at com.github.moregorenine.lambda.unit2.ExeptionExample.lambda$0(ExeptionExample.java:11)
	at com.github.moregorenine.lambda.unit2.ExeptionExample.process(ExeptionExample.java:16)
	at com.github.moregorenine.lambda.unit2.ExeptionExample.main(ExeptionExample.java:11)

위와 같이 5line 람다식 실행 중 Exception이 발생했을 때 람다에서는 어떻게 처리해야 할까요?
강의자는 Wrapper로 감싸는 #3 처리방식을 추천합니다. 왜일까요?

개인적인 견해로는 ExeptionExample.java의 코드와 처리 #1, #2, #3을 비교해보면 #3방식은 기존 코드를 수정하지 않았습니다.
람다식 부분을 수정한 것도 아니고, 람다식을 수행하는 interface를 수정한 것도 아닙니다.
그래서 #3방식이 #1, #2 방식에 비해 조금 더 유연한 처리가 가능한 방식이란 생각이 드네요.
시간을 가지고 조금더 곰곰히 생각 해봐야겠네요. 다른 의견이나 보충하고 싶은 내용이 있으시면 댓글 부탁드려요.

Exception 처리 #1 - ExeptionHandlingExample1.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String[] args) {
	int[] sumeNumbers = { 1, 2, 3, 4, 5 };
	int key = 0;

	process(sumeNumbers, key, (v, k) -> System.out.println(v / k));
}

private static void process(int[] sumeNumbers, int key, BiConsumer<Integer, Integer> consumer) {
	for (int i : sumeNumbers) {
		try {
			consumer.accept(i, key);
		} catch (ArithmeticException e) {
			System.out.println("ArithmeticException 발생...");
		}
	}
}
  • 결과값
ArithmeticException 발생...
ArithmeticException 발생...
ArithmeticException 발생...
ArithmeticException 발생...
ArithmeticException 발생...

Exception 처리 #2 - ExeptionHandlingExample2.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) {
	int[] sumeNumbers = { 1, 2, 3, 4, 5 };
	int key = 0;

	process(sumeNumbers, key, (v, k) -> {
		try {
			System.out.println(v / k);
		} catch (ArithmeticException e) {
			System.out.println("ArithmeticException 발생...");
		}
	});
}

private static void process(int[] sumeNumbers, int key, BiConsumer<Integer, Integer> consumer) {
	for (int i : sumeNumbers) {
		consumer.accept(i, key);
	}
}
  • 결과값
ArithmeticException 발생...
ArithmeticException 발생...
ArithmeticException 발생...
ArithmeticException 발생...
ArithmeticException 발생...

Exception 처리 #3 - ExeptionHandlingExample3.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void main(String[] args) {
	int[] sumeNumbers = { 1, 2, 3, 4, 5 };
	int key = 0;

	process(sumeNumbers, key, wrapperLambda((v, k) -> System.out.println(v / k)));
}

private static BiConsumer<Integer, Integer> wrapperLambda(BiConsumer<Integer, Integer> consumer) {
	return (v, k) -> {
		try {
			consumer.accept(v, k);
		} catch (ArithmeticException e) {
			System.out.println("ArithmeticException 발생...");
		}
	};
}

private static void process(int[] sumeNumbers, int key, BiConsumer<Integer, Integer> consumer) {
	for (int i : sumeNumbers) {
		consumer.accept(i, key);
	}
}
  • 결과값
ArithmeticException 발생...
ArithmeticException 발생...
ArithmeticException 발생...
ArithmeticException 발생...
ArithmeticException 발생...

Closures 람다식

ClosuresExample.java

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
public class ClosuresExample {

	public static void main(String[] args) {
		int a = 10;
		int b = 20;

		doProcess(a, new Process() {
			@Override
			public void process(int i) {
				System.out.println(i + b);
				b++;
			}
		});

	}

	private static void doProcess(int i, Process p) {
		p.process(i);
	}

}

interface Process {
	void process(int i);
}

위의 코드는 오류가 발생한다. 어느 부분에서 왜 날까?
11line 부분에서 아래와 같은 오류가 난다.

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	Local variable b defined in an enclosing scope must be final or effectively final

그 이유는 java의 anonymous class나 람다는 final 이어야만 접근이 가능하다. effectively final은 final 선언이 되어있진 않지만 생략만 됐지 실지적으로 final이란 말이다. 이에 대해 참조로 아래 링크를 추가한다.
java anonymous class 의 final

람다식의 ‘this’ 참조

ThisReferenceExample1.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) {
	ThisReferenceExample1 thisReferenceExample = new ThisReferenceExample1();

	thisReferenceExample.doProcess(10, new Process() {
		@Override
		public void process(int i) {
			System.out.println("value of i is " + i);
			System.out.println(this);
		}
	});
}

private void doProcess(int i, Process p) {
	p.process(i);
}
  • 결과값
value of i is 10
com.github.moregorenine.lambda.unit2.ThisReferenceExample1$1@7852e922

8line에 this는 누굴 가르키는 것일까? 4line의 Process interface의 인스턴스를 가르킨다.

ThisReferenceExample2.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ThisReferenceExample2 {
	public static void main(String[] args) {
		ThisReferenceExample2 thisReferenceExample = new ThisReferenceExample2();

		thisReferenceExample.doProcess(10, i -> {
			System.out.println("value of i is " + i);
			System.out.println(this);
		});
	}

	private void doProcess(int i, Process p) {
		p.process(i);
	}
}

ThisReferenceExample1의 4line을 람다식으로 변경해보았다.
그러자 this 참조를 사용할 수 없는 컴파일오류가 발생한다.

ThisReferenceExample3.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ThisReferenceExample3 {
	public static void main(String[] args) {
		ThisReferenceExample3 thisReferenceExample = new ThisReferenceExample3();

		thisReferenceExample.doProcess(10, i -> {
			System.out.println("value of i is " + i);
//			System.out.println(this); this will not work
		});
		
		thisReferenceExample.execute();
	}

	private void doProcess(int i, Process p) {
		p.process(i);
	}
	
	private void execute() {
		doProcess(10, i -> {
			System.out.println("value of i is " + i);
			System.out.println(this);
		});
	}
}

ThisReferenceExample2.java의 람다식을 execute 함수를 생성해서 호출할 경우

1
2
3
4
5
/** Static wrapper for DirectMethodHandle.internalMemberName. */
    @ForceInline
    /*non-public*/ static Object internalMemberName(Object mh) {
        return ((DirectMethodHandle)mh).member;
    }

위 함수가 실행되며 ‘this’ 객체 참조가 가능했다.

Java 8 Lambda 람다 #1 link

댓글남기기