잘할수있을거야 2022. 3. 13. 19:31

Consumer<T>

@FunctionalInterface
public interface Consumer<T> {
	
    //T 타입 객체의 특정 작업만 수행
    void accept(T t); 
    
    //현재 Consumer의 accept메서드가 실행되고
    //바로 다음으로 인자로 받은 Consumer의 accept메서드가 실행되는 내용이 구현된
    //(accept메서드에 구현) 새로운 Consumer 객체 리턴
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

 

Consumer<T> 

accept 메서드의 파라메터 타입 - T 

andThen의 리턴 타입 - Consumer<T> (<- 동일) 


accept 

지네릭 타입 T 객체를 받아 T에 대한 특정 작업을 수행하는 메서드

package functionalstudy;

import java.util.function.Consumer;

class Person {

	private String name = null;
	private int age = 0;

	public void setName(String name) {
		this.name = name;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}

}

public class TestProgram {

	public static void main(String[] args) {

		Consumer<Person> consumerPerson = p -> {
			p.setName("홍길동");
			p.setAge(40);
		};

		Person person = new Person();
		
		consumerPerson.accept(person);
		System.out.println(person.getName());
		System.out.println(person.getAge());

	}

}


andThen

여러 Consumer 객체의 accept메서드가 연쇄적으로 호출되도록 구현된 accept메서드를 가진 Consumer 구현객체 리턴 

 

age 작업을 하는 Consumer와 name 작업을 하는 Consumer로 분리

 

andThen을 사용하지 않은 경우 

public class TestProgram {

	public static void main(String[] args) {

		Consumer<Person> consumerName = p -> p.setName("홍길동");
		Consumer<Person> consumerAge = p -> p.setAge(40);

		Person person = new Person();

		consumerName.accept(person);
		consumerAge.accept(person);

		System.out.println(person.getName());
		System.out.println(person.getAge());

	}

}

 

andThen을 사용한 경우

public class TestProgram {

	public static void main(String[] args) {

		Consumer<Person> consumerName = p -> p.setName("홍길동");
		Consumer<Person> consumerAge = p -> p.setAge(40);
		
		//consumerName.accept(person)작업 후 consumerAge.accept(person)작업
		Consumer<Person> consumerNameThenAge = consumerName.andThen(consumerAge);

		Person person = new Person();

		//연쇄작업이 accept메서드에 구현된 Consumer의 accept 호출(Person 객체를 넘기면서)
		consumerNameThenAge.accept(person); 

		System.out.println(person.getName());
		System.out.println(person.getAge());

	}

}


andThen의 Consumer<? super T> (와일드 카드 하한 제한)

package functionalstudy;

import java.util.function.Consumer;

class A {
	void aMethod() {
		System.out.println("A 작업");
	}
}

class B extends A {
	void bMethod() {
		System.out.println("B 작업");
	}
}

class C extends B {
	void cMethod() {
		System.out.println("C 작업");
	}
}

public class TestProgram {

	public static void main(String[] args) {

		// A타입을 처리하는 consumerA
		Consumer<A> consumerA = a -> {
			a.aMethod();
			System.out.println("consumerA 작업 끝");
			System.out.println();
		};

		// B타입을 처리하는 consumerB
		Consumer<B> consumerB = b -> {
			b.bMethod();
			b.aMethod();
			System.out.println("consumerB 작업 끝");
			System.out.println();
		};

		// C타입을 처리하는 consumerC
		Consumer<C> consumerC = c -> {
			c.cMethod();
			c.bMethod();
			c.aMethod();
			System.out.println("consumerC 작업 끝");
			System.out.println();
		};

		// C인스턴스는 B의 subclass이므로 consumerB에 의해 처리될 수 있다.
		Consumer<C> consumerCandThenB = consumerC.andThen(consumerB);
		consumerCandThenB.accept(new C());
		System.out.println("---------------------------------");

		// C인스턴스는 A의 subclass이므로 consumerA에 의해 처리될 수 있다.
		Consumer<C> consumerCandThenA = consumerC.andThen(consumerA);
		consumerCandThenA.accept(new C());
		System.out.println("---------------------------------");

		// Consumer<B>의 accept에 B타입을 받으므로 C를 대입도 문제없다.
		Consumer<B> consumerBandThenA = consumerB.andThen(consumerA);
		consumerBandThenA.accept(new C());
		System.out.println("---------------------------------");

	}

}