Java lang

[이것이 자바다] 자바 람다식 공부 정리

Razelo 2020. 12. 22. 21:59

no_argument_no_return

package sec03.exam01_no_argument_no_return;

@FunctionalInterface                     //메소드가 하나인지 체크함. 
public interface MyFunctionalInterface { //함수적 인터페이스  -> 람다식으로 표현 가능 .
	public void method();
}
package sec03.exam01_no_argument_no_return;

public class MyFunctionalInterfaceExample {

	public static void main(String[] args) {
		MyFunctionalInterface fi;
		fi = () -> {
			String str = "method call1";
			System.out.println(str);
		};
		fi.method();

		fi = () -> {
			System.out.println("method call2");
		};
		fi.method();

		fi = () -> System.out.println("method call3");
		fi.method();
		
		//메소드 사용하지 않는 익명 객체 구현 
		fi = new MyFunctionalInterface() {
			public void method() {System.out.println("method call4");};
		};
		fi.method();
	}

}

 

 

 

arguments

package sec03.exam02_arguments;

@FunctionalInterface                     
public interface MyFunctionalInterface { 
	public void method(int x);
}
package sec03.exam02_arguments;

public class MyFunctionalInterfaceExample {

	public static void main(String[] args) {
		MyFunctionalInterface fi;
		fi = (x) -> {
			int result = x *5;
			System.out.println(result);
		};
		fi.method(2);;
		
		//약식으로 작성하기. 
		fi = (x) -> {System.out.println(x *5);};
		fi.method(2);;
		
		fi = x -> System.out.println(x *5);
		fi.method(2);;
	}

}

 

 

 

return

package sec03.exam03_return;

@FunctionalInterface                     
public interface MyFunctionalInterface { 
	public int method(int x,int y);
}
package sec03.exam03_return;

public class MyFunctionalInterfaceExample {

	public static void main(String[] args) {
		MyFunctionalInterface fi;
		
		fi = (x,y) -> {
			int result = x+y;
			return result;
		};
		System.out.println(fi.method(2,5));
		
		fi = (x,y) -> {return x+y;};
		System.out.println(fi.method(2,5));
		
		fi = (x,y) -> x+y;
		System.out.println(fi.method(2,5));
		
		fi = (x,y) -> sum(x,y);
		System.out.println(fi.method(2,5));
		
	}
	
	public static int sum(int x, int y) {
		return x+y;
	}

}

 

 

 

field

package sec04.exam01_field;

public interface MyFunctionalInterface {
	public void method();
}
package sec04.exam01_field;

public class UsingThis {
	//이름이 안쪽과 바깥쪽이 같으면 this를 사용해서 사용한다.(그냥 this만 붙이면 내부 에 있는 클래스의 값을 의미한다. ) 
	//이름이 다르다면 그냥 변수명만 선언해서 값을 사용할 수 있다. 
	
	public int field = 10;
	
	class Inner{ //멤버 클래스인 중첩 클래스 
		int field = 20;
		
		void method() {
			MyFunctionalInterface fi = () ->{
				System.out.println("outterField: "+UsingThis.this.field);
				System.out.println("innerField: "+field);
			};
			fi.method(); //인터페이스의 메소드이다. 헷갈리지 말기. 
		}
	}
}
package sec04.exam01_field;

public class UsingThisExample {

	public static void main(String[] args) {
		UsingThis usingThis = new UsingThis();
		UsingThis.Inner inner =usingThis.new Inner();
		inner.method();
	}

}

 

 

 

local_variable

package sec04.exam02_local_variable;

public interface MyFunctionalInterface {
	public void method();
}
package sec04.exam02_local_variable;

public class UsingLocalVariable {
	void method(int arg) {
		int localVar = 40;
		
		//람다식에서 사용되면 묵시적으로 final이 된다. 그래서 변경 불가함. 
		//arg = 31;
		//localVar - 41;
		
		MyFunctionalInterface fi = ()->{
			System.out.println("arg: "+arg);
			System.out.println("localVar: "+localVar);
		}; 
		fi.method();
	}
}
package sec04.exam02_local_variable;

public class UsingLocalVariableExample {

	public static void main(String[] args) {
		UsingLocalVariable ulv = new UsingLocalVariable();
		ulv.method(20);
	}

}

 

 

runnable

package sec05.exam01_runnable;

public class RunnableExample {

	public static void main(String[] args) {
//		Runnable runnable = () ->{
//			for(int i = 0;i<10;i++) {
//				System.out.println(i);
//			}
//		};
//		 
//		Thread thread = new Thread(runnable);
//		thread.start();
		
		//둘다 똑같긴 한데, 이 방식이 조금 더 일반적이다. 좀 더 많이 쓰인다. Runnable 익명 객체 
		Thread thread = new Thread(()->{
			for(int i = 0;i<10;i++) {
				System.out.println(i);
			}
		});
		thread.start();
	}

}

 

 

 

consumer

package sec05.exam02_consumer;

import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.DoubleConsumer;
import java.util.function.ObjIntConsumer;

public class ConsumerExample {

	public static void main(String[] args) {
		Consumer<String> consumer = t -> System.out.println(t+"8"); //소비코드 
		consumer.accept("java");
		
		BiConsumer<String,String> biConsumer = (t,u) -> System.out.println(t+u);
		biConsumer.accept("Java", "8");
		
		DoubleConsumer doubleConsumer = d -> System.out.println("Java"+d);
		doubleConsumer.accept(8.0);
		
		ObjIntConsumer<String> objIntConsumer = (t,i) -> System.out.println(t+i);
		objIntConsumer.accept("Java",8);
	}

}

 

 

 

supplier

package sec05.exam03_suppllier;

import java.util.function.IntSupplier;

public class SupplierExample {

	public static void main(String[] args) {
		IntSupplier intSupplier = () -> {
			int num = (int)(Math.random()*6)+1;
			return num;
		};
		int num = intSupplier.getAsInt();
		System.out.println("눈의 수: "+num);
		
		
		
	}

}

 

 

 

function

package sec05.exam04_function;

public class Student {
	private String name;
	private int englishScore;
	private int mathScore;
	
	public Student(String name, int englishScore,int mathScore) {
		this.name = name;
		this.englishScore = englishScore;
		this.mathScore = mathScore;
	}

	public String getName() {
		return name;
	}

	public int getEnglishScore() {
		return englishScore;
	}

	public int getMathScore() {
		return mathScore;
	}
	
}
package sec05.exam04_function;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.ToIntFunction;

public class FunctionExample1 {
	private static List<Student> list = Arrays.asList(
			new Student("홍길동",90,96),new Student("신용권",95,93)
	);
	
	public static void printString(Function<Student,String> function) {
		for(Student student: list) {
			System.out.print(function.apply(student) + " ");
		}
		System.out.println();
	}
	
	public static void printInt(ToIntFunction<Student> function) {
		for(Student student:list) {
			System.out.print(function.applyAsInt(student) + " ");
		}
		System.out.println();
	}
	
	public static void main(String[] args) {
		System.out.println("[학생 이름]");
		printString(t -> t.getName()); // 학생 객체를 매개값으로 주면 학생의 이름을 리턴하라... 라는 뜻. 
		
		System.out.println("[영어 점수]");
		printInt(t -> t.getEnglishScore());
		
		System.out.println("[수학 점수]");
		printInt(t -> t.getMathScore());
		
		
	}

}
package sec05.exam04_function;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.ToIntFunction;

public class FunctionExample2 {
	private static List<Student> list = Arrays.asList(
			new Student("홍길동",90,96),
			new Student("신용권",95,93)
	);
	
	//이 함수를 사용하려면 매개변수에 람다식을 제공해야 한다. 
	public static double avg(ToIntFunction<Student> function) {
		int sum = 0;
		for(Student student: list) {
			sum += function.applyAsInt(student);
		}
		//나누기 연산중 좌항을 double로 만든 것은 정수/정수 = 정수값이 나오기 때문이다. 
		//그래서 한쪽을 double로 만들어줬다.
		double avg = (double)sum/list.size();  
		return avg;
	}
	
	public static void main(String[] args) {
		double englishAvg = avg(t -> t.getEnglishScore());
		System.out.println("영어 평균 점수: "+englishAvg);
		
		double mathAvg = avg(t -> t.getMathScore());
		System.out.println("수학 평균 점수: "+mathAvg);
	}

}

 

 

operator

package sec05.exam05_operator;

import java.util.function.IntBinaryOperator;

public class OperatorExample {
	private static int[] scores = {92,95,87}; //배열 필드 
	
	public static int maxOrMin(IntBinaryOperator operator) {
		int result = scores[0];
		for(int score: scores) {
			result = operator.applyAsInt(result,score);
		}
		return result;
	}
	public static void main(String[] args) {
		
		// 최대값 얻기 
		int max = maxOrMin(
			(a,b) -> {
				if(a>=b) return a;
				else return b;
			}
		);
		System.out.println("최대값: "+ max); 
		
		
		//최소값 얻기 
		int min = maxOrMin(
			(a,b) -> {
				if(a<=b) return a;
				else return b;
			}
		);
		System.out.println("최소값: "+ min);
	}

}

 

 

 

predicate

package sec05.exam06_predicate;

public class Student {
	private String name;
	private String sex;
	private int score;
	
	public Student(String name,String sex,int score) {
		this.name = name;
		this.sex = sex;
		this.score = score;
	}

	public String getSex() {
		return sex;
	}

	public int getScore() {
		return score;
	}
	
	
	
}



package sec05.exam06_predicate;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class PredicateExample {
	private static List<Student> list = Arrays.asList(
			new Student("홍길동","남자",90),
			new Student("김순희","여자",90),
			new Student("감자바","남자",95),
			new Student("박한나","여자",92)
	);
	
	//남자의 평균 여자의 평균을 구하는 메소드 
	public static double avg(Predicate<Student> predicate) {
		int count = 0, sum = 0;
		for(Student student: list) {
			if(predicate.test(student)) {
				count++;
				sum += student.getScore();
			}
		}
		
		return (double)sum/count; //평균이 된다. 리턴값이 정수가 되지 않기 위해 double 을 써준다. 
	}
	
	public static void main(String[] args) {
		//남자 평균 점수 
		double maleAvg = avg(t -> t.getSex().equals("남자")); //남자의 점수만 sum에 누적됨, 
		System.out.println("남자 평균 점수: "+maleAvg);
		
		//여자 평균 점수 
		double femaleAvg = avg(t -> t.getSex().equals("여자")); //여자의 점수만 sum에 누적됨, 
		System.out.println("여자 평균 점수: "+femaleAvg); 
	}

}

 

 

andthen_compose

package sec05.exam07_andthen_compose;

public 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;
	}
	
	
}
package sec05.exam07_andthen_compose;

public 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;
	}
	
	
}
package sec05.exam07_andthen_compose;

import java.util.function.Consumer;

public class ConsuerAndThenExample {

	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());
		};
		
		//consumerA의 accept가 먼저 실행된다. 
		Consumer<Member> consumerAB = consumerA.andThen(consumerB);
		consumerAB.accept(new Member("홍길동","hong",null));
	}

}
package sec05.exam07_andthen_compose;

import java.util.function.Function;

public class FunctionAndThenComposeExample {

	public static void main(String[] args) {
		Function<Member,Address> functionA;
		Function<Address,String> functionB;
		Function<Member,String> functionAB;
		
		functionA = m -> m.getAddress();
		functionB = a -> a.getCity();
		
		functionAB = functionA.andThen(functionB); //A 부터 실행 
		String city = functionAB.apply(new Member("홍길동","hong",new Address("한국","서울")));
		System.out.println("거주 도시:" +city);
	
		functionAB = functionB.compose(functionA); //A 부터 실행 
		city = functionAB.apply(new Member("홍길동","hong",new Address("한국","서울")));
		System.out.println("거주 도시:" +city);
	
	}

}

 

 

and_or_negate_isequal

package sec05.exam08_and_or_negate_isequal;

import java.util.function.IntPredicate;

public class PredicateAndOrNegageExample {

	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); // and의 리턴타입은 predicate
		result = predicateAB.test(9);
		System.out.println("9는 2와 3의 배수 입니까? " + result);

		// or()
		predicateAB = predicateA.or(predicateB); // or의 리턴타입은 predicate
		result = predicateAB.test(9);
		System.out.println("9는 2또는 3의 배수 입니까? " + result);
		
		//negate()
		predicateAB= predicateA.negate();
		result = predicateAB.test(9);
		System.out.println("9는 홀수입니까? "+result);
	}

}
package sec05.exam08_and_or_negate_isequal;

import java.util.function.Predicate;

public class PredicateIsEqualExample {

	public static void main(String[] args) {
		Predicate<String> predicate;
		
		//isEqual은 결국은 preicate의 익명객체를 리턴을 한다. 
		predicate = Predicate.isEqual(null); 
		System.out.println("null,null: "+predicate.test(null));
		
		predicate = Predicate.isEqual("Java8"); 
		System.out.println("null,Java8: "+predicate.test(null));
		
		predicate = Predicate.isEqual(null); 
		System.out.println("Java8,null: "+predicate.test("Java8"));
		
		predicate = Predicate.isEqual("Java8"); 
		System.out.println("Java8,Java8: "+predicate.test("Java8"));
		
		//그냥 비교하면 되지 왜 굳이 Predicate를 쓰나요?
		//컬렉션 프레임워크 사용할때 유용하게 사용할 수 있기 때문이다. 나중에 배움! 
		
		
	}

}

 

 

minby_maxby

package sec05.exam09_minby_maxby;

public class Fruit {
	public String name;
	public int price;
	
	public Fruit(String name, int price) {
		this.name = name;
		this.price = price;
	}
	
}
package sec05.exam09_minby_maxby;

import java.util.function.BinaryOperator;

public class OperatorMinByMaxByExample {

	public static void main(String[] args) {
		BinaryOperator<Fruit> binaryOperator;
		Fruit fruit; //리턴값을 받기 위해 
		                     					//<------여기부터 comparator의 익명 구현 객체 -----> 
		binaryOperator = BinaryOperator.minBy((f1,f2) -> Integer.compare(f1.price,f2.price));
		fruit = binaryOperator.apply(new Fruit("딸기",6000), new Fruit("수박",10000)); // 이중에서 조건에 해당되는 Fruit객체가  fruit에 할당된다.  
		System.out.println(fruit.name);
		
		binaryOperator = BinaryOperator.maxBy((f1,f2) -> Integer.compare(f1.price,f2.price));
		fruit = binaryOperator.apply(new Fruit("딸기",6000), new Fruit("수박",10000));
		System.out.println(fruit.name);
		
	}

}

 

 

method_references

package sec06.exam01_method_references;

public class Calculator {
	
	//static 메소드 
	public static int staticMethod(int x, int y) {
		return x+y;
	}
	
	//인스턴스 메소드 
	public int instanceMethod(int x, int y) {
		return x+y;
	}
}
package sec06.exam01_method_references;

import java.util.function.IntBinaryOperator;

public class MethodReferencesExample {

	public static void main(String[] args) {
		//두 개의 int값을 받아서 연산후에 하나의 int를 리턴하기 때문에 
		//Caculator의 매개변수 및 리턴과 형태가 같기 때문에 이걸 사용했다.
		IntBinaryOperator operator;  
		
		//정적 메소드 참조 
		operator = (x,y) -> Calculator.staticMethod(x,y);
		System.out.println("결과1: "+operator.applyAsInt(1,2));
		
		operator = Calculator :: staticMethod;
		System.out.println("결과2: "+operator.applyAsInt(3,4));
		
		//인스턴스 메소드 참조 
		Calculator obj = new Calculator();
		operator = (x,y) -> obj.instanceMethod(x, y);
		System.out.println("결과3: "+operator.applyAsInt(5,6));
		
		operator = obj :: instanceMethod;
		System.out.println("결과4: "+operator.applyAsInt(7,8));
		
	}

}

 

 

argument_method_references

package sec06.exam02_argument_method_references;

import java.util.function.ToIntBiFunction;

public class ArgumentMethodReferencesExample {

	public static void main(String[] args) {
		ToIntBiFunction<String,String> function;
		//a와 b를 대소문자 상관없이 사전순으로 비교한다. a가 사전순으로 먼저오면 음수/ 같으면 0 /a가 뒤에 오면 양수 
		function = (a,b) -> a.compareToIgnoreCase(b); 
		print(function.applyAsInt("Java8","JAVA8"));
		
		//자바는compareToIgnoreCase가 인스턴스 메소드임을 알고, a의 인스턴스 메소드임을 확인하고, 
		//맞다면 이 메소드의 매개값으로 b를 대입을 해서 리턴값을 만들어 낸다.
		function = String :: compareToIgnoreCase; //인스턴스 메소드가 된다. 
		print(function.applyAsInt("Java8","JAVA8"));
		
	}

	public static void print(int order) { //applyAsInt가 리턴하는 값이 int이니까 int를 받는다. 
		if(order<0) System.out.println("사전순으로 먼저 옵니다.");
		else if(order == 0) System.out.println("동일한 문자열입니다.");
		else System.out.println("사전순으로 나중에 옵니다.");
	}
}

 

 

constructor_references

package sec06.exam03_constructor_references;

public class Member {
	private String name;
	private String id;
	
	public Member() {
		System.out.println("Member() 실행");
	}
	public Member(String id) {
		System.out.println("Member(String id) 실행");
		this.id = id;
	}
	public Member(String name, String id) {
		System.out.println("Member(String name, String id) 실행");
		this.name = name;
		this.id = id;
	}
	
}
package sec06.exam03_constructor_references;

import java.util.function.BiFunction;
import java.util.function.Function;

public class ConstructorReferencesExample {

	public static void main(String[] args) {
		Function<String, Member> function1 = Member::new; // 생성자 참조
		Member member1 = function1.apply("angel");

		BiFunction<String, String, Member> function2 = Member::new;
		Member member2 = function2.apply("신천사", "angel");
		
	}

}

 

 

 

 

 

필기

package Lamda;
/*

자바 람다식

함수적 프로그래밍 
y = f(x)형태의 함수로 구성된 프로그래밍 기법
데이터를 매개값으로 전달하고 결과를 받는 코드들로 구성
객체 지향 프로그래밍 보다는 효율적인 경우 -> 
1. 대용량 데이터의 처리시에 유리
	데이터 포장 객체를 생성후 처리하는 것보다 데이터를 바로 처리하는 것이 속도에 유리하다.
	멀티 코어 CPU에서 데이터를 병렬 처리하고 취합할 때 객체보다는 함수가 유리 
2. 이벤트 지향프로그래밍 (이벤트가 발생하면 핸들러 함수 실행)에 적합
	반복적인 이벤트 처리는 헨들러 객체보다는 핸들러 함수가 적합 
	
현대적 프로그래밍 기법 -> 
객체지향 프로그래밍 + 함수적 프로그래밍 

자바 8부터 함수적 프로그래밍 지원 
람다식 (Lamda Expressions)을 언어 차원에서 제공
람다 계산법에서 사용된 식을 프로그래밍 언어에 접목 
익명 함수 (anonymous function)을 생성하기 위한 식 

y = f(x) 에서 따져보면 
(타입 매개변수, ... ) -> {실행문;... }
 x               ->        y 
꼴이라고 볼 수 있다. 

자바에서 람다식을 수용한 이유 
코드가 매우 간결해진다. 
컬렉션 요소(대용량 데이터)를 필터링 또는 매핑해서 쉽게 집계할 수 있다. 

자바는 람다식을 함수적 인터페이스의 익명 구현 객체로 취급한다. -> 가장 간결한 표현인듯... 
함수적 인터페이스 ->  (한 개의 메소드를 가지고 있는 인터페이스 )
람다식 -> 매개변수를 가진 코드 블록 -> 익명 구현 객체 
 다 같은 표현이다. 
 
어떤 인터페이스를 구현할지는 대입되는 인터페이스에 달려있다. 

<람다식 기본 문법>
(int a) -> {System.out.println(a);}

매개 타입은 런타임시에 대입값에 따라 자동으로 인식하기 때문에 생략 가능 
(a) -> {System.out.println(a);}

하나의 매개변수만 있을 경우에는 괄호 생략 가능
a -> {System.out.println(a);}

하나의 실행문만 있다면 중괄호 생략 가능
a -> System.out.println(a)

매개변수가 없다면 괄호를 생략할 수 없음
() -> {실행문;...}

리턴값이 있는 경우, return문을 사용
(x,y) -> {return x+y;}

중괄호에 return 문만 있을 경우, 중괄호를 생략 가능
(x,y) -> x+y


<타겟 타입 target type>
람다식이 대입되는 인터페이스를 말한다.
익명 구현 객체를 만들 때 사용할 인터페이스이다. 

함수적 인터페이스(functional interface)
모든 인터페이스는 람다식의 타겟 타입이 될 수 없다.
람다식은 하나의 메소드를 정의하기 때문에 하나의 추상 메소드만 선언된 인터페이스만 타겟 타입이 될 수 있음. 

함수적 인터페이스
하나의 추상 메소드만 선언된 인터페이스를 말한다. 

@FunctionalInterface 어노테이션 -> 항상 써줄필요는 없음. 검사하고 싶으면 써주셈. / 실수 줄이고 싶다면 사용 ㄱㄱ 
하나의 추상 메소드만을 가지는지 컴파일러가 체크하도록 함
두 개 이상의 추상 메소드가 선언되어 있으며 컴파일 오류 발생. 
   
매개변수와 리턴값이 없는 람다식 
@FunctionalInterface
public void MyFunctionalInterface{
	public void method();
}

MyFunctionalInterface fi = () -> {...}
fi.method();



<클래스의 멤버 사용>
람다식 실행블록에는 클래스의 멤버인 필드와 메소드를 제약 없이 사용할 수 있다.
람다식 실행 블록내에서는 this는 람다식을 실행한 객체의 참조이다. 

<로컬 변수의 사용>
람다식은 함수적 인터페이스의 익명 구현 객체를 생성한다.
 람다식에서 사용하는 외부 로컬 변수는 final 특성을 갖는다. 
 -> 심지어 람다식보다 위에 있는 코드에서 값을 변경하려고 하더라도 
  final 특성 때문에 값을 변경할 수 없다. 
  -->굳이 final 선언하지 않아도 묵시적으로 final선언이 되는거나 마찬가지 



< 표준 API의 함수적 인터페이스 >
한 개의 추상 메소드를 가지는 인터페이스들은 모두 람다식 사용 가능. 

<자바 8부터 표준 API로 제공되는 함수적 인터페이스 >
java.util.function 패키지에 포함되어 있다. 
매개타입으로 사용되어 람다식을 매개값으로 대입할 수 있도록 해준다. 

<종류>
Consumer 함수적 인터페이스 류 : 소비한다... 데이터를 그냥 소비만하고 끝나는 기능 제공 
-> 매개값만 있고, 리턴값이 없는 추상 메소드를 가지고 있다. 

Supplier 함수적 인터페이스 류 : 데이터를 공급해준다. 공급자 기능. 데이터를 리턴해줌. 
-> 매개값은 없고, 리턴값만 있는 추상 메소드를 가지고 있다. 

Function 함수적 인터페이스 류 : A라는 데이터를 B로 변환할 떄 사용
-> 매개값과 리턴값이 모두 있는 추상 메소드를 가지고 있다. 
   주로 매개값을 리턴값으로 매핑(타입변환)할 경우에 사용. 
   
Operator 함수적 인터페이스 류 : 어떤 데이터를 연산할 때 사용 
-> 매개값과 리턴값이 모두 있는 추상 메소드를 가지고 있다. 
    주로 매개값을 연산하고, 그 결과를 리턴할 경우에 사용한다. 

Predicate 함수적 인터페이스 류 : 어떤 매개값을 조사해서 참거짓을 리턴할때 사용함. 
-> 매개값을 조사해서 true또는 false 를 리턴할 떄 사욯함. 

-----------------------------------------------------------
Tip: 이름에 Bi가 들어가면 왠만해서는 매개변수 개수는 2개다... 라고 이해하면 편하다.

 
Consumer 함수적 인터페이스 
Consumer 함수적 인터페이스의 특징은 리턴값이 없는 accept() 메소드를 가지고 있다.  
accept() 메소드는 단지 매개값을 소비하는 역할만 한다. 여기서 소비한다는 말은 사용만 할 뿐
리턴값이 없다는 뜻이다. 

Supplier 함수적 인터페이스 
Supplier 함수적 인터페이스의 특징은 매개변수가 없고, 리턴값이 있는 getXXX() 메소드를 
가지고 있다. 이들 메소드는 실행 후 호출한 곳으로 데이터를 리턴 (공급) 하는 역할을 한다. 

Function 함수적 인터페이스 
Function 함수적 인터페이스의 특징은 매개변수와 리턴값이 있는 applyXXX() 메소드를 가지고 
있다. 이들 메소드는 매개값을 리턴값으로 매핑(타입변환)하는 역할을 한다. 

Operator 함수적 인터페이스
tip: Unary는 1이라는 의미를 갖고 있다. 이게 들어가면 보통 매개값이 하나라고 보면 된다, 
Operator 함수적 인터페이스의 특징은 Function과 동일하게 매개변수와 리턴값이 있는
applyXXX() 메소드를 가지고 있다. 하지만 이들 메소드는 매개값을 리턴값으로 매핑 (타입변환)
하는 역할보다는 매개값을 이욯해서 연산을 수행한 후 동일한 타입으로 리턴값을 제공하는 역할을 한다. 

Predicate 함수적 인터페이스 
Predicate 함수적 인터페이스의 특징은 매개변수와 boolean 리턴값이 있는 testXXX() 메소드를
가지고 있다. 이들 메소드는 매개값을 조사해서 true 또는 false 를 리턴하는 역할을 한다. 
매개변수 타입과 수에 따라서 아래와 같은 Predicate 함수적 인터페이스들이 있다. 

---------------------------------------------------------------------------
<andThen()과 compose() 디폴트 메소드>
함수적 인터페이스가 가지고 있는 디폴트 메소드이다. 
두 개의 함수적 인터페이스를 순차적으로 연결해서 실행한다. 
첫번째 리턴값을 두번째 매개값으로 제공해서 최종 결과값 리턴한다. 
andThen() 과 compose() 의 차이점은 어떤 함수적 인터페이스부터 처리한냐이다. (즉 실행순서)

<andThen() 디폴트 메소드> -> A부터 실행 
인터페이스 AB = 인터페이스A.andThen(인터페이스B);
최종결과 = 인터페이스 AB.method();

<compose() 디폴트 메소드> -> B부터 실행
인터페이스 AB = 인터페이스 A.compose(인터페이스 B);
최종결과 = 인터페이스 AB.method();

andThen()메소드는 대부분의 함수적 인터페이스에서 제공한다. compose()는 안지원해는데가 많음... 

Consumer의 순차적 연결
Consumer 종류의 함수적 인터페이스는 처리 결과를 리턴하지 않기 때문에 
andThen()과 compose()디폴트 메소드는 함수적 인터페이스의 호출 순서만 정한다. 

Function 의 순차적 연결 
Function 과 Operator종류의 함수적 인터페이스는 먼저 실행한 함수적 인터페이스의 결과를 
다음 함수적 인터페이스의 매개값으로 넘겨주고, 최종 처리 결과를 리턴한다. 

--------------------------------------------------------------------
and(),or(),negate() 디폴트 메소드와 isEqual() 정적 메소드
<Predicate 함수적 인터페이스의 디폴트 메소드 >

and(): &&과 대응, 두 Predicate 가 모두 true를 리턴하면, 최종적으로 true를 리턴
PredicateAB = predicateA.and(predicateB);

or(): ||과 대응, 두 Predicate 중 하나만 true를 리턴하면, 최종적으로 true를 리턴
PredicateAB = predicateA.or(predicateB);

negate(): !과 대응, Predicate의 결과가 true면 false, false면 true를 리턴한다. 
PredicateAB = predicateA.negate();


<isEqual() 정적 메소드 >
Predicate<T>의 정적 메소드 

Predicate<Object> predicate = Predicate.isEqual(targetObject);
boolean result = predicate.test(sourceObject); 

--> 여기서 Objects.equals(sourceObject,targetObject) 가  실행된다. 
Objects.equals(sourceObject,targetObject)는 다음과 같은 리턴값을 제공한다. 

source 			target				리턴값
null			null				true
not null		null				false
null			not null			false
not null		not null			sourceObject.equals(targetObject)의 리턴값  


<minBy(), maxBy() 정적 메소드>
BinaryOperator<T> 함수적 인터페이스의 정적 메소드
Comparator를 이용해서 최대 T와 최소 T를 얻는 BinaryOperator<T>를 리턴한다. 

Comparator<T>는 다음과 같이 선언된 함수적 인터페이스이다. o1과 o2를 비교해서 o1이 작으면 
음수를, o1과 o2가 동일하면 0, o1이 크면 양수를 리턴해야 하는 compare() 메소드가 선언되어 있다. 

@FunctionalInterface 
public interface Comparator<T>{
	public int compare(T o1, T o2);
}

그러므로 Comparator<T>를 타겟 타입으로 하는 람다식은 다음과 같이 작성할 수 있다. 
(o1,o2) -> {...; return int 값}

만약 o1과 o2가 int 타입이라면 다음과 같이Integer.compare(int,int) 메소드를 이용할 수 있다. 
(o1,o2) -> Integer.compare(o1,o2);

  



*/

 

/*



<메소드 참조> 
메소드를 참조해서 매개변수의 정보 및 리턴타입을 알아내어 람다식에서 불필요한 매개변수를
제거하는 것이 목적이다. 
종종 람다식은 기존 메소드를 단순하게 호출만  하는 경우가 있다. 

메소드 참조도 람다식과 마찬가지로 인터페이스의 익명 구현 객체로 생성된다.
타겟 타입에서 추상 메소드의 매개변수 및 리턴타입에 따라 매개변수 참조도 달라진다. 

정적 메소드 참조
클래스 :: 메소드

인스턴스 메소드 참조
참조변수 :: 메소드 

<매개변수의 메소드 참조 >
(a,b) -> {a.instanceMethod(b);}
클래스 :: instanceMethod
는 같다. 


<생성자 참조>
(a,b) -> {return new 클래스(a,b);}
클래스 :: new 
는 같다. 



*/

 

 

Consumer

 

 

Supplier

 

 

Function

 

 

Operator

 

 

 

Predicate

 

 

 

 

 

 

 

반응형