위로 아래

함수형 인터페이스

  1. 추상 메소드가 1개인 인터페이스
  2. 주어진 추상 메소드 1개 이외에, 디폴트 메소드나 정적 메소드도 포함하고 있다.
  3. java.util.function.*;
  4. 직접 만들 일은 없고, 그냥 코드를 직관적으로 보기 쉽게 해주려고 만들어져 있는 기능들이다.

 

목록

종류 매개 값 반환 값 메소드 의미
Predicate 있음 boolean test() 매개 값을 조사하여 논릿값으로 보낸다.
Consumer 있음 void accept() 매개 값을 소비한다.
Supplier 없음 있음 get() 반환 값을 공급한다.
Function 있음 있음 apply() 매개 값을 반환 값으로 매핑한다.
Operator 있음 있음 apply() 매개 값을 연산하여 반환 값으로 보낸다.

 

 

 

 


Predicate인터페이스 유형

종류 매개 값 반환 값 메소드 의미
Predicate 있음 boolean test() 매개 값을 조사하여 논릿값으로 보낸다.
  1. 매개 값이 있고, boolean을 반환하는 test()라는 추상메서드를 가진 함수형 인터페이스.
  2. 종류가 여러개 있고(Predicate, IntPredicate, BiPredicate, LongPredicate 등), 각자 test() 추상 메소드를 가지고 있다.

 

 

예시

더보기
import java.util.function.*;
public class PredicateDemo {

	public static void main(String[] args) {
		IntPredicate even = x -> x % 2 == 0;   // 람다식 이용, IntPredicate의 test 구현
		System.out.println(even.test(3)?"짝수":"홀수");
		
		IntPredicate one = x -> x == 1;   // 람다식 이용, IntPredicate의 test 구현
		IntPredicate oneOrEven = one.or(even);   // one 객체이냐, even 객체이냐 물어보는 것.
		System.out.println(oneOrEven.test(1) ? "1 혹은 짝수":"1이 아닌 홀수");
		
		// String 전용 Predicate p를 선언하고 "Java Lambda"가 리턴
		// "Java Lambda" -> targetRef.equals("Java Lambda") 리턴
		// 하나의 추상메소드가 구현됨. 해당되는 개체가 같은지가 리턴되는 메소드로 구형.
		Predicate<String>p = Predicate.isEqual("Java Lambda");
		
		System.out.println(p.test("Java Lambda"));
		System.out.println(p.test("JavaFX"));
		// 하나의 메소드 구현 test가구현 (x,y) -> x>y로 구현되고
		//결과는 x크면 true, 그렇지 않으면 false로 리턴
		BiPredicate<Integer, Integer> bp = (x,y) -> x>y;
		System.out.println(bp.test(2, 3));
	} 
}

 

 

 


Consumer 인터페이스 유형

종류 매개 값 반환 값 메소드 의미
Consumer 있음 void accept() 매개 값을 소비한다.
  1. 주어진 매개 값을 소비만 하고 반환할 값이 없는 accept()라는 추상 메소드를 가진 함수형 인터페이스.
  2. 종류가 여러개 있다(Consumer, BiConsumer, IntConsumer, ObjConsumer 등)
  3. 디폴트 메소드인 andThen()을 포함한다.
Consumer<T> c = t -> { T 타입 t 객체를 사용한 후 void를 반환하는 실행문; };

예시

더보기
import java.util.function.*;

public class ConsumerDemo {
	public static void main(String[]args) {
		// accept 메소드를 구현. x가 들어오면 소문자로 바꿔서 출력.
		Consumer<String> c1 = x -> System.out.println(x.toLowerCase());
		c1.accept("Java Functional Interface");
		
		// 인자가 2개인 accept 메소드를 구현. x와 y를 받아서 출력.
		BiConsumer<String, String> c2 = (x,y) -> System.out.println(x + " : " + y);
		c2.accept("Java", "Lambda");
		
		// accept 메소드를 구현. s와 x를 매개변수로 받아서 s는 정수로 변경해서 정수 x와 더해서 출력
		ObjIntConsumer<String> c3 = (s,x) -> {
			int a = Integer.parseInt(s) + x;
			System.out.println(a);
		};
		c3.accept("100",50);
		
		// accept 메소드 구현. x를 입력 받아서 x*x 제곱 결과를 출려
		IntConsumer c4 = 
				x -> System.out.printf("%d * %d = %d\n", x,x,x*x);
		IntConsumer c5 = 
				c4.andThen(x -> System.out.printf("%d+10 = %d", x, x+10));
		c5.accept(10);
	}
}

 

 

 


Supplier 인터페이스 유형

종류 매개 값 반환 값 메소드 의미
Supplier 없음 있음 get() 반환 값을 공급한다.
  1. 매개 값은 없지만 무언가를 반환하는 get()혹은 getAsInt() 추상 메소드를 가지고 있다.
  2. 종류가 여러 개(Supplier, getAsInt, getAsBoolean, getAsDouble 등)
  3. 포함하는 디폴트메소드나 정적 메소드가 없다.

 

예시

더보기
import java.util.*;
import java.text.*;
import java.util.function.*;

public class SupplierDemo {
	public static void main(String[] args) {
		// get 구현 (return apple;)
		Supplier<String> s1 = () -> "apple";
		System.out.println(s1.get());
		
		int[]x = {0};
		// getAsInt 구현, 배열방에 1 증가하는 것으로 구현
		IntSupplier s2 = () -> x[0]++;
		for(int i=0;i<3;i++)
			System.out.println(s2.getAsInt());
		
		DoubleSupplier s3 = () -> Math.random() * 10;
		System.out.println(s3.getAsDouble());
		
		SimpleDateFormat format = new SimpleDateFormat("MM월 dd일 (E요일) a hh:mm:ss)");
		// 구현 get return format 씌워서 리턴
		Supplier<String> s4 = () -> format.format(new Date());
		System.out.println(s4.get());
	}
}

 

 


Function 인터페이스 유형

종류 매개 값 반환 값 메소드 의미
Function 있음 있음 apply() 매개 값을 반환 값으로 매핑한다.
  1. apply() : 매개 값을 타입 변환하는 추상 메소드
  2. applyAsInt() : 결과를 정수로 반환 / applyAsDouble() : 결과를 실수로 반환
  3. 종류가 여러 개(Bi, Double, IntToDouble,ToDoubleBi 등)
  4. 포함하는 메소드 종류 (위의 종류에 따라 안 가지고 있을 수도 있음)
    1. 순방향 연결 디폴트 메소드 andThen()
    2. 역방향 연결 디폴트 메소드 compose()
    3. 정적 메소드 identity() 
// 정의
Function<T,R> f = t -> {T타입 t객체를 사용하여 R타입 객체를 반환하는 실행문;}

Function<Integer, Integer> add2 = x -> x+2;   // 정수형을 인자로 받아서, 2를 더한 후 정수형을 리턴하는 Function 메소드.

// 사용
참조변수.apply(매개변수);

add2.apply(3);   // 정수 3을 인자로 받아서 2를 더하고 5를 반환하는 Function 메소드 사용


---------------------------------------------
두 개 이상일 때

//순방향 연결
add2.andThen(mul2).apply(3);   // add2 먼저 연산 후, mul2 연산

//역방향 연결
add2.compose(mul2).apply(3);   // mul2 먼저 연산 후, add2 연산

 

예시

더보기
import java.util.function.*;

public class Function1Demo {
	public static void main(String[] args) {
		Function<Integer, Integer> add2 = x -> x+2;
		Function<Integer, Integer> mul2 = x -> x*2;
		
		System.out.println(add2.apply(3));   // 결과 5
		System.out.println(mul2.apply(3));   // 결과 6
		
		System.out.println(add2.andThen(mul2).apply(3));   // 결과 10
		// 3에다 2를 더한 후(add2 연산), 2 곱하기(mul2 연산)
		System.out.println(add2.compose(mul2).apply(3));   // 결과 8
		// 3에다 2곱하고(mul2 연산), 2 더하기(add2 연산)
		
		IntToDoubleFunction half = x -> x / 2.0;   // Function<Integer,Double>
		System.out.println(half.applyAsDouble(5));   // 결과 2.5
		
		ToDoubleBiFunction<String,Integer> circleArea = (s, i) -> Double.parseDouble(s)*i*i;
		double area = circleArea.applyAsDouble("3.14", 5);
		System.out.println(area);   // 결과 78.5
	}
}

예시 2

더보기
// Car 클래스 파일

import java.util.*;

public class Car {
	private String model;
	private boolean gasoline;
	private int age;
	private int mileage;
	
	public Car(String model, boolean gasoline, int age, int mileage) {
		this.model =  model;
		this.gasoline = gasoline;
		this.age = age;
		this.mileage = mileage;
	}
	
	public String getModel() { return model; }
	public boolean isGasoline() { return gasoline; }
	public int getAge() { return age; }
	public int getMileage() { return mileage; }
	
	public String toString() {
		return String.format("Car(%s,%s,%d,%d)", model, gasoline, age, mileage);
	}
	
	public static final List<Car> cars = Arrays.asList(
			new Car("소나타", true, 18, 210000),
			new Car("코란도", false, 15, 200000),
			new Car("그랜저", true, 12, 150000),
			new Car("싼타페", false, 10, 220000),
			new Car("아반테", true, 10, 70000),
			new Car("에쿠스", true, 6, 100000),
			new Car("그랜저", true, 5, 80000),
			new Car("소나타", true, 2, 35000),
			new Car("쏘렌토", false, 1, 10000),
			new Car("아반테", true, 1, 7000)
			);
}
//Function 인터페이스 유형 파일

import java.util.*;
import java.util.function.*;
import sec02.Car;

public class Function2Demo {
	public static void main(String[] args) {
		//Return 타입은 String 들어가는 인자는 Car
		//Car c는 모델 리턴
		Function<Car, String> f1 = c -> c.getModel();
		ToIntFunction<Car> f2 = c -> c.getAge();
		
		for (Car car : Car.cars)
			System.out.println("("+f1.apply(car)+", "+f2.applyAsInt(car)+") ");
		
		System.out.println();
		
		double averageAge = average(Car.cars, c -> c.getAge());   // (1)
		double averageMileage = average(Car.cars, c -> c.getMileage());   // (2)
		
		System.out.println("평균 연식 = "+averageAge);
		System.out.println("평균 주행거리 = "+averageMileage);
		
	}
	//(1) List<Car> cars = Car.cars이고 ToTintFunction<Car> f = c -> c.getAge()
	//(2) List<Car> cars = Car.cars이고 ToTintFunction<Car> f = c -> c.getMileage()
	static public double average(List<Car> cars, ToIntFunction<Car> f) {
		double sum = 0.0;
		
		for(Car car:cars)
			sum+=f.applyAsInt(car);
		
		return sum/cars.size();
	}
}

 

 


Operator 인터페이스 유형

종류 매개 값 반환 값 메소드 의미
Operator 있음 있음 apply() 매개 값을 연산하여 반환 값으로 보낸다.
  1. Function 인터페이스의 특수한 경우.
  2. 매개변수와 반환타입이 같다
  3. apply() 사용
  4. applyAsInt() : 결과를 정수로 반환 / applyAsDouble() : 결과를 실수로 반환
  5. Operator는 기본 인터페이스는 없고, Binary, Unary, Double, Int, Long이 붙은 변종들만 있다.
  6. 포함하는 메소드 종류 (위의 종류에 따라 안 가지고 있을 수도 있음)
    1. 순방향 연결 디폴트 메소드 andThen()
    2. 역방향 연결 디폴트 메소드 compose()
    3. 정적 메소드 identity()
// 정의
Function<T> o = (x,y)-> {T타입 x와 y 객체를 사용하여 T타입을 반환하는 실행문;}

 

예시

더보기

 

import java.util.*;
import java.util.function.*;

public class Operator1Demo {
	public static void main(String[]args) {
		// add2라는 참조 레퍼런스 변수는 x가 파라메터이고, 그 실행 결과값은 x+2인 함수이다.
		IntUnaryOperator add2 = x -> x+2;
		System.out.println(add2.applyAsInt(3));
		
		UnaryOperator<Integer> add2again = x -> x+2;
		System.out.println(add2again.apply(3));
		
		IntUnaryOperator mul2= x -> x*2;
		IntUnaryOperator add2mul2 = add2.andThen(mul2);
		System.out.printf("(3+2)*2 = ");
		System.out.println(add2mul2.applyAsInt(3));
		
		IntBinaryOperator add = (x,y) -> x+y;
		System.out.println(add.applyAsInt(1, 2));
		
		List<Integer> list = new ArrayList<>();
		list.add(5);
		list.add(6);
		list.add(7);
		// 각 엘리먼트의 값을 10을 더한 값으로 바꾼다.
		list.replaceAll(e -> e+10);
		System.out.println(list);
	}
}

 

 

예시2

더보기
// Car 클래스 파일

import java.util.*;

public class Car {
	private String model;
	private boolean gasoline;
	private int age;
	private int mileage;
	
	public Car(String model, boolean gasoline, int age, int mileage) {
		this.model =  model;
		this.gasoline = gasoline;
		this.age = age;
		this.mileage = mileage;
	}
	
	public String getModel() { return model; }
	public boolean isGasoline() { return gasoline; }
	public int getAge() { return age; }
	public int getMileage() { return mileage; }
	
	public String toString() {
		return String.format("Car(%s,%s,%d,%d)", model, gasoline, age, mileage);
	}
	
	public static final List<Car> cars = Arrays.asList(
			new Car("소나타", true, 18, 210000),
			new Car("코란도", false, 15, 200000),
			new Car("그랜저", true, 12, 150000),
			new Car("싼타페", false, 10, 220000),
			new Car("아반테", true, 10, 70000),
			new Car("에쿠스", true, 6, 100000),
			new Car("그랜저", true, 5, 80000),
			new Car("소나타", true, 2, 35000),
			new Car("쏘렌토", false, 1, 10000),
			new Car("아반테", true, 1, 7000)
			);
}
import java.util.*;
import java.util.function.*;
import sec02.Car;

public class Operator2Demo {
	public static void main(String[] args) {
		// comparator +, - ,0
		Comparator<Integer> comparator = (a,b) -> a-b;
		
		// 두 수 중에 더 큰 값이 찾아지는 함수로 선언
		BinaryOperator<Integer> o1 = BinaryOperator.maxBy(comparator);
		System.out.println(o1.apply(10,5));
		System.out.println(o1.apply(20,25));
		
		// 두 수 중에 더 작은 값이 찾아지는 함수로 선언
		BinaryOperator<Integer> o2 = BinaryOperator.minBy(comparator);
		System.out.println(o2.apply(10, 5));
		System.out.println(o2.apply(20, 25));
		
		List<Car> newCars = remodeling(Car.cars, c-> new Car("뉴" + 
				c.getModel(), c.isGasoline(), c.getAge(), c.getMileage()
				));
		System.out.println(newCars);	
	}
	
	// remodeling의 파라미터로 cars, new car
	//new Car("뉴" + 
	//c.getModel(), c.isGasoline(), c.getAge(), c.getMileage()가 전달된다.
	
	static public List<Car> remodeling(List<Car> cars, UnaryOperator<Car> o){
		ArrayList<Car> result = new ArrayList<>();
		for(Car car : Car.cars)
			result.add(o.apply(car));
		return result;
	}
}

 

 

 


Comparator 인터페이스

  1. 객체의 순서를 정렬하기 위해 사용되는 함수형 인터페이스
  2. 메소드의 반환 타입은 모두 Comparator<T> 타입이다
  3. 매개변수 타입은 제네릭 타입이인데 복잡하므로, 편의상 생략한다.
  4. 포함하는 메소드 종류 (위의 종류에 따라 안 가지고 있을 수도 있음)
    1. 정적 메소드
      1. comparing() : Comparable 타입의 정렬 키로 비교하는 Comparator를 반환
      2. naturalOrder() : Comparable 객체에 자연 순서로 비교하는 Comparator를 반환
      3. nullsFirst() : null을 객체보다 작은 값으로 취급하는 Comparator를 반환
      4. nullsLast() : null을 객체보다 큰 값으로 취급하는 Comparator를 반환
      5. reverseOrder() : 자연 반대 순서로 비교하는 Comparator를 반환
      6. comparingInt(), comparingDouble() 등
    2. 디폴트 메소드
      1. reversed() : 현재 Comparator의 역순으로 비교하는 Comparator를 반환
      2. thenComparing() : 다중 키를 사용하여 정렬하려고 새로운 Comparator를 반환

예시

더보기
// Car 클래스 파일

import java.util.*;

public class Car {
	private String model;
	private boolean gasoline;
	private int age;
	private int mileage;
	
	public Car(String model, boolean gasoline, int age, int mileage) {
		this.model =  model;
		this.gasoline = gasoline;
		this.age = age;
		this.mileage = mileage;
	}
	
	public String getModel() { return model; }
	public boolean isGasoline() { return gasoline; }
	public int getAge() { return age; }
	public int getMileage() { return mileage; }
	
	public String toString() {
		return String.format("Car(%s,%s,%d,%d)", model, gasoline, age, mileage);
	}
	
	public static final List<Car> cars = Arrays.asList(
			new Car("소나타", true, 18, 210000),
			new Car("코란도", false, 15, 200000),
			new Car("그랜저", true, 12, 150000),
			new Car("싼타페", false, 10, 220000),
			new Car("아반테", true, 10, 70000),
			new Car("에쿠스", true, 6, 100000),
			new Car("그랜저", true, 5, 80000),
			new Car("소나타", true, 2, 35000),
			new Car("쏘렌토", false, 1, 10000),
			new Car("아반테", true, 1, 7000)
			);
}
import java.util.*;
import sec02.Car;

public class Comparator1Demo {
	public static void main(String[]args) {
		List<Car> list = Car.cars.subList(0, 3);
		Car[] cars = list.toArray(new Car[3]);
		// car의 모델로 비교하는 함수 정의
		
		Comparator<Car> modelComparator = Comparator.comparing(Car::getModel);
		
		System.out.println("배열 cars => " + Arrays.toString(cars));
		//cars를 가지고 모델을 비교하는 (가나다 순) 함수를 이요해서 정렬
		Arrays.sort(cars, modelComparator);
		System.out.println("모델 이름으로 정렬 : " + Arrays.toString(cars));
		
		Arrays.sort(cars, modelComparator.reversed());
		System.out.println("모델 이름 역순으로 정렬 : " + Arrays.toString(cars));
		//비교 기준 : Car::getMileage 주행거리를 가져오는 함수이고, 그 결과를 정수로 비교
		Arrays.sort(cars, Comparator.comparingInt(Car::getMileage));
		System.out.println("주행거리 순으로 정렬 : " + Arrays.toString(cars));
		// -, 0 ,+ => +, 0, - 순으로 결국 역순
		Arrays.sort(cars, Comparator.comparing(Car::getMileage, (a,b) -> b-a));
		System.out.println("주행거리 역순으로 정렬 : " + Arrays.toString(cars));
	}
}