⚠️Warning
본 포스트는 당일 학원에서 배운 내용을 복습하는 목적의 공부 기록 시리즈입니다. 정보 전달의 목적이 아님을 유의해주세요! 잘못된 내용에 대한 피드백을 환영합니다:)
: 메소드를 하나의 식(expression)으로 표현한 것. 메소드를 람다식으로 표현하면 메소드의 이름과 반환값이 없어지므로, 람다식을 '익명 함수(anonymous function)'이라고도 한다.
인터페이스 변수 = 람다식; MyInterface m1 = () -> {};
(매개변수) -> {실행코드}(매개변수) : 메소드의 매개변수 리스트와 동일-> : 화살표(Arrow), 코드 블럭 호출 역할{실행코드} : 메소드의 구현부와 동일MyInterface m2 = new MyInterface() {
@Override
public void test() {
System.out.println("익명 클래스에서 구현한 메소드");
}
};
m2.test(); //익명 클래스에서 구현한 메소드```java
MyInterface m3 = () -> {
System.out.println("람다식에서 구현한 메소드");
};
m3.test(); //람다식에서 구현한 메소드
//람다식 왼쪽에 인터페이스가 빠지면 추상메소드를 알 수가 없기 때문에 람다식 왼쪽에 인터페이스가 들어와야 함! > 자바 람다식의 한계! > 람다식 만으로는 에러가 남.
```NoParameterNoReturn pr1 = new NoParameterNoReturn() {
@Override
public void call() {
System.out.println("pr1");
}
};
pr1.call(); //pr1NoParameterNoReturn pr2 = () -> {
System.out.println("pr2");
};
pr2.call(); //pr2{} 생략 가능NoParameterNoReturn pr3 = () -> System.out.println("pr3");
pr3.call(); //pr3
System.out.println();
ParameterNoReturn pr4 = (int num) -> {
System.out.println(num);
};
pr4.call(100); //100
System.out.println();ParameterNoReturn pr5 = (num) -> System.out.println(num);
pr5.call(500); //500()를 생략할 수 있다.```java
ParameterNoReturn pr6 = num -> System.out.println(num);
pr6.call(5000); //5000
System.out.println();
MultiParameterNoReturn pr7 = (String name, int age) -> {
System.out.println(name + "," + age);
};
pr7.call("홍길동", 20); //홍길동, 20
System.out.println();
MultiParameterNoReturn pr8 = (name, age) -> System.out.println(name + "," + age);
pr8.call("아무개", 25); //아무개, 25
System.out.println();
NoParameterReturn pr9 = () -> {
return 100;
};
System.out.println(pr9.call()); //100
System.out.println();
```return마저도 생략해야 한다.(구현부 중괄호{} 없애고 싶으면 return까지 같이 생략)NoParameterReturn pr10 = () -> 300;
System.out.println(pr10.call()); //300
System.out.println();
ParameterReturn pr11 = name -> name.length();
System.out.println(pr11.call("홍길동")); //3
System.out.println(pr11.call("남궁길동")); //4
System.out.println();//람다식 활용 == 익명클래스(객체) 활용
//Math.random() //0~1 실수 난수
Random rnd = new Random();
//int valuebetween 0 (inclusive) and the specified value (exclusive)
//System.out.println(rnd.nextInt(10)); //0~9
ArrayList<Integer> nums = new ArrayList<Integer>();
for (int i=0; i<10; i++) {
nums.add(rnd.nextInt(10) + 1); //1~10
}
System.out.println(nums); //[8, 2, 4, 6, 3, 3, 3, 9, 4, 9]
//익명클래스 활용하여 정렬
nums.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2; //오름차순
}
});
System.out.println(nums); //[2, 3, 3, 3, 4, 4, 6, 8, 9, 9]
//람다식 활용하여 정렬
nums.sort((Integer o1, Integer o2) -> {
return o1 - o2;
});
//더줄여
nums.sort((o1, o2) -> o2 - o1); //내림차순
System.out.println(nums); //[9, 9, 8, 6, 4, 4, 3, 3, 3, 2]
//1. 파일 읽기
String path = "C:\\Users\\skfoc\\Downloads\\파일_입출력_문제\\성적.dat";
try {
BufferedReader reader = new BufferedReader(new FileReader(path));
ArrayList<Student2> list = new ArrayList<Student2>();
String line = null;
while ((line = reader.readLine()) != null) {
//텍스트 1줄 > Student2 객체 1개
//홍길동,47,61,73
String[] temp = line.split(",");
Student2 s = new Student2(
temp[0],
Integer.parseInt(temp[1]),
Integer.parseInt(temp[2]),
Integer.parseInt(temp[3])
);
list.add(s);
}
System.out.println(list);
//성적순 > 정렬
// list.sort(new Comparator<Student2>() {
//
// @Override
// public int compare(Student2 o1, Student2 o2) {
// return o2.getTotal() - o1.getTotal();
// }
// });
//람다식으로 정렬
list.sort((o1, o2) -> o2.getTotal() - o1.getTotal());
for (Student2 s : list) {
System.out.println(s.getName() + ":" + s.getTotal());
}
reader.close();
} catch (Exception e) {
System.out.println("at Ex72_Lambda.m2");
e.printStackTrace();
}
: 익명 객체의 (구현된) 추상 메소드 → 인터페이스 변수에 저장 → 람다식은 반드시 인터페이스가 필요하다!!!
'The target type of this expression must be a functional interface.'
람다식을 저장하는 목적의 인터페이스 vs 일반적인 인터페이스
→ 차이가 없다.
단, 람다식을 저장하는 인터페이스는 반드시 메서드를 1개만 가질 수 있다.
→ 이게 바로 '함수형 인터페이스'@FunctionalInterface interface Test { void aaa(); //void bbb(); }
표준 API 함수형 인터페이스
1. Consumer → 매개변수O, 반환값X
- Consumer
- BiConsumer
- IntConsumer
- ..
2. Supplier → 매개변수X, 반환값O
- Supplier
- ..
3. Function → 매개변수O, 반환값O
- Function<T,R>
- BiFunction<T,U,R>
- ..
4. Operator → 매개변수O, 반환값O
- BinaryOperator
- Function 하위셋
5. Predicate → 매개변수O, 반환값O
- Predicate
- Function 하위셋
- ..
acceptXXX() 추상 메소드 제공사용자 정의형 인터페이스 사용해보기
My Consumer m1 = num -> System.out.println(num * num);
m1.test(10);
@FunctionalInterface
interface MyConsumer {
void test(int num);
}
표준 API 사용해보기
```java
//Integer
Consumer<Integer> c1 = num -> System.out.println(num * num);
c1.accept(5); //25
//String
Consumer<String> c2 = str -> System.out.println(str.length());
c2.accept("람다식"); //13
c2.accept("람다식입니다. 그렇습니다."); //14
//Integer
Consumer<Integer> c3 = count -> {
for (int i=0; i<count; i++) {
System.out.println(i);
}
System.out.println();
};
c3.accept(5); //0 1 2 3 4
//Student
Consumer<Student> c4 = s -> {
System.out.println("이름: " + s.getName());
System.out.println("국어: " + s.getKor());
System.out.println("영어: " + s.getEng());
System.out.println("수학: " + s.getMath());
System.out.println("총점: " + s.getTotal());
};
c4.accept(new Student("홍길동", 100, 90, 80));
//이름: 홍길동
//국어: 100
//영어: 90
//수학: 80
//총점: 270
//BiConsumer
BiConsumer<String, Integer> bc1 = (name, age) -> {
System.out.printf("이름: %s, 나이: %d세\n", name, age);
};
bc1.accept("홍길동", 20); //이름: 홍길동, 나이: 20세
//IntConsumer
IntConsumer ic1 = num -> System.out.println(num * num);
ic1.accept(10); //100
```
getXXX() 추상 메소드 제공Supplier<Integer> s1 = () -> 100;
System.out.println(s1.get()); //100
Supplier<Double> s2 = () -> Math.random();
System.out.println(s2.get()); //0.8898797069506995
Supplier<String> s3 = () -> "홍길동";
System.out.println(s3.get()); //홍길동
Supplier<Student> s4 = () -> new Student("홍길동", 100, 90, 80);
System.out.println(s4.get()); //Student [name=홍길동, kor=100, eng=90, math=80]
IntSupplier s5 = () -> 200;
System.out.println(s5.getAsInt()); //200
applyXXX() 추상 메소드 제공Function<T, R><T>: the type of the input to the function<R>: the type of the result of the functionBiFunction<T, U, R><T>: the type of the first argument to the function<U>: the type of the second argument to the function<R>: the type of the result of the functionFunction<Integer, Boolean> f1 = num -> num > 0;
System.out.println(f1.apply(10)); //true
System.out.println(f1.apply(-10)); //false
Function<String,Integer> f2 = str -> str.length();
System.out.println(f2.apply("펑션이오")); //4
System.out.println(f2.apply("안녕하세요")); //5
Function<Student,Boolean> f3 = s -> {
return s.getTotal() >= 180? true : false;
};
if (f3.apply(new Student("홍길동", 80, 75, 90))) {
System.out.println("합격");
} else {
System.out.println("불합격");
} //합격
BiFunction<Integer, Integer, Integer> bf1 = (a,b) -> a + b;
System.out.println(bf1.apply(10, 20)); //30
DoubleToIntFunction f4 = num -> (int)num;
System.out.println(f4.applyAsInt(3.14)); //3
applyXXX() 추상 메소드 제공BinaryOperator<Integer> bo1 = (a, b) -> a + b;
System.out.println(bo1.apply(10, 20)); //30
BiFunction<Integer, Integer, Integer> bf1 = (a, b) -> a + b;
System.out.println(bf1.apply(10, 20)); //30
//Function<T,T>
UnaryOperator<Integer> uo1 = num -> num * num;
System.out.println(uo1.apply(10)); //100
Function<Integer, Boolean> f1 = num -> num > 0;
Predicate<Integer> p1 = num -> num > 0;
//Function 사용
System.out.println(f1.apply(10)); //true
System.out.println(f1.apply(-10)); //false
//Predicate 사용
System.out.println(p1.test(10)); //true
System.out.println(p1.test(-10)); //false
BiPredicate<Integer, Integer> bp2 = (a, b) -> a > b;
System.out.println(bp2.test(10, 20)); //false
System.out.println(bp2.test(20, 10)); //true
: 람다 객체들의 연산자 역할
andThen 으로 이어 사용하기c1 > 총점Student s1 = new Student("홍길동", 100, 90, 80);
Consumer<Student> c1 = s -> System.out.println("총점: " + s.getTotal());
c1.accept(s1); //총점: 270c2 > 이름Consumer<Student> c2 = s -> System.out.println("이름: " + s.getName());
c2.accept(s1); //이름: 홍길동andThen 사용하기 → 업무 1 + 2```java
Consumer<Student> c3 = c1.andThen(c2);
c3.accept(s1);
//andThen은 이어서 사용 가능하다
Consumer<Student> c4 = s -> System.out.println("평균: " + s.getTotal()/ 3.0);
c4.accept(s1);
Consumer<Student> c3 = c1.andThen(c2).andThen(c4);
c3.accept(s1);
```andThen 으로 이어 사용하기업무 1
Function<Integer, Boolean> f1 = num -> num > 0;
System.out.println(f1.apply(10)); //true
업무 2
Function<Boolean, String> f2 = flag -> flag ? "성공" : "실패";
System.out.println(f2.apply(true)); //성공
andThen 사용하기 → 업무 1 + 2 (A.andThen(B)) → A먼저 처리 후 결과를 B의 매개값으로 제공
Function<Integer, String> f3 = f1.andThen(f2);
System.out.println(f3.apply(-10)); //실패
compose() 사용하기(andThen의 반대 순서) A.compose(B) → B먼저 처리 후 결과를 A의 매개값으로 제공
```java
Function<Integer, String> f4 = num -> num > 0 ? "참" : "거짓";
Function<String, Integer> f5 = str -> str.length();
Function<Integer, Integer> f7 = f5.compose(f4); //f5 + f4
System.out.println(f7.apply(-10)); //2
```
and
//2의 배수
Predicate<Integer> p1 = num -> num % 2 == 0;
//3의 배수
Predicate<Integer> p2 = num -> num % 3 == 0;
int a = 10;
System.out.println(p1.test(a)); //true
System.out.println(p2.test(a)); //false
//a가 2와 3의 공배수?
System.out.println(p1.test(a) && p2.test(a)); //false
//p1 && p2
Predicate<Integer> p3 = p1.and(p2);
System.out.println(p3.test(a)); //false
or
//p1 || p2
//case 1)
System.out.println(p1.test(a) || p2.test(a));
//case 2)
Predicate<Integer> p4 = p1.or(p2);
System.out.println(p4.test(a));
System.out.println(!p1.test(a));
Predicate<Integer> p5 = p1.negate();
System.out.println(p5.test(a));
💡 함수형 인터페이스
(매개변수) → {구현부}() → {return 값}(매개변수) → {return 값}(매개변수) → {return 값}(매개변수) → {return 값}