[JAVA] 1. Functional interface

초보개발자·2024년 1월 22일
0

Java

목록 보기
1/5
post-thumbnail

📕명령형 프로그래밍과 선언형 프로그래밍

1. 명령형 프로그래밍(Imperative Programming)

  • OOP 객체 지향 프로그래밍
  • How to do?
  • 어떻게 하여야 하는가?

예시

  1. 이메일을 담을 리스트 선언
  2. 루프
  3. 유저 선언
  4. 검증되지 않았는지 체크
  5. 않았다면 변수에 이메일 추출
  6. 이메일 리스트에 넣기

2. 선언형 프로그래밍(Declarative Programming)

  • Functional Programming
  • What to do?
  • 무엇을 하여야 하는가?

예시

  1. 유저리스트에서
    (1) 검증되지 않은 유저만 골라내서
    (2) 이메일을 추출해서
  2. 리스트로 받기

📙1급 시민의 조건

  • 함수/메서드의 매개변수(parameter)로서 전달할 수 있는가
  • 함수/메서드의 반환값(return)이 될 수 있는가
  • 변수에 담을 수 있는가

☀️다양한 Function Package

java.util.function

왜 이렇게 양이 많을까?

T만을 사용한다면 boxed 타입인 Integer, String과 같은 것들을 계속 사용해줘야 한다. 그러나 이것은 int 등에 비해 메모리를 훨씬 더 많이 사용하기에 primitive 타입을 다루는 interface를 만들었다.

1. Function interface

  • T -> R
@FunctionalInterface
public interface Function<T, R> {
	R apply(T t);
}

그냥 사용

// 사용예제1
public class Main implements Function<Integer, Integer> {
    @Override
    public Integer apply(Integer x) {
        return x+10;
    }
}

public static void main(String[] args) {
    Function<Integer, Integer> myAdder = new Main();
    int result = myAdder.apply(5);
    System.out.println(result);
}

람다 사용

Function<Integer, Integer> myAdder = (Integer x) -> {
    return x + 10;
};
int result = myAdder.apply(5);
System.out.println(result);

Function<Integer, Integer> myAdder = x -> x + 10;
int result = myAdder.apply(5);
System.out.println(result);

더 단순하개 사용 가능

  • 매개변수의 타입이 유추 가능할 경우 타입 생략 가능
  • 매개변수가 하나일 경우 괄호 생략 가능
  • 바로 리턴하는 경우 중괄호 생략 가능

2. BiFunction interface

  • T, U -> R
@FunctionalInterface
public interface BiFunction<T, U, R> {
	R apply(T t, U u);
}
BiFunction<Integer, Integer, Integer> add = (Integer x, Integer y) -> {
    return x + y;
};
int result1 = add.apply(3, 5);
System.out.println(result1);

3. 사용자 설정 interface

  • T, U , V -> R
@FunctionalInterface
public interface TriFunction<T,U,V,R> {
    R apply(T t, U u, V v);
}
// 직접 만들어서 사용
TriFunction<Integer, Integer, Integer, Integer> addThree = (x, y, z) -> x + y + z;

⭐Functional Interface

  • 단 하나의 abstract method만을 가지는 인터페이스 (Single Abstract Method interface)
  • Default method와 static method는 이미 구현이 되어있으므로 있어도 괜찮음

1. Supplier

  • void -> T
@FunctionalInterface
public interface Supplier<T> {
	T get();
}
Supplier<String> mySup = () -> "hello world";
System.out.println(mySup.get());

Supplier<Double> myRandom = () -> Math.random();
System.out.println(myRandom.get());

// 메서드를 만들어서 인수로 받아 사용
public static void printRandom(Supplier<Double> random, int count) {
    for (int i = 0; i < count; i++) {
        System.out.println(random.get());
    }
}

// 새로 만든 메서드 사용
printRandom(myRandom,5);

2. Consumer

  • T -> void
@FunctionalInterface
public interface Consumer<T> {
	void accept(T t);
}
Consumer<String> myConsumer = (String str) -> System.out.println(str);
myConsumer.accept("hello");

// 매서드를 만들어 사용
public static <T> void process(List<T> inputs, Consumer<T> processor) {
    for (T input : inputs) {
        processor.accept(input);
    }
}

// consuemr 인터페이스 만들어 사용
Consumer<Integer> myDifferentIntegerProcessor = x ->
        System.out.println("Processing integer in different way " + x);
process(integerInputs, myDifferentIntegerProcessor);

// 람다식으로 바로 사용
List<Double> doubleInputs = Arrays.asList(1.1, 2.2, 3.3);
process(doubleInputs, x -> System.out.println("Processing double " + x));

3. BiConsumer

  • T, U -> void
@FunctionalInterface
public interface BiConsumer<T, U> {
	void accept(T t, U u);
}
public static <T> void process(List<T> inputs, BiConsumer<Integer, T> processor) {
    for (int i = 0; i< inputs.size(); i++) {
        processor.accept(i, inputs.get(i));
    }
}

BiConsumer<Integer, Double> myDoubleProcessor =
        (index, input) ->
                System.out.println("Processing " + input + " at index " + index);
List<Double> inputs = Arrays.asList(1.1, 2.2, 3.3);
process(inputs, myDoubleProcessor);

4. Predicate

  • T -> boolean
@FunctionalInterface
public interface Predicate<T> {
	boolean test(T t);
}
Predicate<Integer> isPositive = x -> x > 0;
System.out.println(isPositive.test(-10));

//
public static <T> List<T> filter(List<T> inputs, Predicate<T> condition) {
    List<T> output = new ArrayList<>();
    for (T input : inputs) {
        if (condition.test(input)) {
            output.add(input);
        }
    }
    return output;
}

// 인터페이스 내부에 디폴트 메서드 이용
List<Integer> inputs = Arrays.asList(10, -5, 4, -2, 0, 3);
System.out.println("Positive number: " + filter(inputs, isPositive));
System.out.println("Non-positive number: " + filter(inputs, isPositive.negate()));
System.out.println("Non-negative number: "
        + filter(inputs, isPositive.or(x -> x == 0)));
System.out.println("Positive even numbers: "
        + filter(inputs, isPositive.and(x -> x % 2 == 0)));
    }

5. Comparator

  • 비교를 위한 인터페이스
  • java.util 패키지 (다른 애들은 java.util.function)
@FunctionalInterface
public interface Comparator<T> {
	int compare(T o1, T o2);
}
  • 음수면 o1 < o2
  • 0이면 o1 = o2
  • 양수면 o1 > o2
List<User> users = new ArrayList<>();
users.add(new User(3, "Alice"));
users.add(new User(1, "Charlie"));
users.add(new User(5, "Bob"));
System.out.println(users);

Comparator<User> idComparator = (u1, u2) -> u1.getId() - u2.getId();
Collections.sort(users, (u1, u2) -> u1.getId() - u2.getId());
System.out.println(users);

Collections.sort(users, (u1, u2) -> u1.getName().compareTo(u2.getName()));
System.out.println(users);
profile
꾸준히 빠르게

0개의 댓글