표준 API 함수적 인터페이스

  • 자바에서 제공되는 표준API에서 한 개의 추상메소드를 가지는 인터페이스는 모두 람다식을 이용해서 익명 구현 객체로 표현 가능

  • 자바8 부터 java.util.function 패키지에 자주 사용되는 함수적 인터페이스를 표준 API로 제공
  • 제공되는 인터페이스는 5가지

    • Consumer: 매개값은 있고 리턴값이 없음
    • Supplier: 매개값이 없고 리턴값이 있음
    • Function: 매개값, 리턴값 모두 있음(주로 매개값은 리턴값으로 매핑)
      • Function<T, R>
        • T는 입력 타입
        • R은 출력 타입 (Apply의 return 타입)
    • Operator: 매개값, 리턴값 모두 있음(주로 매개값을 연산하고 결과를 리턴)
    • Predicate: 매개값은 있고 리턴 타입은 boolean(매개값을 조사해서 true/false 리턴)

1. Consumer 예제

// 예제 1. FunctionalInterfaceApiMain.java
package com.jremind.exam0625;

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

public class FunctionalInterfaceApiMain {
	public static void main(String[] args) {
		Consumer<String> consumer = t -> System.out.println(t + " Class");
		consumer.accept("Java");

		BiConsumer<String, String> biConsumer = (t, u) -> System.out.println(t+u);
		biConsumer.accept("Java", " Class");

		DoubleConsumer doubleConsumer = d -> System.out.println(d + "를 10으로 나눈 나머지 " + d%10 + "입니다.");
		doubleConsumer.accept(14.0);

		ObjIntConsumer<String> objIntConsumer = (t, i) -> System.out.println(t+i);
		objIntConsumer.accept("Java", 8);
	}
}

2. Supplier 예제

// 예제 1. FunctionalInterfaceApiMain.java
package com.jremind.exam0625;

import java.util.function.IntSupplier;

public class FunctionalInterfaceApiMain {
	public static void main(String[] args) {
		IntSupplier intSupplier = () ->{
			int num = (int)(Math.random()*6) +1;
			return num;
		};
		int num = intSupplier.getAsInt();
		System.out.println("주사위 눈: "+ num);
	}
}

3. Function 예제

// 예제 1-1. Student2.java
package com.jremind.exam0625;

public class Student2 {
	private String name;
	private int englishScore;
	private int mathScore;

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

	public String getName() {
		return name;
	}

	public int getEnglishScore() {
		return englishScore;
	}

	public int getMathScore() {
		return mathScore;
	}
}
// 예제 1-2. Student2Main.java
package com.jremind.exam05;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.ToIntFunction;

public class Student2Main {
	private static List<Student2> list = Arrays.asList(
			new Student2("홍길동", 95, 80),
			new Student2("이순신", 90, 85)
	);

	public static void printString(Function<Student2, String> function) {
		for(Student2 student: list) {
			System.out.println(function.apply(student));
		}
		System.out.println();
	}

	public static void printInt(ToIntFunction<Student2> function) {
		for(Student2 student: list) {
			System.out.println(function.applyAsInt(student));
		}
		System.out.println();
	}

	public static void main(String[] args) {

		System.out.println("[학생이름]");
		// 람다에서 t는 매개인자 "->"는 메소드
		// printString(t -> t.getName()) 코드를 풀어쓰면
		// Function<Student2, String> f = t -> t.getName()
		// printString(f) 와 같음
		printString(t -> t.getName()); //메소드를 가지는 객체를 전달

		System.out.println("[영어점수]");
		printInt(t -> t.getEnglishScore());

		System.out.println("[수학점수]");
		printInt(t-> t.getMathScore());
	}

}

// 예제 2. ToIntBiFunctionMain.java
package com.jremind.exam05;

import java.util.function.ToIntBiFunction;

public class ToIntBiFunctionMain {

	public static void main(String[] args) {
		ToIntBiFunction<String, String> function;

		function = (a, b) -> a.compareToIgnoreCase(b);
		print(function.applyAsInt("Hello World", "hello world"));

		function = String::compareToIgnoreCase;
		print(function.applyAsInt("Hello World", "hello world"));

	}

	public static void print(int order){
		if(order == 0) {
			System.out.println("동일한 문자열입니다.");
		}
	}
}
// 예제 3-1. Member.java
package com.jremind.exam05;

public class Member {
	private String name = "아무개";
	private String id = "없다";

	public Member() {
		System.out.println("Member() 실행");
	}

	public Member(String id) {
		System.out.println("Member(String id) 실행");
		this.id = id;
	}

	public Member(String name, String id) {
		System.out.println("Member(String name, String id) 실행");
		this.name = name;
		this.id = id;
	}

	public String getId() {
		return id;
	}

	public void printStatus() {
		System.out.println("name: " + name);
		System.out.println("id: " + id);
	}
}
// 예제 3-2. BiFunctionMain.java
package com.jremind.exam05;

import java.util.function.BiFunction;
import java.util.function.Function;

public class BiFunctionMain {
	public static void main(String[] args) {
		// 생성자 참조
		// new는 생성자를 호출하는 키워드. Member의 생성자를 호출
		Function<String, Member> function1 = Member::new;
		Member member1 = function1.apply("java8");
		member1.printStatus();

		// 생성자 참조
		// new는 생성자를 호출하는 키워드. Member의 생성자를 호출
		BiFunction<String, String, Member> function2 = Member::new;
		Member member2 = function2.apply("홍길동", "java8");
		member2.printStatus();
	}
}

4. Operator 예제

package com.jremind.exam0625;

import java.util.function.IntBinaryOperator;

public class OperatorMain {
	private static int[] scores = {94, 96, 86};

	public static int maxOrMin(IntBinaryOperator operator) {
		int result = scores[0];
		for(int score : scores) {
			result = operator.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);

	}
}

5. Predicate

// 예제 1-1. Student.java
package com.jremind.exam05;

public class Student {
	private String name;
	private String sex;
	private int score;

	public Student(String name, String sex, int score) {
		this.name = name;
		this.sex = sex;
		this.score = score;
	}

	public String getSex() {
		return sex;
	}
	public int getScore() {
		return score;
	}
}
// 예제 1-2. PredicateMain.java
package com.jremind.exam05;

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

public class PredicateMain {
	private static List<Student> list = Arrays.asList(
			new Student("홍길동", "남자", 90),
			new Student("김영희", "여자", 90),
			new Student("박철수", "남자", 85),
			new Student("이혜숙", "여자", 87)
	);

	public static double avg(Predicate<Student> predicate) {
		int count = 0, sum = 0;
		for(Student student : list) {
			if(predicate.test(student)) {
				count++;
				sum += student.getScore();
			}
		}
		return (double)sum/count;
	}

	public static void main(String[] args) {
		double maleAvg = avg(t -> t.getSex().equals("남자"));
		System.out.println("남자 평균 점수: " + maleAvg);

		double femaleAvg = avg(t -> t.getSex().equals("여자"));
		System.out.println("여자 평균점수: " + femaleAvg);
	}
}