인스턴스보다 기능 하나가 필요한 상황을 위한 람다
“기능 하나를 정의해서 전달해야 하는 상황”
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class SlenCamp implements Comparator{
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
}
public class Main1 {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add("TOY");
list.add("ROBOT");
list.add("BOX");
Collections.sort(list, new SlenCamp());
for (String s:
list) {
System.out.println(s);
}
}
}
Collections.sort 메소드 호출하면서 두 번째 인자로 정렬의 기준을 갖고 있는 인스턴스를 생성해서 전달. 인스턴스를 전달하는 형태, 내용을 보면 메소드, 즉 기능을 전달하는 것에 해당.
매개변수가 있고 반환하지 않는 람다식
interface Printable{
void print(String s);
}
public class Main2 {
public static void main(String[] args) {
Printable p;
p =(String s) -> {
System.out.println(s);
};
p.print("Lambda exp one");
p = (String s) ->
System.out.println(s);
p.print("Lambda exp two");
p = (s) -> System.out.println(s);
p.print("Lambda exp three");
p = s -> System.out.println(s);
p.print("Lambda exp four");
}
}
람다식은
매개변수 정보에 소괄호를 하고, 메소드 몸체에 중괄호를 한다. 만약 메소드 몸체가 하나의 문장으로 이뤄져있다면, 중괄호의 생략이 가능하다.
단 중괄호를 생략할 때 해당 문장의 끝에 위치한 세미콜론도 함께 지워야 한다. 리턴 문이라면, 중괄호의 생략은 불가능하다. 매개변수 정보에 있어서 s가 String 형 임은 컴파일러 입장에 유추가 가능하다.
물론 메소드 몸체가 둘 이상의 문장으로 이뤄졌거나, 매개변수의 수가 둘 이상인 경우, 각각 중괄호와 소괄호의 생략이 불가능하다. 매개변수가 둘이고 반환하지 않는 람다식
interface Calculator {
void cal(int a, int b);
}
public class Main3 {
public static void main(String[] args) {
Calculator c;
c = (a, b) ->
System.out.println(a + b);
c.cal(4, 3);
c = (a, b) -> System.out.println(a / b);
c.cal(4, 3);
c = (a, b) -> System.out.println(a - b);
c.cal(4, 3);
}
}
매개변수가 있고, 반환하는 람다식
interface Cal {
int cal(int a, int b); //반환하는 추상메소드
}
public class Main4 {
public static void main(String[] args) {
Cal c;
c = (a, b) -> {
return a + b;
};
System.out.println(c.cal(4, 3));
c = (a, b) -> {
return a - b;
};
System.out.println(c.cal(4,3));
}
}
메소드 몸체에 해당하는 내용이 return문이면, 문장이 하나라도, 중괄호 생략이 불가능 하다. 이경우 몸체에 연산이 등장하는데, 연상이 진행되면, 그 결과로 값이 남는다. return문이 메소드 몸체를 이루는 유일한 문장이라면 이렇게 바꿔 사용
interface HowLong {
int len(String s);
}
public class Main5 {
public static void main(String[] args) {
HowLong h1 = s -> s.length();
System.out.println(h1.len("Happy"));
}
}
호출하는 length는 값을 반환한다. 메소드의 호출 결과로 반환된 값이 남는다. Return 굳이 작성 안해도 ok
매개변수가 없는 람다식
매개변수를 표현하는 소괄호 안을 비우면 된다.
import java.util.Random;
interface Genrator{
int rand();
}
public class Main6 {
public static void main(String[] args) {
Genrator gen = () -> {
Random random = new Random();
return random.nextInt();
};
System.out.println(gen.rand());
}
}
interface Genrator{
int rand();
}
매개변수 없는 메소드
Genrator gen = () -> {
Random random = new Random();
return random.nextInt();
};
매개변수 선언이 없는 관계로 매개변수 정보를 담는 소괄호 비어 있다. 이럴 때는 둘 이상의 문장으로 이뤄진 다음 람다식은 중괄호로 반드시 감싸야 하며, 값을 반환 할때도 return문이 반드시 사용
함수형 인터페이스
“예제에 정의되어 있는 인터페이스에는 추상 메소드가 딱 하나 존재 “
이러한 인터페이스를 가리켜 함수형 인터페이스. 람다식은 이러한 함수형 인터페이스를 기반으로 적성 가능.
@FunctionalInterface
interface Calcul{
T cal(T a, T b);
}
@FunctionalInterface는 함수형 인터페이스에 부합하는지 확인 하기 위한 어노테이션 타입. 인터페이스에 둘 이상의 추상 메소드가 존재 시 함수형 인터페이스가 아니기 때문에 컴파일 오류로 나타난다. Static default 선언이 붙은 메소드의 정의는 함수형 인터페이스의 정의에 아무런 영향 X
람다식과 제네릭
인터페이스는 제네릭으로 정의하는 것 가능
@FunctionalInterface
interface Calcul{
T cal(T a, T b);
}
public class Main7 {
public static void main(String[] args) {
Calcul cal = (a,b) -> a + b;
System.out.println(cal.cal(3,4));
Calcul<Double> c = (a,b) -> a +b;
System.out.println(c.cal(4.32, 3.45));
}
}
@FunctionalInterface
interface Calcul{
T cal(T a, T b);
}
제네릭 기반의 함수형 인터페이스
<문제>
interface Calculat {
T cal(T a, T b);
}
public class Main8 {
public static void calAndShow(Calculat op, T n1, T n2) {
T r = op.cal(n1, n2);
System.out.println(r);
}
public static void main(String[] args) {
calAndShow((a, b) -> a + b, 3, 4);
calAndShow((a, b) -> a + b, 2.5, 7.1);
calAndShow((a,b) -> a - b, 4, 2);
calAndShow((a,b) -> a -b, 4.5, 3.2);
}
}
정의되어 있는 함수형 인터페이스
미리 정의 되어 있는 함수형 인터페이스
Collections 인터페이스에 정의 되어 있는 디폴트 메소드중 하나인 removelf 메소드.
Default boolean reomovelf(Predicate<? Super E> filter)
Predicate는 제네릭 인터페이스이자 함수형 인터페이스다.
Predicate
Boolean test(T t) //전달 인자를 대상으로 true, false
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Main9 {
public static int sum(Predicate p, List list) {
int s = 0;
for (int n :
list) {
if (p.test(n))
s += n;
}
return s;
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>(Arrays.asList(1, 5, 7, 9, 11, 12));
int s;
s = sum(n -> n % 2 ==0 , list);
System.out.println("짝수 합" + s);
s = sum(n -> n % 2 != 0, list);
System.out.println("홀수 합" + s);
}
}
<문제>
public class Main10 {
public static <T> void show(Predicate<T> p, List<T> list) {
int s = 0;
for (T n :
list) {
if (p.test(n)){
System.out.println(n);
}
}
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>(Arrays.asList(1, 3, 8, 10, 11));
show(n -> n % 2 != 0, list);
List<Double> list1 = new ArrayList<>(Arrays.asList(-1.0, -2.0, 3.5, -2.4, 9.5));
show(n -> n > 0.0, list1);
}
}
Predicate를 구체화하고, 다양화 한 인터페이스들
IntPredicate, LongPredicate, DoublePredicate
두개의 인자를 받아서 true 또는 false를 결정 할 수 있는 제네릭 인터페이스도 정의
BiPredicate<T, U>
IntPredicate 예시
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.IntPredicate;
public class Main11 {
public static int sum(IntPredicate ip, List list) {
int s = 0;
for (int n :
list) {
if (ip.test(n)) {
s += n;
}
}
return s;
}
public static void main(String[] args) {
List<Integer> lst = new ArrayList<>(Arrays.asList(1, 5, 7, 9, 11, 12));
int s;
s = sum(n -> n % 2 == 0, lst);
System.out.println(s);
s = sum(n -> n % 2 != 0, lst);
System.out.println(s);
}
}
<문제>
import java.util.function.BiPredicate;
public class Main12 {
public static void main(String[] args) {
BiPredicate<String, Integer> conv = (s, i) -> {
if (s.length() > i){
return true;
}
return false;
};
if (conv.test("Robot", 3))
System.out.println("3 초과");
else
System.out.println("3 미만");
if (conv.test("Toy", 5))
System.out.println("5초과");
else
System.out.println("5미만");
}
}
Supplier
T get(); -> 단순히 무언가 반환할 때
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
public class Main13 {
public static List makeIntList(Supplier s, int n) {
List list = new ArrayList<>();
for (int i = 0; i < n; i++) {
list.add(s.get());
}
return list;
}
public static void main(String[] args) {
Supplier<Integer> supplier = () -> {
Random random = new Random();
return random.nextInt(50);
};
List<Integer> list =makeIntList(supplier, 5);
System.out.println(list);
list = makeIntList(supplier, 10);
System.out.println(list);
}
}
list.add(s.get());
난수를 생성
public static List makeIntList(Supplier s, int n) {
첫 인자를 통해서 컬랙션 인스턴스에 담을 정수의 생성 방법을 결정 할 수 있다.
Supplier를 구체화 한 인터페이스들
IntSupplier, LongSupplier, DoubleSupplier, BooleanSupplier
public class Main14 {
public static List makeIntList(IntSupplier is, int n){
List list = new ArrayList<>();
for (int i = 0; i < n; i++) {
list.get(is.getAsInt());
}
return list;
}
public static void main(String[] args) {
IntSupplier supplier = () -> {
Random random = new Random();
return random.nextInt(50);
};
List<Integer> list = makeIntList(supplier, 5);
System.out.println(list);
List<Integer> list1 = makeIntList(supplier, 10);
System.out.println(list1);
}
}
Consumer
전달인자를 소비하는 형태로 매개변수와 반환형 선언. (인자는 절달받지만, 반환은 하지 않는다.)
Void accept(T t) //전달인자 기반으로 “반환” 이외의 다른 결과를 보일 때
import java.util.function.Consumer;
public class Main15 {
public static void main(String[] args) {
Consumer c = s -> System.out.println(s);
c.accept("pineapple");
c.accept("strawberry");
}
}
Consumer를 구체화하고 다양화 한 인터페이스들
IntConsumer, ObjIntConsumer, LongConsumer, ObjLongConsumer, DoubleConsumer, ObjDoubleConsumer, BiConsumer<T, U>
Void accept
import java.util.function.ObjIntConsumer;
public class Main16 {
public static void main(String[] args) {
ObjIntConsumer c = (a, b) -> System.out.println(a + b);
int n =1;
c.accept("Toy", n++);
c.accept("Book", n++);
c.accept("Candy", n);
}
}
인터페이스 ObjIntConsumer의 추상메소드는 Consumer의 추상메소드 보다 int형 인자를 하나 더 받는다.
<문제>
import java.util.function.BiConsumer;
class Book{
private T ob;
public void set(T o){
ob = o;
}
public T get(){
return ob;
}
}
public class Main17 {
public static void main(String[] args) {
BiConsumer<Book, Integer> c = (a, b) -> a.set(b);
BiConsumer<Book, Double> c1 = (a, b) -> a.set(b);
Book<Integer> bi = new Book<>();
Book<Double> bi1 = new Book<>();
c.accept(bi, 50);
c1.accept(bi1, 50.01);
System.out.println(bi.get());
System.out.println(bi1.get());
}
}
Function<T, R>
R apply (T t) // 전달 인자와 반환 값이 모두 존재
public static void main(String[] args) {
Function<Double, Double> c = d -> d 0.393701;
Function<Double, Double> c1 = d -> d 2.54;
System.out.println(c.apply(1.0));
System.out.println(c1.apply(1.0));
}
}
import java.util.function.Function;
public class Main19 {
public static void main(String[] args) {
Function<String, Integer> f = s -> s.length();
System.out.println(f.apply("Toy"));
System.out.println(f.apply("System"));
}
}
Function을 구체화, 다양화 한 인터페이스
IntToDoubleFunction -> double applyAsDouble(int value)
DoubleToIntFunction -> int applyAsInt(double value)
Int형 값을 인자로 받아서 long 값으로 반환해야 한다면, IntToLongFunction 사용
import java.util.function.ToIntBiFunction;
import java.util.function.ToIntFunction;
public class Main20 {
public static void main(String[] args) {
ToIntFunction f = s -> s.length();
System.out.println(f.applyAsInt("Root"));
System.out.println(f.applyAsInt("System"));
}
}
DoubleUnaryOperator
import java.util.function.DoubleUnaryOperator;
public class Main21 {
public static void main(String[] args) {
DoubleUnaryOperator c = d -> d 0.351478;
DoubleUnaryOperator c1 = d -> d 2.54;
System.out.println(c.applyAsDouble(1.0));
System.out.println(c1.applyAsDouble(1.0));
}
}
UnaryOperator는 function<T, R>을 그리고 BinayOperator은 BiFunction<T,U,R>을 상속하여 정의한 인터페이스다.
Removelf 메소드를 활용
Default Boolean removelf(Predicate<? Super E> filter)
매개변수 선언에 <? Super E> 가 존재하므로, 람다식을 작성해서, 메소드의 인자로 전달 할 수 있다. 컬랙션 인스턴스에 저장된 인스턴스를 teat 메소드의 인자로 전달시 true가 반환되는 인스턴스는 모두 삭제
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Main22 {
public static void main(String[] args) {
List list = new ArrayList<>(Arrays.asList(1, -2, 3, -4, 5));
list = new ArrayList<>(list);
List<Double> list1 = Arrays.asList(1.0, 2.0, 3.0, 4.5);
list1 = new ArrayList<>(list1);
Predicate<Number> p = n -> n.doubleValue() < 0.0;
list1.removeIf(p);
list.removeIf(p);
System.out.println(list);
System.out.println(list1);
}
}
List 인스턴스의 removelf 메소드에 인자로 전달을 이용