[LG CNS AM CAMP 1기] 백엔드 I 5 | Java

letthem·2일 전
0

LG CNS AM CAMP 1기

목록 보기
15/16
post-thumbnail

람다식 ⭐️⭐️⭐️

활용 ⬇️

익명 이너 클래스 내부 구현 메서드의 약식 표현

package com.test;

import java.util.*;

// 매개변수 X, 반환값 X
@FunctionalInterface
interface XX {
    void method(); // public abstract void method();
}

public class MyTest {
    public static void main(String[] args) {
        // 구현 클래스를 정의하고, 해당 클래스의 인스턴스를 이용해서 메서드를 호출
        class XXClass implements XX {
            @Override
            public void method() {
                System.out.println("XX1");
            }
        }
        XX xx1 = new XXClass();
        XX xx11 = new XXClass();
        XX xx111 = new XXClass();
        XX xx1111 = new XXClass();
        xx1.method();

        // 익명 이너 클래스를 정의해서 메서드를 호출
        XX xx2 = new XX() {
            @Override
            public void method() {
                System.out.println("XX2");
            }
        };
        xx2.method();

        // 람다 표현식
        XX xx3 = () -> {
            System.out.println("XX3");
        };
        xx3.method();
    }
}

실습

매개변수와 반환값 유뮤에 따라 람다식 사용해보기 !

// 매개변수 X, 반환값 X
@FunctionalInterface
interface XX {
    void method();  // public abstract void method();
}

// 매개변수 X, 반환값 O
@FunctionalInterface
interface XO {
    int method();   // 숫자 100을 반환
}

// 매개변수 O, 반환값 X
@FunctionalInterface
interface OX {
    void method(int i); // 매개변수에 10을 더한 수를 출력
}

// 매개변수 O, 반환값 O
@FunctionalInterface
interface OO {
    double method(int i, double d); // 매개변수 값들을 더한 결과를 반환
}


public class MyTest {
    static void caseXx() {
        class XXClass implements XX {
            @Override
            public void method() {
                System.out.println("XX1");
            }
        }
        XX xx1 = new XXClass();
        xx1.method();

        XX xx2 = new XX() {
            @Override
            public void method() {
                System.out.println("XX2");
            }
        };
        xx2.method();

        XX xx3 = () -> System.out.println("XX3");
        xx3.method();
    }

    static void caseXo() {
        class XOClass implements XO {
            @Override
            public int method() {
                return 100;
            }
        }
        XO xo1 = new XOClass();
        System.out.println(xo1.method());

        XO xo2 = new XO() {
            @Override
            public int method() {
                return 100;
            }
        };
        System.out.println(xo2.method());

        XO xo3 = () -> 100;
        System.out.println(xo3.method());
    }

    static void caseOx() {
        OX ox1 = i -> System.out.println(i + 10);
        ox1.method(100);    // 110

        OX ox2 = new OX() {
            @Override
            public void method(int i) {
                System.out.println(i + 10);
            }
        };
        ox2.method(100);

        class OXClass implements OX {
            @Override
            public void method(int i) {
                System.out.println(i + 10);
            }
        }
        OX ox3 = new OXClass();
        ox3.method(100);
    }

    public static void caseOO() {
        OO oo1 = (int i, double d) -> i + d;
        System.out.println(oo1.method(100, 10.0)); // 110.0

        OO oo2 = new OO() {
            @Override
            public double method(int i, double d) {
                return i + d;
            }
        };
        System.out.println(oo2.method(100, 10.0));

        class OOClass implements OO {
            @Override
            public double method(int i, double d) {
                return i + d;
            }
        }
        OO oo3 = new OOClass();
        System.out.println(oo3.method(100, 10.0));
    }

    public static void main(String[] args) {
        caseXx();
        caseXo();
        caseOx();
        caseOO();
    }
}

이미 구현되어 있는 인스턴스 메서드를 참조 => 객체참조변수::인스턴스메서드명

인스턴스 메서드를 사용할 때는 반드시 객체를 먼저 생성해야 한다 !!

interface I {
    void iii(); // C 클래스의 ccc() 메서드를 호출
}

class C {
    void ccc() {
        System.out.println("ccc()");
    }
}

public class MyTest {
    public static void main(String[] args) {
        // 익명 이너클래스
        I i1 = new I() {
            @Override
            public void iii() {
                C c = new C();
                c.ccc();
            }
        };
        i1.iii();

        // 람다식
        I i2 = () -> {
            C c = new C();
            c.ccc();
        };
        i2.iii();
        
        // 메서드 참조로 변경
        C cc = new C(); // C 객체 만들기
        I i3 = cc::ccc; // I로 C 클래스의 ccc() 메서드를 호출
        i3.iii();
    }
}

전체

  • 구현 클래스 정의 후 인스턴스를 생성해서 실행
  • 익명 이너 클래스를 이용해서 실행
  • 람다식을 이용해서 실행
  • 메서드 참조를 이용해서 실행

예시 1

package com.test;

interface I {
    // 매개변수로 전달된 i 값을 출력
    void printNumber(int i);
}

public class MyTest {
    public static void main(String[] args) {
        // 구현 클래스 정의 후 인스턴스를 생성해서 실행
        class II implements I {
            @Override
            public void printNumber(int i) {
                System.out.println(i);
            }
        }
        I i1 = new II();
        i1.printNumber(100);

        // 익명 이너 클래스를 이용해서 실행
        I i2 = new I() {
            @Override
            public void printNumber(int i) {
                System.out.println(i);
            }
        };
        i2.printNumber(100);

        // 람다식을 이용해서 실행
        I i3 = i -> System.out.println(i);
        i3.printNumber(100);

        // 메서드 참조를 이용해서 실행 (람다식의 한 종류)
        I i4 = System.out::println;
        i4.printNumber(100);
    }
}

예시 2: 정적 메서드 참조

클래스 이름::정적메서드이름

정적 메서드라서 객체를 생성하면 안 된다.

package com.test;

interface I {
    // 클래스 C의 smile() 메서드를 호출
    void printSmile();
}

class C {
    static void smile() {
        System.out.println("^_^");
    }
}

public class MyTest {
    public static void main(String[] args) {
        class IClass implements I {
            @Override
            public void printSmile() {
                C.smile();
            }
        }
        I i1 = new IClass();
        i1.printSmile();

        I i2 = new I() {
            @Override
            public void printSmile() {
                C.smile();
            }
        };
        i2.printSmile();

        I i3 = () -> C.smile();
        i3.printSmile();

        I i4 = C::smile;
        i4.printSmile();

    }
}

예시 3 - 첫번째 매개변수로 전달된 객체의 인스턴스 메서드 참조

package com.test;

@FunctionalInterface
interface I {
    // 클래스 C의 print() 메서드를 이용해서 매개변수 i의 출력
    void printNumber(C c, int i);
}

class C {
    void print(int i) {
        System.out.println(i);
    }
}

public class MyTest {
    public static void main(String[] args) {
        class IClass implements I {
            @Override
            public void printNumber(C c, int i) {
                c.print(i);
            }
        }
        I i1 = new IClass();
        i1.printNumber(new C(), 100);

        I i2 = new I() {
            @Override
            public void printNumber(C c, int i) {
                c.print(i);
            }
        };
        i2.printNumber(new C(), 100);

        I i3 = (C c, int i) -> c.print(i);
        i3.printNumber(new C(), 100);

        I i4 = C::print;
        i4.printNumber(new C(), 100);
    }
}

예시 4 - 첫번째 매개변수로 전달된 객체의 인스턴스 메서드 참조

@FunctionalInterface
interface I {
    // 매개변수로 전달된 s의 길이를 반환
    int stringLength(String s);
}

public class Lambda {
    public static void main(String[] args) {
        I i4 = String::length;
        System.out.println(i4.stringLength("hello, lambda"));   // 13
        
        I i3 = s -> s.length();
        System.out.println(i3.stringLength("hello, lambda"));
        
        I i2 = new I() {
            @Override
            public int stringLength(String s) {
                return s.length();
            }
        };
        System.out.println(i2.stringLength("hello, lambda"));
        
        class IClass implements I {
            @Override
            public int stringLength(String s) {
                return s.length();
            }
        }
        I i1 = new IClass();
        System.out.println(i1.stringLength("hello, lambda"));
    }
}

예시 5 - 배열 생성자 참조

배열타입[]::new

package com.test;

import java.util.Arrays;

@FunctionalInterface
interface Arr {
    // 매개변수로 전달된 len 크기의 int[]를 반환
    int[] createArray(int len);
}

public class MyTest {
    public static void main(String[] args) {
        class ArrClass implements Arr {
            @Override
            public int[] createArray(int len) {
                return new int[len];
            }
        }
        Arr arr1 = new ArrClass();
        System.out.println(Arrays.toString(arr1.createArray(3)));   // [0, 0, 0]

        Arr arr2 = new Arr() {
            @Override
            public int[] createArray(int len) {
                return new int[len];
            }
        };
        System.out.println(Arrays.toString(arr2.createArray(3)));

        Arr arr3 = len -> new int[len];
        System.out.println(Arrays.toString(arr3.createArray(3)));

        Arr arr4 = int[]::new;
        System.out.println(Arrays.toString(arr4.createArray(3)));
    }
}

예시 6 - 클래스 생성 참조

클래스명::new

이때까지는 함수 내부에서 객체를 생성한 게 없었는데
이 예시는 메서드 내부에서 객체를 생성하는 메서드를 구현하는 예시다.
객체를 반환해야 하니까 new로 객체를 생성해서 반환해준다.

package com.test;

import java.util.Arrays;
@FunctionalInterface
interface RefDefaultConstructor {
    // Cls 클래스의 Cls() 생성자를 이용해서 인스턴스를 생성해서 반환
    Cls getInstance();
}

@FunctionalInterface
interface RefParamConstructor {
    // Cls 클래스의 Cls(int i) 생성자를 이용해서 인스턴스를 생성해서 반환
    Cls getInstance(int i);
}

class Cls {
    Cls() {
        System.out.println("첫번째 생성자");
    }
    Cls(int i) {
        System.out.println("두번째 생성자");
    }
}

public class MyTest {
    public static void main(String[] args) {
        RefDefaultConstructor r1 = new RefDefaultConstructor() {
            @Override
            public Cls getInstance() {
                return new Cls();
            }
        };
        r1.getInstance();       // 첫번째 생성자

        RefDefaultConstructor r2 = () -> new Cls();
        r2.getInstance();

        RefDefaultConstructor r3 = Cls::new;
        r3.getInstance();


        RefParamConstructor p1 = new RefParamConstructor() {
            @Override
            public Cls getInstance(int i) {
                return new Cls(i);
            }
        };
        p1.getInstance(100);    // 두번째 생성자

        RefParamConstructor p2 = i -> new Cls(i);
        p2.getInstance(100);

        RefParamConstructor p3 = Cls::new;
        p3.getInstance(100);
    }
}

연습

Q1

다음은 함수형 인터페이스 A의 객체를 익명 이너 클래스 방법으로 생성한 후 메서드를 호출한 코드다. 이를 람다식 코드로 변경하시오. (단, 람다식의 약식 표현은 사용하지 말 것)

A a = new A() {
    public void abc(double k) {
        System.out.println(k + 0.5);
    }
};        
a.abc(3.8);

A

A a = (double k) -> {
        System.out.println(k + 0.5);
    };
a.abc(3.8);

실행 가능한 형태로 만들어 보기 ⬇️

package com.test;

@FunctionalInterface
interface A {
    void abc(double k);
}

public class MyTest {
    public static void main(String[] args) {
        A a = new A() {
            public void abc(double k) {
                System.out.println(k + 0.5);
            }
        };
        a.abc(3.8);
        
        A a1 = (double k) -> {
            System.out.println(k + 0.5);
        };
        a1.abc(3.8);
        
        A a2 = k -> System.out.println(k + 0.5);
        a2.abc(3.8);
    }
}

Q2

다음과 같이 함수형 인터페이스 A가 정의돼 있다.

interface A {
    int abd(String str);
}

이때 다음의 람다식을 이용한 객체 생성 코드를 익명 이너 클래스를 이용한 객체 생성 코드로 바꿔 작성하시오.

A a = str -> str.length();

A

A a = new A() {
	@Override
    public int abd(String str) {
    	return str.length();
    }
};

실행 가능한 형태로 만들어 보기 ⬇️

package com.test;

interface A {
    int abd(String str);
}

public class MyTest {
    public static void main(String[] args) {
        A a = str -> str.length();
        System.out.println(a.abd("Hello, Lambda")); // 13

        A a2 = new A() {
            @Override
            public int abd(String str) {
                return str.length();
            }
        };
        System.out.println(a2.abd("Hello, Lambda"));

        A a3 = String::length;
        System.out.println(a3.abd("Hello, Lambda"));
    }
}

Q3

다음과 같이 인터페이스 A와 클래스 B가 정의돼 있다.

interface A {
    double abc(int k);
}

class B {
    double bcd(int k) {
        return k * 0.1;
    }
}

이때 익명 이너 클래스 방법을 사용해 인터페이스 A 객체를 생성한 코드는 다음과 같다.

A a1 = new A() {
    @Override
    public double abc(int k) {
        B b = new B();
        return b.bcd(k);
    }
};

위의 코드를 인스턴스 메서드를 참조하는 람다식 문법을 사용해 변경하시오.

A

B b = new B();
A a = b::bcd;

실행 가능한 형태로 만들어 보기 ⬇️

interface A {
    double abc(int k);
}

class B {
    double bcd(int k) {
        return k * 0.1;
    }
}

public class MyTest {
    public static void main(String[] args) {
        A a1 = new A() {
            @Override
            public double abc(int k) {
                B b = new B();
                return b.bcd(k);
            }
        };
        System.out.println(a1.abc(100));    // 10.0

        A a2 = k -> {
            B b = new B();
            return b.bcd(k);
        };
        System.out.println(a2.abc(100));
     
        B b = new B();
        A a3 = b::bcd;
        System.out.println(a3.abc(100));
        
        A a4 = new B()::bcd;
        System.out.println(a4.abc(100));
    }
}

Q4

다음은 abc() 추상 메서드를 갖고 있는 함수형 인터페이스 A 객체를 익명 이너 클래스 방법으로 생성한 코드다. 구현 메서드의 내부에서는 문자열을 정수로 변환하는 Integer 클래스의 정적 메서드인 parseInt() 메서드로 매개변수를 그대로 넘겨 호출했다. 이때 다음 코드를 정적 메서드를 참조하는 람다식 문법을 사용해 변경하시오.

A a1 = new A() {
    @Override
    public int abc(String str) {
        return Integer.parseInt(str);
    }
};

A

A a1 = Integer::parseInt;

실행 가능한 형태로 만들어 보기 ⬇️

package com.test;

@FunctionalInterface
interface A {
    int abc(String str);
}

public class MyTest {
    public static void main(String[] args) {
        A a1 = new A() {
            @Override
            public int abc(String str) {
                return Integer.parseInt(str);
            }
        };

        A a2 = str -> Integer.parseInt(str); // 람다식
        
        A a3 = Integer::parseInt; // 정적 메소드 참조 방식
        
        System.out.println(a1.abc("12345")); // 12345
        System.out.println(a2.abc("12345")); // 12345
        System.out.println(a3.abc("12345")); // 12345
    }
}

Q5

다음 코드는 배열 생성자 참조를 이용한 람다식으로 인터페이스 A의 객체를 생성하는 코드다. 인터페이스 A를 작성하시오. (추상메서드의 이름은 abc)

A a1 = double[]::new;

A

@FunctionalInterface
interface A {
	double[] abc(int len);
}

배열의 크기를 입력 받아야 생성할 수 있다.

실행 가능한 형태로 만들어 보기 ⬇️


@FunctionalInterface
interface A {
    double[] abc(int len);
}

public class MyTest {
    public static void main(String[] args) {
        A a2 = new A() {
            @Override
            public double[] abc(int len) {
                return new double[len];
            }
        };
        
        A a1 = double[]::new;
    }
}

Q6

3개의 생성자가 오버로딩된 클래스 B는 다음과 같다.

class B {
    B() { System.out.println("첫번째 생성자"); }
    B(int a) { System.out.println("두번째 생성자"); }
    B(int a, double b) { System.out.println("세번째 생성자"); }
}

클래스 생성자 참조 람다식을 사용해 a의 객체를 생성하고, A객체의 abc() 메서드를 호출했을 때 "세번째 생성자"가 출력될 수 있도록 인터페이스 A를 작성하시오.

A a1 = B::new;
a1.abc(1, 2.0); // 세번째 생성자

A

@FunctionalInterface
interface A {
	B abc(int a, double b);
}

실행 가능한 형태로 만들어 보기 ⬇️

package com.test;

class B {
    B() { System.out.println("첫번째 생성자"); }
    B(int a) { System.out.println("두번째 생성자"); }
    B(int a, double b) { System.out.println("세번째 생성자"); }
}

@FunctionalInterface
interface A {
    B abc(int i, double d);
}

public class MyTest {
    public static void main(String[] args) {
        A a1 = B::new;
        a1.abc(1, 2.0);

        A a2 = new A() {
            @Override
            public B abc(int i, double d) {
                return new B(i, d);
            }
        };
        a2.abc(1, 2.0);
    }
}

Q7

다음과 같이 클래스 B 내부에는 정수값 하나를 입력받는 bcd(int k) 인스턴스 메서드가 정의돼 있다.

class B {
    void bcd(int k) {
        System.out.println(k);
    }
}

다음과 같이 람다식을 이용해 인터페이스 A 객체를 생성한 후 abc()를 호출하면 3이 출력된다. 이때 인터페이스 A를 작성하시오.

A a1 = B::bcd;
B b = new B();
a1.abc(b, 3);    // 3

A

@FunctionalInterface
interface A {
	void abc(B b, int n);
}

실행 가능한 형태로 만들어 보기 ⬇️

class B {
    void bcd(int k) {
        System.out.println(k);
    }
}

@FunctionalInterface
interface A {
    void abc(B b, int k);
}

public class MyTest {
    public static void main(String[] args) {
       A a1 = B::bcd;
        B b = new B() ;
        a1.abc(b, 3);    // 3

        A a2 = new A() {
            @Override
            public void abc(B b, int k) {
                b.bcd(k);
            }
        };
        a2.abc(b, 3);
    }
}

표준 API의 함수적 인터페이스

Thread 구현 요즘엔 람다식으로 한다 !

예전엔 runner1, 2 처럼만 썼는데 @FunctionalInterface 생긴 이후로 runner3처럼 간결하게 구현할 수 있다.

package com.test;

public class MyTest {
    public static void main(String[] args) {
        class MyRunnable implements Runnable {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++)
                    System.out.println("#1 : " + i);
            }
        };
        Runnable runner1 = new MyRunnable();

        Runnable runner2 = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++)
                    System.out.println("#2 : " + i);
            }
        };

        Runnable runner3 = () -> { <= 람다식으로 run() 메서드를 정의하고 실행 가능
            for (int i = 0; i < 10; i++)
                System.out.println("#3 : " + i);
        };


        Thread thread1 = new Thread(runner1);
        Thread thread2 = new Thread(runner2);
        Thread thread3 = new Thread(runner3);

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

java.util.function => 함수형 인터페이스를 제공

대표적인 것들 ⬇️

  • Consumer => void accept(T t);
    • 매개변수는 있고, 리턴값은 없음
    • 주로 accept로 매개 값을 소비
  • Supplier => T get();
    • 매개변수는 없고, 리턴값은 있음
    • 데이터를 만들어서 공급해주는 역할
  • Function => R apply(T t);
    • 매개 변수도 있고, 리턴값도 있음
    • 주로 매개값을 리턴값으로 맵핑 (타입 변환)
  • xxxOperator => applyAs...
    • 매개 변수도 있고, 리턴값도 있음
    • 주로 매개값을 연산하고 결과를 반환
  • Predicate => boolean test(T t);
    • 매개 변수도 있고, boolean을 반환
    • 매개값을 조사해서 true/false를 반환

Consumer 함수형 인터페이스

public interface Consumervoid accept(T t)
public interface BiConsumer<T, U>void accept(T t, U u)
public interface DoubleConsumervoid accept(double value)
public interface LongConsumervoid accept(long value)
public interface ObjDoubleConsumervoid accept(T t, double value)
public interface ObjIntConsumervoid accept(T t, int value)
public interface ObjLongConsumervoid accept(T t, long value)
package com.test;

import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.DoubleConsumer;
import java.util.function.ObjIntConsumer;

class MyClass {
    private String str;

    MyClass(String str) {
        this.str = str;
    }

    public void print() {
        System.out.printf("%s's length is %d\n", this.str, this.str.length());
    }
}
public class MyTest {
    public static void main(String[] args) {
        MyClass mc = new MyClass("Hello, Consumer");
        mc.print();

        Consumer<String> consumer1 = new Consumer<>() {
            @Override
            public void accept(String s) {
                System.out.printf("%s's length is %d\n", s, s.length());
            }
        };
        consumer1.accept("Hello, Consumer");

        Consumer<String> consumer2 = s -> System.out.printf("%s's length is %d\n'", s, s.length());
        consumer2.accept("Hello, Consumer");

        BiConsumer<String, Integer> consumer3 = (s, i) -> System.out.printf("이름은 %s이고, 나이는 %d입니다.\n", s, i);
        consumer3.accept("홍길동", 23);

        DoubleConsumer consumer4 = d -> System.out.printf("Java version is %.2f\n", d);
        consumer4.accept(11.2);

        ObjIntConsumer<String> consumer5 = (o, i) -> System.out.printf("%s의 나이는 %d입니다.\n", o, i);
        consumer5.accept("홍길동", 23);
    }
}

원래라면 이렇게 ⬇️ 일일이 클래스를 만들어 적어야 하는데 Consumer를 활용하면 아무것도 안 하고 데이터를 어떻게 소비할 건지에 대한 동작만 써서 간편하게 활용할 수 있다.

class MyClass {
    private String str;
    
    MyClass(String str) {
        this.str = str;
    }
    
    public void print() {
        System.out.printf("%s's length is %d\n", this.str, this.str.length());
    }
}

Supplier 함수형 인터페이스
=> getXXX() 메서드를 포함

package com.test;

import java.util.function.IntSupplier;

class Dice {
    static int getNumber() {
        return (int)(Math.random() * 6) + 1;
    }
}
public class MyTest {
    public static void main(String[] args) {
        System.out.println("주사위 결과 >>> " + Dice.getNumber());
        IntSupplier intSupplier1 = new IntSupplier() {
            @Override
            public int getAsInt() {
                return (int)(Math.random() * 6) + 1;
            }
        };
        System.out.println("주사위 결과 >>> " + intSupplier1.getAsInt());

        IntSupplier intSupplier2 = () -> (int)(Math.random() * 6) + 1;
        System.out.println("주사위 결과 >>> " + intSupplier2.getAsInt());
    }
}

Function 함수형 인터페이스
=> 매개변수와 리턴값이 있는 applyXXX() 메서드를 포함

public interface Function<T, R>R apply
public interface BiFunction<T, U, R>R apply<T t, U u>
public interface DoubleFunctionR apply(double value)
public interface IntFunctionR apply(int value)
public interface LongFunctionR apply(long value)
public interface IntToLongFunctionlong applyAsLong(int value)
public interface ToIntFunctionint applyAsInt(T t)
package com.test;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.ToIntFunction;

class Student {
    private String name;
    private int englishScore;
    private int mathScore;

    public Student(String name, int englishScore, int mathScore) {
        super();
        this.name = name;
        this.englishScore = englishScore;
        this.mathScore = mathScore;
    }

    public String getName() {
        return name;
    }

    public int getEnglishScore() {
        return englishScore;
    }

    public int getMathScore() {
        return mathScore;
    }
}

public class MyTest {

    private static List<Student> list = Arrays.asList(
            new Student("홍길동", 90, 96),
            new Student("고길동", 85, 90)
    );

    public static void printString(Function<Student, String> function) {
        for (Student student : list) {
            System.out.print(function.apply(student) + "\t");
        }
        System.out.println();
    }

    public static void printInt(ToIntFunction<Student> function) {
        for (Student student : list) {
            System.out.print(function.applyAsInt(student) + "\t");
        }
        System.out.println();
    }

    public static double average(ToIntFunction<Student> function) {
        int sum = 0;
        for (Student student : list) {
            sum += function.applyAsInt(student);
        }
        return (double) sum / list.size();
    }

    public static void main(String[] args) {
        // 학생이름     홍길동     고길동
        // 영어점수     90          85
        // 수학점수     96          90
        // 영어평균     87.5
        // 수학평규     93.0
        System.out.print("학생이름\t");
        printString(t -> t.getName());

        System.out.print("영어점수\t");
        printInt(t -> t.getEnglishScore());

        System.out.print("수학점수\t");
        printInt(t -> t.getMathScore());

        System.out.print("영어평균\t");
        System.out.println(average(t -> t.getEnglishScore()));

        System.out.print("수학평균\t");
        System.out.println(average(t -> t.getMathScore()));
    }
}

Operator 함수형 인터페이스

public interface BinaryOperatorT apply(T t1, T t2)
public interface UnaryOperatorT apply(T t)
public interface DoubleBinaryOperatordouble applyAsDouble(double left, double right)
public interface DoubleUnaryOperatordouble applyAsDouble(double value)
public interface IntBinaryOperatorint applyAsInt(int left, int right)
public interface IntUnaryOperatorint applyAsInt(int value)
import java.util.function.IntBinaryOperator;

public class Lambda {
    private static int[] scores = { 92, 95, 87 };
    
    public static int maxOrMin(IntBinaryOperator op) {
        int result = scores[0];
        for (int score : scores) {
            result = op.applyAsInt(result, score);
        }
        return result;
    }
    
    public static void main(String[] args) {
        int max = maxOrMin((a, b) -> {
            if (a >= b) return a;
            else return b;
        });
        System.out.println("최대값 >>> " + max);
        
        int min = maxOrMin((a, b) -> {
            if (a <= b) return a;
            else return b;
        });
        System.out.println("최소값 >>> " + min);
        
        
        
        IntBinaryOperator maxOp = (a, b) -> {
            if (a >= b) return a;
            else return b;
        };        
        int result = scores[0];
        for (int score : scores) {
            result = maxOp.applyAsInt(result, score);
        }
        System.out.println("최대값 >>> " + result);
        
        
        IntBinaryOperator minOp = (a, b) -> {
            if (a <= b) return a;
            else return b;
        };
        result = scores[0];
        for (int score : scores) {
            result = minOp.applyAsInt(result, score);
        }
        System.out.println("최소값 >>> " + result);        
    }
}

Predicate 함수형 인터페이스

Predicateboolean test(T t)
BiPredicate<T, U>boolean test(T t, U u)
DoublePredicateboolean test(double v)
IntPredicateboolean test(int v)
LongPredicateboolean test(longv)

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

class Student {
    String name;
    String gender;
    int score;
    
    public Student(String name, String gender, int score) {
        super();
        this.name = name;
        this.gender = gender;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public String getGender() {
        return gender;
    }

    public int getScore() {
        return score;
    }    
}

public class Lambda {
    
    private static List<Student> students = Arrays.asList(
            new Student("홍길동", "남자", 90), 
            new Student("고길동", "남자", 91), 
            new Student("나여자", "여자", 93), 
            new Student("여자야", "여자", 92) 
    );
    
    public static double average(Predicate<Student> pred) {
        int count = 0;
        int total = 0; 
        for (Student student: students) {
            if (pred.test(student)) {
                count ++;
                total += student.score;
            }
        }
        return (double) total / count;
    }
    
    public static void main(String[] args) {
        double maleAverage = average(t -> t.getGender().equals("남자"));
        System.out.println("남자 평균 점수 >>> " + maleAverage);
        
        double femaleAverage = average(t -> t.getGender().equals("여자"));
        System.out.println("여자 평균 점수 >>> " + femaleAverage);         
        

        
        int count = 0;
        int total = 0;
        Predicate<Student> pred = new Predicate<>() {
            @Override
            public boolean test(Student t) {
                return t.getGender().equals("남자");
            }            
        };
        for (Student student: students) {
            if (pred.test(student)) {
                count ++;
                total += student.getScore();
            }
        }
        maleAverage = (double) total / count;
        System.out.println("남자 평균 점수 >>> " + maleAverage);
    }
}

0개의 댓글