미리 정의되어 있는 함수형 인터페이스
Predicate<T> boolean tedt(T t)
Supplier<T> T get();
Consumer<T> void accept(T t)
Function<T,R> R apply(T t)
Predicate<'T'>
Predicate 인터페이스에는 다음 추상 메소드가 존재한다.
boolean tst(T t);
따라서 Pridecate<T> 인터페이스는 전달된 인자를 판단하여 true 또는 false를 반환해야
하는 상황에서 유용하게 사용할 수 있다.
---------------------------------------------------------------------
public class PredicateDemo {
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;
}
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);
}
}
---------------------------------------------------------------------
짝수 합 : 12
홀수 합 : 33
---------------------------------------------------------------------------
public interface Predicate<T>{
boolean test(T t);
}
public static int sum(Predicate<Integer> p, List<Integer> 1st{...}
위 메소드의 매개변수 선언을 볼때 Predicate가 어떤 인터페이스인지 알고 있다면 바로 다음과
같이 판단 할 수 있다.
'boolean test(Integer t)메소드 정의에 해당하는 람다식을 작성해야 전달해야 한다'
이것이 다양한 함수형 인터페이스를 표준화해서 자바 라이브러리에 포함시킨 이유.
Predicate<'T'>를 구체화하고 다양화 한 인터페이스들.
제공한 이유는 불필요한 언박싱 오토박싱 과정을 막기위해서.
Predicate<T>에서 T를 다음과 같이 기본 자료형으로 결정하여 정의한 인터페이스들도 존재함.
IntPredicate boolean test(int value)
LongPredicate boolean test(long value)
DoublePredicate boolean test(double value)
그리고 Predicate<T>와 달리 두개를 인자로 받아서 true 또는 false를 결정할수있는
다음 인터페이스도 정의되어 있다.
BiPredicate<T,U> boolean test(T t, U u);
---------------------------------------------------------------------
public class IntPredicateDemo {
public static int sum(IntPredicate ip, List<Integer> lst){
int s = 0;
for(int n : lst){
if(ip.test(n))
s += n;
}
return s;
}
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);
}
}
-----------------------------------------------------------------------
짝수 합 : 12
홀수 합 : 33
Supplier<'T'>
Supplier<'T'> 인터페이스에는 다음 추상 메소드가 존재한다.
T get();
public class SupplierDemo {
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;
}
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);
}
}
-------------------------------------------------------------------
[47, 29, 23, 22, 2]
[2, 18, 3, 39, 43, 17, 15, 35, 5, 25]
-------------------------------------------------------------------
public static List<Integer> makeIntList(Supplier<Integer> s, int n)
첫 번째 인자를 통해서 컬렉션 인스턴스에 담을 정수의 생성 방법을 결정할 수 있다.
위 예제에서는 난수의 생성을 택했지만 람다식의 작성을 달리하여 동일한 특정 값을
담을 수도 있고 1씩 증가하는 정수들을 담을 수도 있다.
Supplier<'T'> 구체화 한 인터페이스들.
Supplier<T>에서 T를 기본 자료형으로 결정하여 정의한 인터페이스들은 다음과 같다.
IntSupplier int getasInt()
LongSupplier long getAsLong()
DoubleSupplier double getAsDouble()
BooleanSupplier boolean getAsBoolean()
IntSupplier 기반으로 수정해보기
public class IntSupplierDemo {
public static List<Integer> makeIntList(IntSupplier is, int n){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < n; i++)
list.add(is.getAsInt());
return list;
}
public static void main(String[] args) {
IntSupplier ispr = () -> {
Random rand = new Random();
return rand.nextInt(50);
};
List<Integer> list = makeIntList(ispr,5);
System.out.println(list);
list = makeIntList(ispr,10);
System.out.println(list);
}
}
Consumer<'T'>
Consumer<T> 인터페이스에는 다음 추상 메소드가 존재한다. Consumer라는 이름 처럼
전달 인자를 소비하는 형태로 매개변수화 반환형이 선언되어 있다.
(인자는 전달받지만 반환은 하지 않는다는 뜻)
void accept(T t);
따라서 Consumer<T> 인터페이스는 전달된 인자를 가지고 어떤 결과를 보여야 할 때 유용하게
사용된다.
public class ConsumerDemo {
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>에서 T를 기본 자료형으로 결정하여 정의한 인터페이스들과, 매개변수의 선언을
다양화 한 인터페이스들은 다음과 같다.
IntConsumer void accpt(int value)
ObjIntConsumer<T> void accpt(T t, int value)
LongConsumer void accpet(long value)
ObjLongConsumer<T> void accpet(T t,long value)
DoubleConsumer void accpet(double value)
ObjDoubleConsumer<T> void accpet(T t,double value)
BiConsumer<T, U> void(T t, U u)
이들은 추상 메소드 중심으로 이해하고, 필요할 때 참조할 수 있으면 된다.
public class ObjIntConsumerDemo {
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
Function<T, R>
Function<T,R> 인터페이스에는 다음 추상 메소드가 존재한다.
R apply(T t); //전달 인자와 반환 값이 모두 존재할때.
이렇듯 Function<T,R>의 추상 메소드는 전달 인자와 반환 값이 있는 가장 보편적인 형태이다.
따라서 프로그래머가 흔히 사용 할 수 있는 인터페이스이다.
Function<String, Integer> f = s -> s.length();
System.out.println(f.apply("Robot"));
System.out.println(f.apply("System"));
5
6
Function<T,R>을 구체화하고 다양화 한 인터페이스들
Function<T,R>에서 T와 R을 모두 기본 자료형으로 결정하여 정의한 인터페이스들
---------------------------------------------------------------------
IntToDoubleFunction double applyAsDouble(int value)
(int 타입을 Double로)
DoubleToIntFunction int applyAsInt(Double value)
(Double 타입을 int로)
---------------------------------------------------------------------
Function<T,R>에서 T와 R의 자료형이 일치한다면
IntUnaryOperator int applyAsInt(int operand)
DoubleUnaryOperator double applyAsDouble(double operand)
----------------------------------------------------------------------
Function<T,R>에 위치한 추상 메소드의 매개변수 선언과 반환형을 다양화 한것들
BiFunction<T,U,R> R apply(T t, U u)
IntFunction<R> R apply(int value)
DoubleFunction<R> R apply(double value)
ToIntFunction<T> int applyAsInt(T value)
ToDoubleFunction<T> double applyAsDouble(T value)
ToIntBiFunction<T,U> int applyAsInt(T t,U u)
ToDoubleBiFunction<T,U> double applyAsDouble(T t,U u)
------------------------------------------------------------------------
T,R또는 T,U,R의 자료형이 모두 일치하는 경우
UnaryOperator<T> T apply(T t)
BinaryOperator<T> T apply(T t1, T t2)
UnaryOperator<T>는 Function<T,R>을
BinaryOperator<T>는 BiFunction<T,U,R>을 상속하여 정의한 인터페이스이다.
removeIf 메소드를 사용해보자.
함수형 인터페이스 Collection<E> 인터페이스에 정의되어 있는 다음 디폴트 메소드
default boolean removeIf(Predicate<? super E> filter)
위의 메소드 removeIf 매개변수 선언은 다음과 같다.
Predicate<? super E> filter
따라서 ArrayList<Integer> 인스턴스를 생성하면 그 안에 존재하는 removeIf 메소드 E는
다음과 같이 변경된다
public boolean removeIf(Predicate<? super Integer> filter){...}
매개변수 선언에<? super Integer>가 존재하므로 다음 참조변수 대상으로 람다식을 작성하여
위의 메소드의 인자로 전달할 수 있다.
Predicate<Integer> f = ...
Predicate<Number> f = ...
Predicate<Object> f = ...
removeIf메소드의 기능은 컬렉션 인스턴스에 저장된 인스턴스를 다음 test 메소드의 인자로
전달할때 true가 반환되는 인스턴스는 삭제하겠다는 뜻.
public interface Predicate<T>{
boolean test(T t);
}
-----------------------------------------------------------------------
public class RemoveIfDemo {
public static void main(String[] args) {
List<Integer> ls1 = Arrays.asList(1, -2, 3, -4, 5);
ls1 = new ArrayList<>(ls1);
List<Double> ls2 = Arrays.asList(-1.1, 2.2, 3.3, -4.4, 5.5);
ls2 = new ArrayList<>(ls2);
Predicate<Number> p = n -> n.doubleValue() < 0.0;
ls1.removeIf(p);
ls2.removeIf(p);
System.out.println(ls1);
System.out.println(ls2);
}
}
[1, 3, 5]
[2.2, 3.3, 5.5]
-------------------------------------------------------------------------
위 예제에서
Predicate<Number> p = n -> n.doubleValue() < 0.0;
이를 List<Integer> 인스턴스, 그리고 List<Double> 인스턴스의 removeIf 메소드에
인자로 전달을 하였다. 이것이 가능한 이유는 removeIf 메소드의 매개변수 선언이
Predicate<? super E> filter 이기 때문이다.