람다?
- 코드 블록
- 기존의 코드 블록은 메소드를 -> 메소드를 사용하기 위해 익명 객체를 만들거나 하는 식
- 하지만 자바 8부터는 람다를 이용하여 코드 블록 생성 가능
- 코드 블록을 변수처럼 사용 가능!
함수형 인터페이스를 람다식으로 변경
- 함수형 인터페이스란?
- 추상 메소드를 하나만 갖는 인터페이스
- ex) Runnable 인터페이스 -> run() 추상 메소드 하나만 갖음
- 기존 방식의 코드 블록 사용 : 별도의 클래스와 객체 그리고 메소드를 생성해야 한다.
- 기존의 코드 방법 : 객체 생성 -> 이용
package book;
public class Test1 {
public static void main(String[] args) {
MyTest mt=new MyTest();
Runnable r=mt;
r.run();
}
}
class MyTest implements Runnable {
@Override
public void run() {
System.out.println("Hello Lambda");
}
}
package book;
public class Test2 {
public static void main(String[] args) {
Runnable r =new Runnable() {
@Override
public void run() {
System.out.println("Hello Lambda 2");
}
};
r.run();
}
}
- 익명 객체 없이 람다를 이용하여 코드 블록만 사용
- 가능한 이유?!
- Runnable 타입으로 참조 변수 r을 만들고 있기 때문에 굳이 new Runnable()을 사용할 필요 없음.
- run ( ) 메소드 -> ( )로 변경 : 이유는 Runnable 인터페이스가 가진 추상 메소드가 run () 메소드 하나 이기 때문에
package book;
public class Test3 {
public static void main(String[] args) {
Runnable r=() -> {
System.out.println("Hello lambda 3");
};
r.run();
}
}
- 더 짧게?! 코드 안에 들어가는 로직이 1줄이기 때문에 { } 생략가능
package book.chapter01.interfaceFunction;
public class Test4 {
public static void main(String[] args) {
Runnable r =()-> System.out.println("lambda 4");
r.run();
}
}
람다 구조
나만의 인터페이스를 이용해서 람다로 변경
package book.chapter02.myInterfaceFunction;
public class Test1 {
public static void main(String[] args) {
MyFunctionInterface m1=(int a) -> {return a*a;};
int b=m1.runSomething(5);
System.out.println(b);
}
}
@FunctionalInterface
interface MyFunctionInterface {
public abstract int runSomething(int count);
}
- Main 함수에 부분을 더 줄일수 있을까?!
- int가 들어가는 것을 알기 때문에 (인터페이스에서) 따라서 int 생략 가능
- 인자 1개가 필요함으로 a를 쓴다!
- runSomething부분에 인자가 int인것을 알기 때문에 return 부분 생략 가능
- 코드가 1줄이기 때문에 { } 생략 가능
package book.chapter02.myInterfaceFunction;
public class Test2 {
public static void main(String[] args) {
MyFunctionInterface mf1=a->a*a;
int b=mf1.runSomething(6);
System.out.println(b);
}
}
메소드 호출 인자 & Return 람다 사용
- 지금까지는 람다식을 함수형 인터페이스의 참조 변수에 저장해서 사용
- 람다식을 변수에 저장하는 것이 가능하다면 당연히 메서드의 인자로도 사용 가능
package book.chapter02.myInterfaceFunction;
public class Test3 {
public static void main(String[] args) {
MyFunctionInterface mf1=a->a*a;
doIt(mf1);
}
public static void doIt(MyFunctionInterface mf1) {
int b=mf1.runSomething(5);
System.out.println(b);
}
}
- 람다식을 1번만 사용한다면 참조변수를 만들 필요도 없다!
package book.chapter02.myInterfaceFunction;
public class Test4 {
public static void main(String[] args) {
doIt(a->a*a);
}
public static void doIt(MyFunctionInterface mf1) {
int b=mf1.runSomething(5);
System.out.println(b);
}
}
package book.chapter02.myInterfaceFunction;
public class Test5 {
public static void main(String[] args) {
MyFunctionInterface mf1=todo();
int result=mf1.runSomething(5);
System.out.println(result);
}
public static MyFunctionInterface todo() {
return num->num*num;
}
}
자바 8 API에서 제공하는 대표적인 함수형 인터페이스
함수형 인터페이스 | 추상 메소드 | 용도 |
---|
Runnable | void run() | 실행할 수 있는 인터페이스 |
Supplier<T> | T get() | 제공할 수 있는 인터페이스 |
Consumer | void accepnt(T t) | 소비(출력)할수 있는 인터페이스 |
Predeicate<T> | Boolean test(T t) | 입력을 받아 참/거짓을 단정 인터페이스 |
UnaryOperator<T> | T apply(T t) | 단항(Unary)연산을 할 수 있는 인터페이스 |
package book.chapter03.java8FunctionInterface;
import java.util.Arrays;
import java.util.List;
import java.util.function.*;
public class Test1 {
public static void main(String[] args) {
Runnable run=()-> System.out.println("hello");
run.run();
Supplier<Integer>sup=()->3*3;
int m=sup.get();
System.out.println(m);
Consumer<Integer> con=num -> System.out.println(num);
con.accept(3);
Consumer<String> sCon=s-> System.out.println(s.toUpperCase());
sCon.accept("hello lambda");
Consumer<String>consumer =s-> System.out.println(s.toUpperCase());
List<String> list= Arrays.asList("abc","def","kgh");
list.forEach(consumer);
Function<Integer, String>fun=num->"input: "+num;
String result=fun.apply(10);
System.out.println(result);
Predicate<Integer> pre=num->num>10;
boolean res=pre.test(100);
System.out.println(res);
UnaryOperator<Integer> uOp=num->num*num;
int k=uOp.apply(100);
System.out.println(k);
}
}
컬렉션 스트림에서 람다 사용
package book.chapter03.java8FunctionInterface;
public class Test2 {
public static void main(String[] args) {
Integer []ages={20,25,18,27,30,21,17,19,34,28};
for (int age :ages) {
if (age<20) {
System.out.format("Age %d Can't enter\n",age);
}
}
}
}
- 컬렉션을 스트림을 이용한 방법의 장점
- 선언적 프로그래밍
- 의사소통 내용 자체가 그대로 코드로 구현되는 것
- SQL 처럼 where 절과 같은 역할을 수행 가능
package book.chapter03.java8FunctionInterface;
import java.util.Arrays;
public class Test3 {
public static void main(String[] args) {
Integer []ages={20,25,18,27,30,21,17,19,34,28};
Arrays.stream(ages)
.filter(age->age<20)
.forEach(age->System.out.format("Age %d Can't enter\n",age));
}
}
- Stream은 Collections Stream을 다른 컬렉션 스트림으로 변경 가능
- mapToInt / mapToDouble / mapToLong
- Stream에서 Integer를 int로 변경
- Integer를 double로 변경
- Integer를 Long으로 변경
- sum, count, average, min, max 뿐만 아니라 집계 함수도 사용 가능
package book.chapter03.java8FunctionInterface;
import java.util.Arrays;
public class Test4 {
public static void main(String[] args) {
Integer []ages={20,25,18,27,30,21,17,19,34,28};
int []test=Arrays.stream(ages).mapToInt(age->age).toArray();
double []dTest=Arrays.stream(ages).mapToDouble(age->age).toArray();
Arrays.stream(test).forEach(System.out::println);
System.out.println(Arrays.stream(ages).count());
System.out.println(Arrays.stream(ages).mapToInt(age->age).sum());
System.out.println(Arrays.stream(ages).mapToInt(age->age).average());
System.out.println(Arrays.stream(ages).mapToInt(age->age).min());
System.out.println(Arrays.stream(ages).mapToInt(age->age).max());
System.out.println(Arrays.stream(ages).allMatch(age->age>20));
System.out.println(Arrays.stream(ages).anyMatch(age->age>20));
System.out.println(Arrays.stream(ages).findFirst());
System.out.println(Arrays.stream(ages).findAny());
Arrays.stream(ages).sorted().forEach(System.out::println);
}
}
메소드 레퍼런스와 생성자 레퍼런스
메소드 레퍼런스란?!
- 간략한 형식으로 변경하여 사용하는것
- 인스턴스::인스턴스메소드
- 클래스::정적메소드
- 클래스::인스턴스멘소드
package book.chapter03.java8FunctionInterface;
import java.util.Arrays;
import java.util.function.BiFunction;
public class Test5 {
public static void main(String[] args) {
Double[]nums={1.0,4.0,9.0,16.0,25.0};
Arrays.stream(nums)
.map(num->Math.sqrt(num))
.forEach(sqrtNum-> System.out.println(sqrtNum));
Arrays.stream(nums)
.map(Math::sqrt)
.forEach(System.out::println);
BiFunction<Integer, Integer, Integer>bip_lambda=(a,b)->a.compareTo(b);
BiFunction<Integer,Integer,Integer>bip_method_reference=Integer::compareTo;
}
}
생성자 레퍼런스
package book.chapter03.java8FunctionInterface;
import java.util.function.Supplier;
public class Test6 {
public static void main(String[] args) {
Test6 test=new Test6();
Supplier<Test6> tt=Test6::new;
Test6 test1=tt.get();
Test6 test2=tt.get();
System.out.println(test.hashCode());
System.out.println(test1.hashCode());
System.out.println(test2.hashCode());
}
}