일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Log
- AWS Athena
- naver smartEditor
- athena
- 자바
- aws S3
- Java
- AWS Glue
- AWS
- 인텔리J
- Git
- ibsheet
- AWS SQS
- intellij
- 자바스크립트
- Study
- 카이호스트만
- JavaScript
- 환경구성
- 아이비시트
- 자바8
- function
- aws lambda
- s3
- 환경 구성
- java8
- jQuery
- 로그 데이터
- #jQuery
- db
- Today
- Total
애매한 잡학사전
[자바8] 람다 표현식 - 1장 본문
'카이 호스트만의 코어 자바 8'을 기준으로 정리하였습니다.
1. 람다 표현식
- 1 ~ n번 실행할 수 있게 전달하는 코드 블록
- 자바에는 함수 타입이 없기 때문에 객체로 표현
- 파라미터 변수가 있는 표현식
: 오래전 컴퓨터가 없던 시절에 논리학자 안론조 처치는 수학 함수로 효과적인 계산을 할 수 있도록 관련 내용을 공식화 하려고 했다.
: 파라미터를 표기하는데 그리스 문자 람다(λ)를 사용했다.
: 공신력 있는 수학 원리 책에서 함수 파라미터를 나타내는 데 악센트 ^를 사용했는데 알론조 처치는 여기서 영감을 얻어
대문자 람다(Λ)를 사용했고, 나중에는 소문자 람다(λ)로 바꿨다.
2. 람다 표현식 문법
2-1. 일반 자바 메서드
public int strLength(String first, String second){
return first.length() - second.length();
}
2-2. 람다 표현식
(String first, String second) -> first.length() - second.length();
- 단순한 코드 블록이지만 해당 코드에 전달해야 하는 변수의 명세를 갖췄다.
- 결과 타입은 명시하지 않지만 컴파일러는 구현부로부터 결과 타입을 추론해서 기대하는 타입과 일치하는지 검사한다.
- 위의 표현식은 기대하는 결과가 int 타입인 문맥에서 사용할 수 있다.
2-3. n라인의 람다 표현식
(String first, String second) -> {
int difference = first.length() - second.length();
if (difference < 0) {
return -1;
} else if(difference > 0) {
return 1;
} else {
return 0;
}
}
- 람다 표현식의 구현부에서 표현식을 여러 줄로 작성할 때는 메서드를 작성하는 것처럼 작성한다.
2-4. 파라미터가 없는 람다 표현식
Runnable task = () -> { for(int i=0; i < 1000; i++) doWork(); }
- 람다 표현식이 파라미터를 받지 않으면 파라미터가 없는 메서드처럼 빈 괄호를 붙인다.
2-5. 파라미터 타입이 없는 람다 표현식
Comparator<String> comp = (first, second) -> first.length() - second.length();
- 람다 표현식을 문자열 비교자에 할당하므로 컴파일러는 first와 second를 문자열이라고 추론할 수 있기 때문에 생략할 수 있다.
2-6. 파라미터가 1개인 람다 표현식
EventHandler<ActionEvent> listener = event -> System.out.println("Oh noes!");
/* (event) 또는 (ActionEvent event) 대신 사용 가능 */
3. 함수형 인터페이스
- 추상 메서드가 한 개만 포함된 인터페이스에만 사용할 수 있는 인터페이스
3-1. 함수형 인터페이스 전달
/* Arrays.sort 메서드 */
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
/* Arrays.sort 람다 전달 */
Arrays.sort(words, (first, second) -> first.length() - second.length());
- Arrays.sort 메서드의 두 번째 파라미터 변수는 Comparator<String>을 구현하는 클래스의 객체를 받는다.
- Arrays.sort 메서드에 위와 같이 람다를 전달하면 람다 표현식의 구현부를 실행한다.
3-2. 함수 리터럴 참고
/* 자바스크립트 함수 타입 선언 */
var compare = function(first, second){
return first.length - second.length;
};
/* 함수 호출 */
compare("test1", "test");
/* 예상결과 : 1 */
- 함수 리터럴을 지원하는 대부분의 프로그래밍 언어는 (String, String) -> int 처럼 함수 타입을 선언하고, 이 함수 타입으로 변수를 선언한다. 그러면 함수를 해당 변수에 저장하고 호출할 수 있다.
String[] words = {"String", "Integer", "Float"};
Comparator<String> comp = (first, second) -> first.length() - second.length();
Arrays.sort(words, comp);
/* or */
Arrays.sort(words, (first, second) -> first.length() - second.length());
- 자바에서는 람다 표현식을 함수형 인터페이스 타입 변수에 저장해서 해당 인터페이스의 인스턴스로 변환하는 것만 가능하다.
3-3. 자주 사용하는 함수형 인터페이스
함수형 인터페이스 | 파라미터 타입 | 반환 타입 | 추상 메서드 이름 | 설명 | 다른 메서드 |
Runnable | 없음 | void | run | 인자나 반환 값 없이 액션을 수행한다. | |
Supplier<T> | 없음 | T | get | T 타입 값을 공급한다. | |
Consumer<T> | T | void | accept | T 타입 값을 소비한다. | andThen |
BiConsumer<T, U> | T, U | void | accept | T 와 U 타입 값을 소비한다. | andThen |
Function<T, R> | T | R | apply | T 타입 인자를 받는 함수다. | compose, andThen, identity |
BiFunction<T, U, R> | T, U | R | apply | T 와 U 타입 인자를 받는 함수다. | andThen |
UnaryOperator<T> | T | T | apply | T 타입에 작용하는 단항 연산자다. | compose, andThen, identity |
BinaryOperator<T> | T, T | T | apply | T 타입에 작용하는 이항 연산자다. | andThen, maxBy, minBy |
Predicate<T> | T | boolean | test | 불 값을 반환하는 함수다. | and, or, negate, isEqual |
BiPredicate<T, U> | T, U | boolean | test | 두 가지 인자를 받고 불 값을 반환하는 함수다. | and, or, negate |
3-4. 기본 타입용 함수형 인터페이스
함수형 인터페이스 | 파라미터 타입 | 반환 타입 | 추상 메서드 이름 |
BooleanSupplier | 없음 | boolean | getAsBoolean |
pSupplier | 없음 | p | getAsP |
pConsumer | p | void | accept |
ObjPConsumer<T> | T, p | void | accept |
pFunction<T> | p | T | apply |
pToQFunction | p | q | applyAsQ |
ToPFunction | T | p | applyAsP |
ToPBiFunction<T, U> | T, U | p | applyAsP |
PUnaryOperator | p | p | applyAsP |
PBinaryOperator | p, p | p | applyAsP |
PPredicate | p | boolean | test |
: p, q는 int, long, double이다. P, Q는 Int, Long, Double이다.
4. 메소드 참조
/* 대소문자 구분 없이 문자열 정렬 */
Arrays.sort(strings, (x, y) -> x.compareToIgnoreCase(y));
/* 위의 표현식 대신 사용 가능 */
Arrays.sort(strings, String::compareToIgnoreCase);
- :: 연산자는 메서드 이름과 클래스를 분리하거나 메서드 이름과 객체의 이름을 분리한다.
- 클래스::인스턴스메서드, 클래스::정적메서드, 객체::인스턴스메서드 3가지 형태로 사용할 수 있다.
4-1. 클래스::인스턴스메서드
- 첫 번째 파라미터가 메서드의 수신자가 되고, 나머지 파라미터는 해당 메서드로 전달된다.
: String::compareToIgnoreCase는 (x, y) -> x.compareToIgnoreCase(y)
4-2. 클래스::정적메서드
- 모든 파라미터가 정적 메서드로 전달된다.
: Objects::isNull은 x -> Objects.isNull(x)
4-3. 객체::인스턴스메서드
- 주어진 객체에서 메서드가 호출되며, 파라미터는 인스턴스 메서드로 전달된다.
: System.out::println은 x -> System.out.println(x)
= 같은 이름으로 오버로드된 메서드가 여러 개일 때 컴파일러는 문맥을 통해 어느 것을 의도했는지 알아내려 한다.
= 예를 들어 println 메서드는 여러 가지 버전이 있다. ArrayList<String>의 forEach 메서드에 println을 전달하면 println(String) 메서드가 선택된다.
5. 생성자 참조
- 생성자 참조는 메서드의 이름이 new라는 점만 제외하면 메서드 참조와 같다.
- 클래스에 생성자가 두 개 이상 있을 때는 문맥을 통해 호출할 생성자를 선택한다.
5-1. 일반 생성자 참조
- Employee::new 로 사용한다.
5-2. 배열 생성자 참조
- Employee[]::new 로 사용 하며 n -> new Employee[n] 과 같다.
- 자바에서는 제네릭 타입으로 배열 생성을 할 수 없어서 배열 생성자 참조를 사용하면 배열을 좀 더 확장해서 사용할 수 있다.
/* 이름 리스트 생성 */
List<String> names = Arrays.asList("A", "B", "C");
/* 일반 생성자 참조 */
Stream<Employee> stream = names.stream().map(Employee::new);
/* 배열 생성자 참조를 이용해서 이름 출력 */
for(Employee name : stream.toArray(Employee[]::new)){
System.out.println(name.getName());
}
/* Employee 클래스 */
public class Employee {
String name;
public Employee(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
'DEV > JAVA' 카테고리의 다른 글
java에서 Database 접속 구현하기 with 인터페이스 (2) | 2022.09.13 |
---|---|
[자바8] 람다 표현식 - 2장 (0) | 2022.02.15 |
[자바8] 인터페이스 java 8 interface - 2장 (0) | 2022.01.27 |
[자바8] 인터페이스 java 8 interface - 1장 (0) | 2022.01.24 |
AWS Personalize putUsers 처리 Importing users incrementally (0) | 2021.10.26 |