모던 자바( 자바8) 못다한 이야기를 보고 정리한 것입니다.
Functional Interface로 java.util.function 패키지 안에 포함되어있다.
람다식의 타입과 형변환
인터페이스인데 abstract 메소드가 하나만 존재하는 경우
Functional interface 4종류
- Function 타입
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
apply 메소드 하나만 가지고 있음
입력값과 리턴값이 있어야한다.
functional interface 는 anonymous 클래스 필요없이 사용이 가능하다.
function type : function패키지 안에 들어있다.
같은 타입을 리턴하는 것을 identity라고 한다.
같은 타입 T -> R은 일반적인 함수
T- >T 는 identity 함수가 된다 . 그 타입을 받아서 그타입으로 바로 넘기게 되는것
//Parameter : T , Return Type : R
//Function <R,T> 하나의 메소드를 호출
Function<String, Integer> toInt = new Function<String, Integer>() {
@Override
public Integer apply(String value) {
return Integer.parseInt(value);
}
};
//lambda로 표현하면 ?
Function<String, Integer> toIntLamda = (value)->Integer.parseInt(value);
Integer number = toInt.apply("200");
System.out.println(number);
- Consumer
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
Accept
void 로 리턴값을 가지고 있음 값은 있고 리턴은 없다.
Ex) 리턴값이 없을경우, 출력
//Basic
//Consumer<T>
//Parameter : T , Return : void
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
//lambda
Consumer<String> consumer2 = (value)->System.out.println(value);
consumer.accept("20");
consumer2.accept("20");
- Predicate
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
결과 값은 항상 boolean 값
function 인데 파라미터 값은 T이고 리턴 타입은항상 boolean 으로 출력
//Basic
Predicate<Integer> isPositive = new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer >0;
}
};
System.out.println("is Positive ? "+isPositive.test(-1));
System.out.println("is Positive ? "+isPositive.test(2));
//응용
List<Integer> numbers = Arrays.asList(-5,-4,-3,-2,-1,0,1,2,3,4,5);
//조건
Predicate<Integer> isPositive2 = value -> value > 0;
List<Integer> positiveNumbers = new ArrayList<>();
for(Integer num : numbers){
if(isPositive2.test(num)){
positiveNumbers.add(num);
}
}
아래와 같이 자주쓰이는 filter 메서드를 만들어서 condition만 변경 해주는 방식으로도 사용이 가능하다.
public static <T> List<T> filter(List<T> list, Predicate<T> condition){
List<T> result = new ArrayList<>();
for(T element: list){
if(condition.test(element)){
result.add(element);
}
}
return result;
}
- Supplier
인자 값은 없고 return type만 존재한다.
일종의 lazy Evaliation 할 수 있다.
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
expensiveValue를 구하는 메서드를 일반 코드로 나타내면 아래와 같은 코드가 된다. 총 소요시간은 총 9초 이다.
long start = System.currentTimeMillis();
printIfValidIndex( 0, getVeryExpensiveValue());
printIfValidIndex( -1, getVeryExpensiveValue());
printIfValidIndex( -2, getVeryExpensiveValue());
System.out.println("Take Time : "+((System.currentTimeMillis()-start)/1000));
메서드 :
private static String getVeryExpensiveValue(){
try{
TimeUnit.SECONDS.sleep(3);
System.out.println("throw this area");
}catch(InterruptedException e){
e.printStackTrace();
}
return "Morris";
}
private static void printIfValidIndex( int number, String valueSupplier){
if(number >=0){
System.out.println("The value is "+ valueSupplier + ".");
}else {
System.out.println("InValid");
}
}
결과 값
getVeryExpensiveValue 메서드가 항상 실행 된다.
그래서 비싼 비용의 메서드가 계속 실행된다는 단점이 있다.
실행 순서는 getVeryExpensiveValue () -> printIfValidIndex -> condition
throw this area
The value is Morris.
throw this area
InValid
throw this area
InValid
Take Time : 9
lazy 하게 실행 할수 있는 supplier로 수정을 해보자
long start = System.currentTimeMillis();
printIfValidIndex( 0, () -> getVeryExpensiveValue());
printIfValidIndex( -1, () -> getVeryExpensiveValue());
printIfValidIndex( -2, () -> getVeryExpensiveValue());
System.out.println("Take Time : "+((System.currentTimeMillis()-start)/1000));
}
메서드
일반 코드에서 printIfValidIndex의 매개변수를 string에서 Supplier
private static String getVeryExpensiveValue(){
try{
TimeUnit.SECONDS.sleep(3);
System.out.println("throw this area");
}catch(InterruptedException e){
e.printStackTrace();
}
return "Morris";
}
private static void printIfValidIndex( int number, Supplier<String> valueSupplier){
if(number >=0){
System.out.println("The value is "+ valueSupplier.get() + ".");
}else {
System.out.println("InValid");
}
}
결과 값
throw this area
The value is Morris.
InValid
InValid
Take Time : 3
결과 값을 보면 3초 밖에 나오지 않는다 .
printIfValidIndex -> condition -> get을 하면 불러온다.
이렇게 알수 있는 것은 supplier를 사용하면 매개변수.get을 사용하는 시점에서 해당 메서드가 실행 되는 것을 알수 있다. 이렇게 하면 컴퓨팅 성능과 리소스를 줄일수 있을 것 같다.
'ProgramLanguage > Java' 카테고리의 다른 글
Java8- Default 메서드(Abstract, Interface) (0) | 2020.03.18 |
---|---|
JVM 튜닝 (0) | 2020.02.10 |
객체 지향 설계 5원칙 - SOLID (0) | 2019.12.26 |
Java 와 객체 지향 (0) | 2019.12.03 |
Java jar파일 만들기 (0) | 2019.08.04 |