▒ 함수형 인터페이스
🔍 Predicate<T> 함수형 인터페이스
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
- 전달된 인자를 대상으로 true, false를 판단할 때 쓰인다.
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Prac {
public static void main (String[] args) {
List<Integer> list = 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 static int sum(Predicate<Integer> p, List<Integer> lst) {
int s = 0;
for(int n : lst) {
if(p.test(n))
s += n;
}
return s;
}
}
짝수 합 : 12
홀수 합 : 33
💡 Predicate<T> 함수형 인터페이스 종류
✔ IntPredicate 함수형 인터페이스
@FunctionalInterface
public interface IntPredicate {
boolean test(int value);
}
✔ LongPredicate 함수형 인터페이스
@FunctionalInterface
public interface LongPredicate {
boolean test(Long value);
}
✔ DoublePredicate 함수형 인터페이스
@FunctionalInterface
public interface DoublePredicate {
boolean test(double value);
}
✔ BiPredicate<T, U> 함수형 인터페이스
@FunctionalInterface
public interface BiPredicate<T, U> {
boolean test(T t, U u);
}
- 함수형 인터페이스 이름 앞에 'Bi' 가 붙은 경우에는 매개변수의 개수가 2개다.
🔍 Supplier<T> 함수형 인터페이스
@FunctionalInterface
public interface Supplier<T> {
T get();
}
- 단순히 다엇인가 반환할 때 쓰인다.
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
public class Prac {
public static void main (String[] args) {
Supplier<Integer> spr = () -> {
Random rand = new Random();
return rand.nextInt(50);
};
List<Integer> list = makeIntList(spr, 5);
System.out.println(list);
list = makeIntList(spr, 10);
System.out.println(list);
}
public static List<Integer> makeIntList(Supplier<Integer> s, int n) {
List<Integer> list = new ArrayList<>();
for(int i=0; i<n; i++)
list.add(s.get());
return list;
}
}
[37, 40, 27, 6, 14]
[5, 35, 3, 41, 35, 25, 0, 39, 9, 22]
- 난수를 리스트의 요소로 넣기 때문에 실행마다 리스트의 요소 값이 달라진다.
💡 Supplier<T> 함수형 인터페이스 종류
✔ IntSupplier 함수형 인터페이스
@FunctionalInterface
public interface IntSupplier {
int getAsInt();
}
✔ LongSupplier 함수형 인터페이스
@FunctionalInterface
public interface LongSupplier {
long getAsLong();
}
✔ DoubleSupplier 함수형 인터페이스
@FunctionalInterface
public interface DoubleSupplier {
double getAsDouble();
}
✔ BooleanSupplier 함수형 인터페이스
@FunctionalInterface
public interface BooleanSupplier {
boolean getAsBoolean();
}
🔍 Consumer<T> 함수형 인터페이스
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
- 전달된 인자를 가지고 어떤 결과(반환 제외)를 보여야 할 때 사용한다.
import java.util.function.Consumer;
public class Prac {
public static void main (String[] args) {
Consumer<String> c = s -> System.out.println(s);
c.accept("Pineapple");
c.accept("Strawberry");
}
}
Pineapple
Strawberry
- Consumer<T> 인터페이스를 통해 출력이라는 결과를 구현했다.
💡 Consumer<T> 함수형 인터페이스 종류
✔ IntConsumer 함수형 인터페이스
@FunctionalInterface
public interface IntConsumer {
void accept(int value);
}
✔ ObjIntConsumer<T> 함수형 인터페이스
@FunctionalInterface
public interface ObjIntConsumer<T> {
void accept(T t, int value);
}
- obj타입 매개변수와 int 타입 매개 변수를 받는다.
import java.util.function.ObjIntConsumer;
public class Prac {
public static void main (String[] args) {
ObjIntConsumer<String> c = (s, i) -> System.out.println(i + ". " + s);
int n = 1;
c.accept("Toy", n++);
c.accept("Book", n++);
c.accept("Candy", n);
}
}
1. Toy
2. Book
3. Candy
✔ LongConsumer 함수형 인터페이스
@FunctionalInterface
public interface LongConsumer {
void accept(long value);
}
✔ ObjLongConsumer<T> 함수형 인터페이스
@FunctionalInterface
public interface ObjLongConsumer<T> {
void accept(T t, long value);
}
- obj타입 매개변수와 long 타입 매개 변수를 받는다.
✔ DoubleConsumer 함수형 인터페이스
@FunctionalInterface
public interface DoubleConsumer {
void accept(double value);
}
✔ ObjDoubleConsumer<T> 함수형 인터페이스
@FunctionalInterface
public interface ObjDoubleConsumer<T> {
void accept(T t, double value);
}
- obj타입 매개변수와 double 타입 매개 변수를 받는다.
✔ BiConsumer<T, U> 함수형 인터페이스
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u);
}
🔍 Function<T, R> 함수형 인터페이스
@FunctionalInterface
public interface function<T, R> {
R apply(T t);
}
- 전달 인자와 반환 값이 존재할 때 쓰인다.
import java.util.function.Function;
public class Prac {
public static void main (String[] args) {
Function<String, Integer> f = s -> s.length();
System.out.println(f.apply("Robot"));
System.out.println(f.apply("System"));
}
}
5
6
💡 Function<T, R> 함수형 인터페이스 종류
- 반환형과 매개변수형이 동일한 인터페이스는 이름에 Operator로 끝나는 규칙이 있다.
- 매개변수가 하나면 인터페이스 이름 앞에 Unary가 붙는다.
✔ IntToDobuleFunction 함수형 인터페이스
@FunctionalInterface
public interface IntToDoubleFunction {
double applyAsDouble(int value);
}
- int타입 → double타입 형변환
✔ DoubleToIntFunction 함수형 인터페이스
@FunctionalInterface
public interface DoubleToIntFunction {
int applyAsInt(double value);
}
- double 타입 → int 타입 형변환
✔ IntUnaryOperator 함수형 인터페이스
@FunctionalInterface
public interface IntUnaryOperator {
int applyAsInt(int operand);
}
- 매개변수와 반환값이 모두 int 타입이다.
✔ DoubleUnaryOperator 함수형 인터페이스
@FunctionalInterface
public interface DoubleUnaryOperator {
double applyAsDouble(double operand);
}
- 매개변수와 반환값이 모두 double 타입이다.
import java.util.function.DoubleUnaryOperator;
public class Prac {
public static void main (String[] args) {
DoubleUnaryOperator cti = d-> d * 0.393701;
DoubleUnaryOperator itc = d-> d * 2.54;
System.out.println("1 cm = " + cti.applyAsDouble(1.0) + "inch");
System.out.println("1 inch = " + itc.applyAsDouble(1.0) + "cm");
}
}
1 cm = 0.393701inch
1 inch = 2.54cm
✔ BiFunction<T, U, R> 함수형 인터페이스
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
}
- 매개변수를 2개 받고 반환값이 1개다.
✔ IntFunction<R> 함수형 인터페이스
@FunctionalInterface
public interface IntFunction<R> {
R apply(int value);
}
- 매개변수 타입이 int타입이다.
✔ DoubleFunction<R> 함수형 인터페이스
@FunctionalInterface
public interface DoubleFunction<R> {
R apply(double value);
}
- 매개변수 타입이 double타입이다.
✔ ToIntFunction<T> 함수형 인터페이스
@FunctionalInterface
public interface ToIntFunction<T> {
int applyAsInt(T value);
}
- 반환 타입이 int타입이다.
import java.util.function.ToIntFunction;
public class Prac {
public static void main (String[] args) {
ToIntFunction<String> f = s -> s.length();
System.out.println(f.applyAsInt("Robot"));
System.out.println(f.applyAsInt("System"));
}
}
5
6
✔ ToDoubleFunction<T> 함수형 인터페이스
@FunctionalInterface
public interface ToDoubleFunction<T> {
double applyAsDouble(T value);
}
- 반환 타입이 double타입이다.
✔ ToIntBiFunction<T, U> 함수형 인터페이스
@FunctionalInterface
public interface ToIntBiFunction<T, U> {
int applyAsInt(T t, U u);
}
- 매개변수가 2개고 반환타입이 int 타입이다.
✔ ToDoubleBiFunction<T, U> 함수형 인터페이스
@FunctionalInterface
public interface ToDoubleBiFunction<T, U> {
double applyAsDouble(T t, U u);
}
- 매개변수가 2개고 반환타입이 double 타입이다.
✔ UnaryOperator<T> 함수형 인터페이스
@FunctionalInterface
public interface UnaryOperator<T> {
T apply(T t);
}
- Function<T, R> 함수형 인터페이스를 상속 받았다.
- Function<T, R> 함수형 인터페이스에서 모든 타입인자인 T, R을 일치시켜서 타입 인자를 한 개만 받는다.
✔ BinaryOperator<T> 함수형 인터페이스
@FunctionalInterface
public interface BinaryOperator<T> {
T apply(T t1, T t2);
}
- BiFunction<T, U, R> 함수형 인터페이스를 상속 받았다.
- BiFunction<T, U, R> 함수형 인터페이스에서 모든 타입 인자인 T, U, R을 일치시켜서 타입 인자를 한 개만 받는다.
▒ 함수형 인터페이스의 합성과 결합
🔍 andThen() 메서드
- Consumer, Function, Operator 종류의 함수형 인터페이스의 디폴트 메서드다.
예제1
import java.util.function.Function;
public class Prac {
public static void main (String[] args) {
Function<String, Integer> f = s -> Integer.parseInt(s, 16);
Function<Integer, String> g = i -> Integer.toBinaryString(i);
Function<String, String> h = f.andThen(g);
System.out.println(h.apply("FF")); // "FF" → 255 → "11111111"
}
}
11111111
![](https://blog.kakaocdn.net/dn/Emp7Q/btrsrmOHiCq/MRR2anemqB4212jsNuNxW1/img.jpg)
- f.andThen(g)는 함수 f를 먼저 적용하고, 그 다음에 함수 g를 적용한다. ( f → g )
예제2
import java.util.function.Consumer;
public class Prac {
public static void main (String[] args) {
Consumer<Member> consumerA = m -> System.out.println("consumerA: " + m.getName());
Consumer<Member> consumerB = m -> System.out.println("consumerB: " + m.getId());
Consumer<Member> consumerAB = consumerA.andThen(consumerB);
consumerAB.accept(new Member("홍길동", "hong", null));
}
}
class Member {
private String name;
private String id;
private Address address;
public Member(String name, String id, Address address) {
this.name = name;
this.id = id;
this.address = address;
}
public String getName() {return name;}
public String getId() {return id;}
public Address getAddress() {return address;}
}
class Address {
private String country;
private String city;
public Address(String country, String city) {
this.country = country;
this.city = city;
}
public String getCountry() {return country;}
public String getCity() {return city;}
}
consumerA: 홍길동
consumerB: hong
- Consumer 함수형 인터페이스는 반환값이 없기 때문에 andThen() 메서드는 함수형 인터페이스의 호출 순서만 정한다.
예제3
import java.util.function.Function;
public class Prac {
public static void main (String[] args) {
Function<Member, Address> functionA;
Function<Address, String> functionB;
Function<Member, String> functionAB;
String city;
functionA = m -> m.getAddress();
functionB = a -> a.getCity();
functionAB = functionA.andThen(functionB);
city = functionAB.apply(new Member("홍길동", "hong", new Address("한국", "서울")));
System.out.println(city);
}
}
class Member {
private String name;
private String id;
private Address address;
public Member(String name, String id, Address address) {
this.name = name;
this.id = id;
this.address = address;
}
public String getName() {return name;}
public String getId() {return id;}
public Address getAddress() {return address;}
}
class Address {
private String country;
private String city;
public Address(String country, String city) {
this.country = country;
this.city = city;
}
public String getCountry() {return country;}
public String getCity() {return city;}
}
서울
- Function<Member, Address> + Function<Address, String> = Function<Member, String>
🔍 compose() 메서드
- Function, Operator 종류의 함수형 인터페이스의 디폴트 메서드다.
예제1
import java.util.function.Function;
public class Prac {
public static void main (String[] args) {
Function<String, Integer> f = s -> Integer.parseInt(s, 16);
Function<Integer, String> g = i -> Integer.toBinaryString(i);
Function<Integer, Integer> h = f.compose(g);
System.out.println(h.apply(2)); // 2 → "10" → 16
}
}
16
![](https://blog.kakaocdn.net/dn/egMkA2/btrsfWLfWGQ/6eT6wKK5t56pEyptIBSov1/img.jpg)
- f.compose(g)는 함수 g를 먼저 적용하고 함수 f를 적용한다. ( g → f )
import java.util.function.Function;
public class Prac {
public static void main (String[] args) {
Function<Member, Address> functionA;
Function<Address, String> functionB;
Function<Member, String> functionAB;
String city;
functionA = m -> m.getAddress();
functionB = a -> a.getCity();
functionAB = functionB.compose(functionA);
city = functionAB.apply(new Member("홍길동", "hong", new Address("한국", "서울")));
System.out.println(city);
}
}
class Member {
private String name;
private String id;
private Address address;
public Member(String name, String id, Address address) {
this.name = name;
this.id = id;
this.address = address;
}
public String getName() {return name;}
public String getId() {return id;}
public Address getAddress() {return address;}
}
class Address {
private String country;
private String city;
public Address(String country, String city) {
this.country = country;
this.city = city;
}
public String getCountry() {return country;}
public String getCity() {return city;}
}
서울
- Function<Member, Address> + Function<Address, String> = Function<Member, String>
💡 정리
종류 | 함수형 인터페이스 | andThen() | compose() |
Consumer | Consumer<T> | O | |
BiConsumer<T, U> | O | ||
DoubleConsumer | O | ||
IntConsumer | O | ||
LongConsumer | O | ||
Function | Function<T, R> | O | O |
BiFunction<T, U, R> | O | ||
Operator | BinaryOperator<T> | O | |
DoubleUnaryOperator | O | O | |
IntUnaryOperator | O | O | |
LongUnaryOperator | O | O |
🔍 Predicate의 결합
- 여러 Predicate를 디폴트 메서드인 and(), or(), negate()로 연결해서 하나의 새로운 Predicate로 결합할 수 있다.
- isEqula() 메서드는 static 메서드다.
- 두 대상을 비교하는 Predicate를 만들 때 사용한다.
- isEqual() 메서드는 매개변수에 null 값도 받을 수 있다.
- isEqual() 메서드의 매개변수로 비교 대상을 하나 지정하고, 또 다른 비교 대상은 test()의 매개변수로 지정한다.
함수형 인터페이스 | and() | or() | negate() | isEqula() |
Predicate<T> | O | O | O | O |
BiPredicate<T, U> | O | O | O | |
DoublePredicate | O | O | O | |
IntPredicate | O | O | O | |
LongPredicate | O | O | O |
예제1
import java.util.function.Predicate;
public class Prac {
public static void main (String[] args) {
Predicate<Integer> p = i -> i<100;
Predicate<Integer> q = i -> i<200;
Predicate<Integer> r = i -> i%2==0;
Predicate<Integer> notP = p.negate(); // i >= 100;
// 100 <= i && (i < 200 || i%2 ==0)
Predicate<Integer> all = notP.and(q.or(r));
System.out.println(all.test(150));
// negate()를 마지막에 붙이면 조건식 전체가 부정이 된다.
Predicate<Integer> notAll = notP.and(q.or(r)).negate();
System.out.println(notAll.test(150));
String str1 = "abc";
String str2 = "abc";
Predicate<String> p2 = Predicate.isEqual(str1);
boolean result = p2.test(str2);
System.out.println(result);
boolean result2 = Predicate.isEqual("hello").test("hello");
System.out.println(result2);
}
}
true
false
true
true
예제2
import java.util.function.IntPredicate;
public class Prac {
public static void main (String[] args) {
// 2의 배수 검사
IntPredicate predicateA = a -> a%2==0;
// 3의 배수 검사
IntPredicate predicateB = a -> a%3==0;
IntPredicate predicateAB;
boolean result;
// and()
predicateAB = predicateA.and(predicateB);
result = predicateAB.test(9);
System.out.println("9는 2와 3의 배수입니까? " + result);
// or()
predicateAB = predicateA.or(predicateB);
result = predicateAB.test(9);
System.out.println("9는 2 또는 3의 배수입니까? " + result);
// negate()
predicateAB = predicateA.negate();
result = predicateAB.test(9);
System.out.println("9는 홀수입니까? " + result);
}
}
9는 2와 3의 배수입니까? false
9는 2 또는 3의 배수입니까? true
9는 홀수입니까? true
🔍 minBy(), maxBy() 메서드
- BinaryOperator<T> 함수형 인터페이스는 static 메서드인 minBy(), maxBy()를 제공한다.
- 두 메소드는 매개변수값으로 제공되는 Comparator를 이용하여 최대 T와 최소 T를 얻어서 BinaryOperator<T> 타입으로 반환한다.
리턴 타입 | 메서드 |
BinaryOperator<T> | minBy(Comparator<? super T> comparator) |
maxBy(Comparator comparator) |
import java.util.function.BinaryOperator;
public class Prac {
public static void main (String[] args) {
BinaryOperator<Fruit> bo;
Fruit fruit;
bo = BinaryOperator.minBy((f1, f2) -> f2.price - f1.price);
fruit = bo.apply(new Fruit("딸기", 6000), new Fruit("수박", 10000));
System.out.println(fruit.name);
bo = BinaryOperator.maxBy((f1, f2) -> f2.price - f1.price);
fruit = bo.apply(new Fruit("딸기", 6000), new Fruit("수박", 10000));
System.out.println(fruit.name);
}
}
class Fruit {
int price;
String name;
Fruit(String name, int price) {
this.name = name;
this.price = price;
}
}
수박
딸기
▒ 컬렉션 프레임워크와 함수형 인터페이스
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Prac {
public static void main (String[] args) {
List<Integer> list = new ArrayList<>();
for(int i=0; i<10; i++) list.add(i);
// list의 모든 요소 출력
list.forEach(i -> System.out.print(i + ","));
System.out.println();
// list에서 2의 배수 또는 3의 배수 제거
list.removeIf(x-> x%2==0 || x%3==0);
System.out.println(list);
// list의 각 요소에 10을 곱한다.
list.replaceAll(i -> i*10);
System.out.println(list);
Map<String, String> map = new HashMap<>();
map.put("1", "11");
map.put("2", "22");
map.put("3", "33");
map.put("4", "44");
// map의 모든 요소를 {k, v}의 형식으로 출력
map.forEach((k, v) -> System.out.print("{" + k + ", " + v + "}, "));
}
}
0,1,2,3,4,5,6,7,8,9,
[1, 5, 7]
[10, 50, 70]
{1, 11}, {2, 22}, {3, 33}, {4, 44},
'[자바] > 자바' 카테고리의 다른 글
[Java] Optional<T> 클래스 (0) | 2022.02.07 |
---|---|
[Java] 메서드 참조 (Method References) (0) | 2022.02.04 |
[Java] 내부 클래스, 네스티드(Nested) 클래스, 익명 클래스 (0) | 2022.01.27 |
[Java] 애노테이션 (annotation) (0) | 2022.01.26 |
[Java] 열거형 (enum) (0) | 2022.01.26 |