728x90
★ 함수와 메서드 차이
  - 메서드 : 클래스 안에 종속
  - 함수는 클래스에 독립적


★ 람다식
  - 함수(메서드)를 간단한 식으로 표현하는 방법
  - 익명 객체 , 익명 클래스

1. 메서드의 반환타입과 이름 제거하고 ->를 {} 앞에 추가
2. 반환값이 있는경우 식이나 값만 적고 return 생략가능 ; 안붙임
3. 매개변수의 타입이 추론가능하면 생략가능
   단 매개변수가 하나인경우 타입이 없을때만 생략가능
4. 블록안의 문장이 하나뿐일때 {} 생략가능 ; 안붙임

int max ( int a , int b ){  return a }

1. ( int a , int b ) -> {  return a; }  
2. (int a , int b ) -> a
3. ( a , b ) -> a
   (int a) -> a * a   ( O )
   (a) -> a * a   ( 에러 )
4. ( int i ) -> System.out.println(i)
 
 
 
public class hello {
	public static void main(String[] args) {
		
//		MyFunction f = new MyFunction() { 
//			public int max(int a, int b) { // 오버라이딩 - 접근제어자는 좁게 못바꾼다.
//				return a > b ? a : b;
//			} 
//		};
		 
		MyFunction f = ( a , b ) -> a > b ? a : b; // 람다식, 익명객체
		 
		// Object 에는 max 라는 메소드가 없어서 형변환이 불가능.
        // 함수형 인터페이스 필요 
		int value = f.max(3,5); // 함수형 인터페이스
		System.out.println("Value = " + value );
	}
}

@FunctionalInterface // 함수형 인터페이스는 단 하나의 추상메서드만 가져야함
interface MyFunction {
	//public abstract int max( int a , int b ); // public abstract 생략 가능 
	int max( int a , int b );
}
 
 
@FunctionalInterface   // 함수형 인터페이스는 단 하나의 추상메서드만 가져야함
interface MyFunction {
	void run();  // public abstract void run();
}

class Ex14_1 {
	static void execute(MyFunction f) { // 매개변수의 타입이 MyFunction인 메서드
		f.run();
	}

	static MyFunction getMyFunction() { // 반환 타입이 MyFunction인 메서드 
		MyFunction f = () -> System.out.println("f3.run()");
		return f;
	}

	public static void main(String[] args) {
		// 람다식으로 MyFunction의 run()을 구현
		MyFunction f1 = ()-> System.out.println("f1.run()");

		MyFunction f2 = new MyFunction() {  // 익명클래스로 run()을 구현
			public void run() {   // public을 반드시 붙여야 함 
                                  // 오버라이딩 - 접근제어자는 좁게 못바꾼다.
				System.out.println("f2.run()");
			}
		};

		MyFunction f3 = getMyFunction();

		f1.run();
		f2.run();
		f3.run(); 
		execute(f1);
		execute( ()-> System.out.println("run()") );
	}
}

// 결과
// f1.run()
// f2.run()
// f3.run()
// f1.run()
// run() 
 
 
★ java.util.function 패키지
★ 매개변수가 하나인 함수형 인터페이스
Runnable
void run()
매개변수 x , 반환값 x
Supplier<T>
Supplier< 출력 >
T get()
매개변수 x , 반환값 o
Consumer<T>
void accept( T t )
매개변수 o , 반환값 x
Function<T,R>
R apply ( T t )
일반적인 함수 , 하나의 매개변수를 받아서 결과 반환
Predicate<T>
boolean test( T t )
조건식 표현에 사용, 매개변수 하나, 반환타입 boolean
★ 매개변수가 두개인 함수형 인터페이스
Consumer<T , U>
void accept( T t , U u)
매개변수 o , 반환값 x
Function<T, R>
Function< 입력 , 출력 >
R apply ( T t , U u )
일반적인 함수 , 두개의 매개변수를 받아서 결과 반환
Predicate<T , U>
boolean test( T t , U u )
조건식 표현에 사용, 매개변수 둘, 반환타입 boolean
★ 매개변수 타입과 반환타입이 일치하는 함수형 인터페이스
UnaryOperator<T>
T apply( T t )
Function의 자손 , 매개변수와 결과의 타입이 같다
BinaryOperator<T>
T apply( T t , T t)
BiFunction의 자손, 매개변수와 결과의 타입이 같다

 

import java.util.function.*;
import java.util.*;

class Ex14_2 {
	public static void main(String[] args) {
		Supplier<Integer>  s = ()-> (int)(Math.random()*100)+1;
		Consumer<Integer>  c = i -> System.out.print(i+", "); 
		Predicate<Integer> p = i -> i%2==0; 
		Function<Integer, Integer> f = i -> i/10*10; // i의 일의 자리를 없앤다.
		
		List<Integer> list = new ArrayList<>();	
		makeRandomList(s, list); 
		System.out.println("리스트: " + list);		
		printEvenNum(p, c, list);
		
		List<Integer> newList = doSomething(f, list);
		System.out.println(newList);
	}
    
	//Function<Integer, Integer> f = i -> i/10*10; // i의 일의 자리를 없앤다.
	static <T> List<T> doSomething(Function<T, T> f, List<T> list) {
		List<T> newList = new ArrayList<T>(list.size());

		for(T i : list) {
			newList.add(f.apply(i)); // 일의 자리를 없애서 새로운 list에 저장
		}	
		return newList;
	}
	
	//Consumer<Integer>  c = i -> System.out.print(i+", "); 
	//Predicate<Integer> p = i -> i%2==0; 
	static <T> void printEvenNum(Predicate<T> p, Consumer<T> c, List<T> list) {
		System.out.print("printEvenNum : [");
		for(T i : list) {
			if(p.test(i)) // Predicate :: 짝수인지 검사
				c.accept(i); // Consumer :: 화면에 i 출력
		}	
		System.out.println("]");
	}

	static <T> void makeRandomList(Supplier<T> s, List<T> list) {
		for(int i=0;i<10;i++) {
			list.add(s.get()); //Supplier로 부터 1~100의 난수를 받아서 list에 넣음
		}
	}
}
 
import java.util.function.*;

class Ex14_3 {
	public static void main(String[] args) {
		Function<String, Integer>	f  = (s) -> Integer.parseInt(s, 16);
		Function<Integer, String>	g  = (i) -> Integer.toBinaryString(i);

		Function<String, String>    h  = f.andThen(g); // f 와 g를 결합
		Function<Integer, Integer>  h2 = f.compose(g); // g 와 f를 결합

		System.out.println(h.apply("FF")); // "FF" → 255 → "11111111"
		System.out.println(h2.apply(2));   // 2 → "10" → 16

		Function<String, String> f2 = x -> x; // 항등 함수(identity function)
		System.out.println(f2.apply("AAA"));  // AAA가 그대로 출력됨

		Predicate<Integer> p = i -> i < 100;
		Predicate<Integer> q = i -> i < 200;
		Predicate<Integer> r = i -> i%2 == 0;
		Predicate<Integer> notP = p.negate(); // i >= 100

		Predicate<Integer> all = notP.and(q.or(r));
		System.out.println(all.test(150));       // true

		String str1 = "abc";
		String str2 = "abc";
		
		// str1과 str2가 같은지 비교한 결과를 반환
		Predicate<String> p2 = Predicate.isEqual(str1); 
		boolean result = p2.test(str2);   
		System.out.println(result);
	}
}
 

함수형 인터페이스를 사용하는 컬렉션 프레임웍의 메서드( 와일드 카드 생략 )

 

 

★ List forEach 

List와 같은 Collection에서 forEach()는 
다음과 같이 Consumer라는 함수형 인터페이스를 인자로 받습니다. 
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

Consumer는 1개의 인자를 받고 리턴 값이 없는 함수형 인터페이스입니다.
default void forEach(Consumer<? super T> action) {
    for (T t : this) {
        action.accept(t);
    }
}

Cosumer 객체를 forEach에 전달하여 List의 모든 아이템을 순회할 수 있습니다.
List<String> items = new ArrayList<>();
items.add("Paris");
items.add("Seoul");
items.add("Tokyo");
items.add("Washington");

:: items.forEach(name -> System.out.println(name));
items.forEach(new Consumer<String>() {
    @Override
    public void accept(String name) {
        System.out.println(name);
    }
});
 
★ Set forEach
Set<String> set = new HashSet<>();
set.add("Paris");
set.add("Seoul");
set.add("Tokyo");
set.add("Washington");

set.forEach(item -> System.out.println(item));
 
★ Map forEach

Map.forEach()는 다음과 같이 BiConsumer라는 함수형 인터페이스를 인자로 받습니다.
default void forEach(BiConsumer<? super K, ? super V> action) {
    Objects.requireNonNull(action);
    for (Map.Entry<K, V> entry : entrySet()) {
        K k = entry.getKey();
        V v = entry.getValue();
        action.accept(k, v);
    }
}

BiConsumer는 두개의 인자를 받고 리턴 값은 없는 함수형 인터페이스입니다.
@FunctionalInterface
public interface BiConsumer<T, U> {
    void accept(T t, U u);
}

BiConsumer 객체를 인자로 전달하여 Map의 모든 아이템을 순회할 수 있습니다. 
Map<String, String> map = new HashMap<>();
map.put("Paris", "France");
map.put("Seoul", "Korea");
map.put("Tokyo", "Japan");
map.put("Washington", "USA");

:: map.forEach((k, v) -> {  System.out.println("key: " + k + ", value: " + v); });
map.forEach((new BiConsumer<String, String>() {
    @Override
    public void accept(String k, String v) {
        System.out.println("key: " + k + ", value: " + v);
    }
}));
 
★ Map.entrySet()에 대한 forEach

Map<String, String> map = new HashMap<>();
map.put("Paris", "France");
map.put("Seoul", "Korea");
map.put("Tokyo", "Japan");
map.put("Washington", "USA");

map.entrySet().forEach(entry -> {
    System.out.println("key: " + entry.getKey()
            + ", value: " + entry.getValue());
});
 
★ Array forEach

String[] array = {"Paris", "Seoul", "Tokyo", "Washington"};
Arrays.stream(array).forEach(item -> System.out.println(item));
 

★ Static 메서드 참조  
 - 람다식을 더 간단히 표현한것
 - 클래이름 :: 메서드 이름

::  Function<String , Integer> f = (String s) -> Integer.parseInt(s);  
::  입력이 String 이라는건 Function<String , Integer> 에 정의되어 있으니 < 입력 , 출력 >
::  (String s) 생략 가능하고 Function<String , Integer> f = 클래스 이름::메서드이름
::  Integer.parseInt(s); ==> 클래스 이름::메서드이름 		 
Function<String , Integer> f = Integer::parseInt; // 메서드 참조
System.out.println(f.apply("100") + 200 );


★ 생성자의 메서드 참조
Supplyer<MyClass> s = () -> new MyClass();  
   >>  Supplyer<MyClass> s = MyClass::new;
Function<Integer,MyClass> s = (i) -> new MyClass(i); 
   >> Function<Integer,MyClass> s = MyClaass::new;
Function<Integer , int[]> f = x -> new int[x];
   >> Function<Integer , int[]> f2 = int[]::new;
 
import java.util.function.Function;
import java.util.function.Supplier;

public class hello {
	public static void main(String[] args) { 
		
		// Supplier<MyClass> s = () -> new MyClass();
		Supplier<MyClass> s = MyClass::new;  
		System.out.println("Supplier :: " + s.get());
		
		// Function<Integer , MyClass> s2 = (i) -> new MyClass();
		Function<Integer , MyClass2> s2 = MyClass2::new;  
		System.out.println("Function :: " +  s2.apply(200).iv);
		
		// 배열 길이를 주어야 배열 생성이 가능
		// Function<Integer , int[]> f = (i) -> new int[i];
		Function<Integer , int[]> f = int[]::new;
		System.out.println( f.apply(100).length );
	}
}

class MyClass{}
class MyClass2{
	int iv;
	MyClass2( int iv){
		this.iv = iv;
	} 
}
 

 

 

728x90

+ Recent posts