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