람다는 메서드를 하나의 식으로 표현한 것
int addOperation(int a, int b) {
return a + b;
}
// ========> 람다식으로 변환
(int a, int b) -> a + b
// (a, b) -> a + b 이렇게 매개변수 생략 가능
// a -> a * a 이렇게 파라미터 괄호 생략 가능
//파라미터 왼쪽, 화살표, 반환할 값 오른쪽
람다식은 Runnable 함수형 인터페이스
함수형 인터페이스 = 추상 메서드가 딱 1개만 있는 인터페이스 (*default 메서드, static 메서드는 존재할 수 있음)
인스턴스를 람다식을 사용해 간단하게 만들수 있다
함수형 언어
자바는 원래 oop 언어인데 jdk 1.8 부터 함수형 언어의 기능이 추가됨,
함수형 언어로는 scala 등이 있고 bigdata 등을 처리하기 위해 함수형 언어가 필요하다
파이썬, js 도 oop + fp (함수형 언어) 기능을 가지고 있다.
람다식
람다식이란 함수(메서드)를 간단한 식으로 표현하는 방법을 말한다.
람다식은 익명 함수(이름이 없는 함수) 이다.
메서드를 람다식으로 쓸 때 반환 타입과 이름을 지우고 가운데에 화살표를 넣는다.
함수와 메소드의 차이?
-> 근본적으로 동일. 함수는 일반적 용어이고 메소드는 객체지향개념 용어이다.
함수는 클래스에 독립적(클래스 바깥에 있음)이고 메서드는 클래스에 종속적(클래스 안에 있음)이다.
자바에서는 클래스 밖에 있을수 없으므로 전부다 메서드이다..
즉 자바에서 함수 = 메서드 라고 생각하면 되겠다
람다식 작성하기
1. 메서드의 이름과 반환타입 제거하고 -> 를 블록{} 앞에 추가
int max(int a, int b) {
return a > b ? a : b;
}
// ------------------>
(a, b) -> a > b ? a : b //람다식으로 표현
2. 반환값이 있는 경우 return 문 생략가능. 끝에 ; 안붙임
3. 매개변수의 타입이 추론 가능하면 생략가능(대부분 생략가능)
(int a, int b) -> a > b ? a : b 에서 (a, b) -> a > b ? a : b 로 작성가능
람다식 작성하기 : 주의사항
1. 매개변수가 하나인 경우 괄호() 생략 가능(타입이 없을때만)
(a) -> a * a 의 경우 a -> a * a 로 작성 가능
(int a) -> a * a 의 경우는 꼭 괄호 있어야 함
2. 블록 안의 문장이 하나뿐일때 괄호 {} 생략가능 (끝에 ; 안붙임)
(int i) -> {
System.out.println(i);
}
// -------> 람다식 작성
(int i) -> System.out.println(i)
// 단, 하나뿐인 문장이 return 문이면 괄호 {} 생략 불가 -- 하지만 대부분 리턴 생략
(int a, int b) -> { return a > b ? a: b; } // OK
(int a, int b) -> return a > b ? a: b; // 에러
람다식 작성 예시
// 1
int max(int a, int b) {
return a > b ? a : b
}
// 람다식 변환
(a, b) -> a > b ? a : b
//2
int printVar(String name, int i) {
System.out.println(name+"="+i);
}
// 람다식 변환
(name, i) -> System.out.println(name+"="+i)
//3
int squre(int x) {
return x * x;
}
// 람다식 변환- 매개변수 하나일때는 () 지울수 있음
x -> x * x
//4
int roll() {
return (int) (Math.random()*6);
}
// 람다식 변환
() -> (int) (Math.random()*6)
람다식은 익명 함수가 아닌 익명 객체
☕ 익명 클래스(Anonymous Class) 사용법 총정리
익명 클래스 (Anonymous Class) 익명 클래스는 내부 클래스(Inner class) 일종으로 단어 그대로 이름이 없는 클래스를 말한다. 익명, 이름이 없다는 것은 별로 기억되지 않아도 된다는 것이며, 나중에 다
inpa.tistory.com
해당 블로그를 참고하면 더 도움이 될거 같다
어쨌든 람다식은 익명객체인데 객체의 선언과 생성을 동시에 한다고 생각하면 된다
new Object() {
int max(int a, int b) {
return a > b ? a : b;
}
}
//위처럼 써야 하는 코드를 람다식으로 간단히 아래처럼 쓸 수 있다
(a, b)-> a > b ? a : b
람다식(익명객체)을 다루기 위한 참조변수가 필요한데 참조변수의 타입은??
public class MainJava2 {
public static void main(String[] args) {
Object obj = new Object() {
int max(int a, int b) {
return a > b? a : b;
}
};
//타입 obj = (a, b)-> a > b ? a : b // 어떤 타입?
//Object 로 타입을 하게되면
int value = obj.max(3,5); // // 에러, Object 클래스에 max() 가 없음,
//즉, 객체가 메서드를 가지고있어도 호출불가 인 사태 발생
}
}
익명 객체에서 메서드 부분을 표현한게 람다식이고,
자바에서는 메서드만 존재할수없기 때문에(모든 메서드는 객체안에 있어야함) 익명 객체안에 감싼 것임
하지만 호출불가인 사태가 발생함
==> 함수형 인터페이스가 필요하다
함수형 인터페이스
함수형 인터페이스란 단 하나의 추상 메서드만 선언된 인터페이스를 말한다.
package plusJavaStudy;
public class StudyLambda3 {
public static void main(String[] args) {
/*
MyFunction2 f = new MyFunction2() { // 익명클래스로 클래스 선언, 객체 생성 동시에.. 문법 : new 조상이름 (클래스나 인터페이스) {}
public int max(int a, int b) { //오버라이딩 - 접근제한자는 좁게 못바꾼다
return a > b ? a : b;
}
};
*/
//람다식을 다루기 위한 참조변수의 타입은 함수형 인터페이스로 한다
MyFunction2 f = (a, b) -> a > b ? a : b; //a, b는 메소드 매개변수 타입과 같아야한다.
//함수형 인터페이스에 있는 추상메소드 max와 해당 람다식을 매칭해준다고 생각하면 된다.
int value = f.max(3,5);
System.out.println("value=" + value);
}
}
@FunctionalInterface //함수형 인터페이스는 단 하나의 추상 메서드만 가져야 함.어노테이션 붙일 경우 검증
interface MyFunction2 {
//public abstract int max(int a, int b);
int max(int a, int b); //인터페이스의 모든 메소드는 public abstract 이기 때문에 생략 가능
}
즉 함수형 인터페이스는 람다식을 다루기 위해서 사용한다.
익명 객체를 람다식으로 대체
List<String> list = Arrays.asList("abc", "aaa", "bbb", "ddd", "aaa");
Collections.sort(list, new Comparator<String>() {
public int compare(String s1, String s2) {
return s2.compareTo(s1);
}
});
//리스트를 정렬할 때 Comparator로 정렬
sort 메소드는 list와 그것을 비교할 방법을 가진 Comparator 를 넘겨받아서 list의 sort 메서드를 한번더 호출하는데
실질적인 정렬은 sort 메소드에서 한번더 호출된 Arrays 의 sort 메서드에서 수행됨.
Comparator 의 경우 https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#method.summary 공식api 를 보면 함수형 인터페이스이므로 람다 표현식이나 메서드 참조의 할당 대상으로 사용 할 수 있다고 뜨고
Comparator <T> 이런식으로 제네릭 사용할수 있다.
c.compare(e1, e2) 를 통해 e1과 e2 객체를 비교할 수 있다.
Java.util의 Comparator.class에서 Comparator는 하나의 public abstract 메서드를 구현해야 하는 함수형 인터페이스로, 두 개의 객체를 넘겨받아 그것의 크기 비교를 수행하는 추상메서드인 compare를 구현하도록 강제하고 있다.
compare 메서드는 두 객체 중 만약 앞의 객체가 더 작다면 음수, 같다면 0, 크다면 양수를 반환해야 한다.
따라서 우리는 list를 정렬하기 위해 우리의 입맛에 맞는 Comparator 구현체를 만들고 Collections.sort를 호출하면 된다.
(*https://jaehee329.tistory.com/11 참고)
package plusJavaStudy;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class StudyLambda4 {
public static void main(String[] args) {
List<String> list = Arrays.asList("abc", "aaa", "bbb", "ddd", "aaa");
Collections.sort(list, (s1,s2) -> s2.compareTo(s1)); //Comparator 는 함수형 인터페이스
System.out.println(list);
}
}
/* Comparator 인터페이스는 이미 자바 표준 라이브러리에 포함되어 있으므로 새로 정의할 필요x 이렇게 정의되어 있음.
@FunctionalInterface //함수형 인터페이스는 단 하나의 추상 메서드만 가져야 함.어노테이션 붙일 경우 검증
interface Comparator<T> {
int compare(T o1, T o2);
}*/
위 코드를 람다식으로 작성한 것.
즉, 람다식에 이름을 붙여주고 호출한다고 생각하면 된다
(함수형 인터페이스를 사용함 = 이름을 붙여주기)
함수형 인터페이스 타입의 매개변수
@FunctionalInterface
interface MyFunction {
void myMethod();
}
void aMethod(MyFunction f) {
f.myMethod(); // MyFunction에 정의된 메소드 호출, 즉 람다식 호출
}
함수형 인터페이스 타입의 반환타입
MyFunction myMethod() {
MyFunction f = ()->{};
return f; //람다식 반환
}
//혹은
MyFunction myMethod() {
return ()->{}; //람다식 반환
}
한번에 정리하면
package plusJavaStudy;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
// Comparator 인터페이스는 이미 자바 표준 라이브러리에 포함되어 있으므로 새로 정의할 필요x 이렇게 정의되어 있음.
@FunctionalInterface //함수형 인터페이스는 단 하나의 추상 메서드만 가져야 함.어노테이션 붙일 경우 검증
interface MyFunction {
void run(); //public abstract 생략
}
class StudyLambda5 {
static void execute(MyFunction f) { // 매개변수의 타입이 MyFunction 인 메서드
f.run();
}
static MyFunction getMyFunction() { // 반환 타입이 MyFunction인 메서드
/*
MyFunction f = () -> System.out.println("f3.run()");
return f;
*/
return ()-> System.out.println("f3.run()");
}
public static void main(String[] args) {
//람다식으로 MyFunction의 run() 을 구현
MyFunction f1 = ()-> System.out.println("f1.run()"); //매개변수(입력) 없음, 반환타입 없음 -> void run(); 과 일치
MyFunction f2 = new MyFunction() { //익명클래스로 run() 을 구현
public void run() { //public을 반드시 붙여야함(안그러면 default 인데 override 된 것은 원 접근제한자보다 더 좁을수 없다)
System.out.println("f2.run()");
}
};
MyFunction f3 = getMyFunction(); //반환 타입이 MyFunction인 메서드
f1.run();
f2.run();
f3.run(); // f3.run() 하면 getMyFunction() 인데 그게 ()-> System.out.println("f3.run()") 이니까 이 해당 람다식 호출됨
execute(f1);
execute( ()-> System.out.println("run()"));
}
}
출력 결과는
f1.run()
f2.run()
f3.run()
f1.run()
run()
이다.
즉 람다식을 주고받는 방법이 이렇게 다양하게 있다고 알아두면 되겠다.
java.util.function 패키지(1/3)
https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
java.util.function (Java Platform SE 8 )
Interface Summary Interface Description BiConsumer Represents an operation that accepts two input arguments and returns no result. BiFunction Represents a function that accepts two arguments and produces a result. BinaryOperator Represents an operation u
docs.oracle.com
설명 번역 >
패키지 java.util.function 설명
함수형 인터페이스는 람다 표현식 및 메서드 참조의 대상 타입을 제공합니다. 각 함수형 인터페이스는 해당 함수형 인터페이스의 함수형 메서드라고 불리는 단일 추상 메서드를 가지고 있으며, 람다 표현식의 매개변수와 반환 타입은 이 메서드와 일치하거나 조정됩니다. 함수형 인터페이스는 할당 컨텍스트, 메서드 호출 컨텍스트 또는 캐스트 컨텍스트와 같은 여러 컨텍스트에서 대상 타입을 제공할 수 있습니다:
이 패키지의 인터페이스는 JDK에서 사용되는 범용 함수형 인터페이스로 사용자 코드에서도 사용할 수 있습니다. 이들은 람다 표현식이 적응될 수 있는 함수 형태의 완전한 집합을 나타내지는 않지만, 일반적인 요구 사항을 충족하기에 충분합니다. 특정 목적을 위해 제공되는 다른 함수형 인터페이스(예: FileFilter)는 사용되는 패키지에서 정의됩니다.
이 패키지의 인터페이스는 FunctionalInterface로 주석 처리되어 있습니다. 이 어노테이션은 컴파일러가 인터페이스를 함수형 인터페이스로 인식하는 데 필수적이지 않지만, 설계 의도를 명확히 하고 설계 의도에 위배되는 실수를 식별하는 데 컴파일러의 도움을 받을 수 있습니다.
함수형 인터페이스는 종종 함수, 동작 또는 조건과 같은 추상 개념을 나타냅니다. 함수형 인터페이스를 문서화하거나 함수형 인터페이스로 타입이 지정된 변수를 참조할 때, 예를 들어 "이 함수"라는 표현을 사용하여 그 추상 개념을 직접 언급하는 것이 일반적입니다. API 메서드가 "제공된 함수를 적용하여..."와 같은 방식으로 함수형 인터페이스를 수락하거나 반환한다고 할 때, 이는 명시적으로 null 가능성이 지정되지 않은 한, 적절한 함수형 인터페이스를 구현하는 객체에 대한 null이 아닌 참조를 의미하는 것으로 이해됩니다.
이 패키지의 함수형 인터페이스는 다음과 같은 확장 가능한 명명 규칙을 따릅니다:
- 여러 기본적인 함수 형태가 있으며, Function(T에서 R로의 단항 함수), Consumer(T에서 void로의 단항 함수), Predicate(T에서 boolean으로의 단항 함수), Supplier(매개변수 없는 R로의 함수) 등이 있습니다.
- 함수 형태는 일반적으로 가장 자주 사용되는 방식에 따라 자연스러운 인수를 가집니다. 기본 형태는 인수의 개수(prefix)를 추가하여 BiFunction(T와 U에서 R로의 이항 함수)와 같이 다른 인수를 나타낼 수 있습니다.
- 기본 함수 형태를 확장한 추가 함수 형태가 있으며, UnaryOperator(Function을 확장)와 BinaryOperator(BiFunction을 확장) 등이 있습니다.
- 함수형 인터페이스의 타입 매개변수는 추가 타입 접두사를 사용하여 원시 타입으로 특수화할 수 있습니다. 반환 타입이 제네릭 타입과 제네릭 인수를 모두 갖는 경우, ToXxx 접두사를 사용하여 반환 타입을 특수화합니다. 그렇지 않으면, DoubleConsumer나 ObjIntConsumer와 같이 타입 인수는 왼쪽에서 오른쪽 순서대로 특수화됩니다. (특수화를 원하지 않는 매개변수를 나타내기 위해 Obj 접두사가 사용되며, 다음 매개변수로 넘어가기를 의미합니다. 예: ObjIntConsumer.)
- 이러한 체계는 IntToDoubleFunction과 같이 결합될 수 있습니다.
- 모든 인수에 대한 특수화 접두사가 있을 경우, 인수 접두사는 생략될 수 있습니다. (예: ObjIntConsumer)
버전: 1.8
참조: FunctionalInterface
java.util.function 패키지의 경우 자주 사용되는 다양한 함수형 인터페이스를 제공한다

자바에서 제공하는 것을 가져와서 사용하면 이해하기 쉽고 표준화되어 편리하다
인터페이스에서 Supplier는 공급자/ Consumer는 소비자/Function 은 일반적인 함수/ Predicate 는 조건식(어떤 값을 받아서 true or False 반환) 이라고 생각하면 쉽다
//사용 예시, https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html 참고
Predicate<String> isEmptyStr = s -> s.length()==0; //문자열을 받아서 문자열 길이가 0인지 확인 0이면 참 아니면 거짓
String s = "";
if(isEmptyStr.test(s)) // 람다식 테스트, test 는 메서드 이름. 위 람다식을 호출하려면 test라는 메서드를 호출함. if(s.length()==0)
System.out.println("This is an empty String.");

1) Supplier<Integer> 인터페이스 사용
2) Consumer<Integer> 인터페이스 사용
3) Predicate<Integer> 인터페이스 사용 -> 원래는 Predicate<Integer,Boolean>인데 반환타입이 항상 Boolean 이어서 Boolean은 생략한다.
4) Function<Integer,Integer> 인터페이스 사용
매개변수가 2개인 함수형 인터페이스

매개변수가 2개 인터페이스는 Bi 가 붙는다
만약 매개변수가 1개, 2개보다 더 많은 인터페이스가 필요한다면 직접 만들면 된다
@FunctionalInterface
interface TriFunction<T,U,V,R> {
R apply(T t, U u, V v);
}
매개변수 타입 == 반환타입인 함수형 인터페이스

UnaryOperator<T> 는 단항 연산자, BinaryOperator<T> 는 이항 연산자
보통 Function<T,R> 의 경우 T를 넣으면 R을 반환하는데 UnaryOperator<T> 는 T를 넣으면 T가 나오기 때문에 타입 하나만 써주면 됨.
package plusJavaStudy;
import java.util.ArrayList;
import java.util.List;
import java.util.function.*;
class StudyLambda6 {
public static void main(String[] args) {
Supplier<Integer> s = ()-> (int)(Math.random()*100)+1; //1~100까지의 난수
Consumer<Integer> c = i -> System.out.print(i);
Predicate<Integer> p = i -> i%2 == 0; //짝수인지 검사
Function<Integer, Integer> f = i -> i/10*10; //i의 일의 자리를 없앤다 나누고 곱하기 25/10*10 = 2 * 10 = 20 25-> 20
List<Integer> list = new ArrayList<>();
makeRandomList(s, list); //list를 랜덤값으로 채운다
System.out.println(list);
printEvenNum(p, c, list); //짝수를 출력
List<Integer> newList = doSomething(f, list);
System.out.println(newList);
}
static <T> void makeRandomList(Supplier<T> s, List<T> list) {
for(int i=0; i<10; i++) {
list.add(s.get()); //Supplier 로부터 1~100 까지의 난수를 받아서 list 에 추가하는 코드
}
}
/*
Predicate<Integer> p = i -> i%2 == 0; //짝수인지 검사
Function<Integer, Integer> f = i -> i/10*10; //i의 일의 자리를 없앤다 나누고 곱하기 25/10*10 = 2 * 10 = 20 25-> 20
* */
static <T> void printEvenNum(Predicate<T> p, Consumer<T> c, List<T> list) {
System.out.print("[");
boolean firstElement = true; //첫번쨰 요소인지 확인
for(T i : list) {
if(p.test(i)) { //조건에 맞는지 검사
if(!firstElement) { //첫번째 요소가 아니면 앞에 쉼표추가
System.out.print(", ");
}
c.accept(i); //요소 출력 -> i -> System.out.print(i)
firstElement = false;
}
}
System.out.println("]");
}
//Function<Integer, Integer> f = i -> i/10*10; //i의 일의 자리를 없앤다 나누고 곱하기 25/10*10 = 2 * 10 = 20 25-> 20
static <T> List<T> doSomething(Function<T, T> f, List<T> list) {
List<T> newList = new ArrayList<T>(list.size());
for(T i : list) {
newList.add(f.apply(i)); // 일의 자리를 없애서 새로운 list에 저장
}
return newList;
}
}
함수형 인터페이스에 제네릭 사용하는 이유
https://codingsimsim.tistory.com/62 에서 작성한 제네릭을 같이 보면 되는데
제네릭을 사용하는 이유는 타입안전성, 코드 재사용 둘다 해결할수 있기 때문이다
제네릭클래스는 생성하는 시점에 <> 사이에 원하는 타입을 지정하기 때문에
타입이 맞지 않으면 컴파일 오류가 발생하므로 타입 안전성을 지켜줄 수 있고,
원하는 타입은 뭐든지 사용 가능하므로 코드의 재사용도 원활하다.(interger용, string 용 이렇게 안 만들어도 된다는 소리)
예를 들어, Predicate<T>는 T 타입의 객체에 대해 조건을 검사하는 함수형 인터페이스인데,
제네릭을 사용하면 String, Integer 등 다양한 타입에 대해 조건을 검사하는 동일한 기능을 수행하는 IntegerPredicate StringPredicate 등 무의미한 무한복제를 막을수가 있다는 것이다
결론은 제네릭을 사용하면
- 다양한 데이터 타입에 대해 동일한 인터페이스를 사용할 수 있게 하여 유연성을 제공
- 컴파일 타임에 타입 오류를 검출하여 타입 안정성 확보
- 코드 중복 줄임
등의 효과가 있다
제네릭은 정말 좋은거구나..
Predicate 의 결합
Predicate<T> 는 T 타입의 객체에 대해 조건을 검사하는 함수형 인터페이스 .. 그냥 조건식이다
두 Predicate 를 하나로 결합할수가 있는데 and(), or(), negate() <- not 임. ! 임. 로 가능하다
Predicate<T> 는 함수형 interface 기 때문에 default메서드, static 메서드, 추상 메서드를 가질 수 있다(인터페이스가 가질수 있는 메서드 3가지, jdk1.8부터)
결합 예시 (default메소드)
Predicate<Interger> p = i -> i < 100;
Predicate<Interger> q = i -> i < 200;
Predicate<Interger> r = i -> i%2 == 0;
일 때, 아래와 같이 쓸 수 있다
Predicate<Interger> notP = p.negate(); //! 의 의미로 사용, i >= 100
Predicate<Interger> all = notP.and(q).or(r); // 100 <= i && i < 200 || i%2 == 0
Predicate<Interger> all2 = notP.and(q.or(r)); // 100 <= i && ( i < 200 || i%2 == 0 )
//Predicate 를 쓸때는 test 추상 메서드 사용
System.out.println(all.test(2)); //true
System.out.println(all2.test(2)); //false
Predicate 등가비교는 isEqual()사용 (static메소드)
/*
Predicate<String> p = Predicate.isEqual(str1); isEquals() 는 static메소드
Boolean result = p.test(str2);// 비교한결과 반환
또는
*/
boolean result = Predicate.isEqual(str1).test(str2);
//이 코드는 str1.equals(str2) 와 같다고 보면 된다.
컬렉션 프레임워크와 함수형 인터페이스
함수형 인터페이스를 사용하는 컬렉션 프레임워크 메서드(와일드 카드 생략)

활용 예시 코드>
list.forEach(i->System.out.print(i+",")); //list의 모든 요소를 출력
list.removeIf(x-> x%2==0 || x%3==0); //2 또는 3의 배수를 제거
list.replaceAll(i->i*10); //모든 요소에 10을 곱함
//map의 모든 요소를 {k,v}의 형식으로 출력
map.forEach((k,v)->System.out.print("{"+k+","+v+"},"));
람다식을 이용하고 그에 관련된 메소드를 쓰면 코드가 훨씬 간단해진다는 장점이 있다.
iterator 가 헷갈리면 https://tlatmsrud.tistory.com/61#google_vignette 참조하면 좋을 것 같다.
package plusJavaStudy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class StudyLamnda7 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; i++)
list.add(i);
list.forEach(i->System.out.print(i+",")); //list의 모든 요소를 출력
System.out.println(list);
//원래는 Iterator 를 사용했다. 이렇게 작성하지 않고 forEach 를 사용할 수 있으니 람다식이 편리하다.
/*
Iterator it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
*/
list.removeIf(x-> x%2==0 || x%3==0); //2 또는 3의 배수를 제거
System.out.println(list);
list.replaceAll(i->i*10); // list의 각 요소에 10을 곱함
System.out.println(list);
Map<String, String> map = new HashMap<>();
map.put("1", "1");
map.put("2", "2");
map.put("3", "3");
map.put("4", "4");
map.forEach((k,v)->System.out.print("{"+k+","+v+"},"));//map의 모든 요소를 {k,v}의 형식으로 출력
/*forEach 대신 원래는 Iterator 사용
Iterator it = map.entrySet().iterator();
while(it.hasNext()) {
System.out.println(it.next());
}*/
}
}
메소드 참조(method reference)
하나의 메서드만 호출하는 람다식은 메서드 참조로 간단히 할 수 있다.

메소드 참조는 람다식을 더 간단히 한 것이다 클래스이름::메소드이름 으로 작성하면 된다
특정 객체 인스턴스메소드 참조는 거의 사용되지 않는다
package plusJavaStudy;
import java.util.function.Function;
public class StudyLamnda8 {
public static void main(String[] args) {
// Function<String, Integer> f = (String s) -> Integer.parseInt(s); 람다식, 문자열을 넣으면 parseInt 를 통해 integer 로 반환
//메서드 참조로 바꾸면 Function<String, Integer> f = Integer::parseInt;
Function<String, Integer> f = Integer::parseInt; //String 은 안넣어줘도 제네릭에 String으로 되어있기 때문에 가능
System.out.println(f.apply("100")+200);
}
}
생성자의 메서드 참조
package plusJavaStudy;
import java.util.function.Function;
import java.util.function.Supplier;
class StudyLamnda9 {
public static void main(String[] args) {
// Supplier 는 입력 X, 출력 O
//Supplier<MyClass> s = () -> new MyClass();
//Supplier<MyClass> s = MyClass::new;
//Function<Integer, MyClass> s = (i) -> new MyClass();
Function<Integer, MyClass> f = MyClass::new;
/*
MyClass mc = s.get();
System.out.println(mc);
System.out.println(s.get()); //또다른 객체가 만들어짐
*/
MyClass mc = f.apply(100);
System.out.println(mc.iv);
System.out.println(f.apply(200).iv);
Function<Integer, int[]> f2 = (i) -> new int[i]; //배열길이가 입력 필요하므로 Function
int[] arr = f2.apply(100);
System.out.println("배열의 길이:" + arr.length);
}
}
class MyClass {
int iv;
MyClass(int iv) {
this.iv = iv;
}
}
헷갈리면 함수를 그림으로 그려보고 입/출력이 어떻게 되는지 생각해보면서 하자
참고자료
자바의 정석,
https://www.youtube.com/watch?v=4ZtKiSvZNu4
https://inpa.tistory.com/entry/%E2%98%95-Lambda-Expression
'JAVA' 카테고리의 다른 글
| [Java] 옵셔널 Optional (0) | 2024.09.24 |
|---|---|
| [Java] 스트림 연산 - 중간 연산 (0) | 2024.09.22 |
| [Java] 스트림(Stream), 스트림의 특징, 스트림 만들기 (0) | 2024.09.22 |
| [JAVA] 제네릭 (1) (0) | 2024.09.15 |