Written by
Poogle
on
on
2021.08.04 TIL
새롭게 배운 것 Done
운동
- 오전 러닝 3km
독서
알고리즘
코딩
인터페이스
- 기능
- 구현을 강제
- 다형성 제공
- 결합도를 낮춤(의존성을 역전시킴)
- Java8 에서는?
default
: 구현한 메서드도 interface에 넣을 수 있음 -> override 안해도 됨- 인터페이스가 변경될 때 구현하고 있는 모든 클래스들이 해당 메서드를 구현해야 함 -> default로 하면 할 필요 X
- Adapter의 역할을 해줌
- 기능 확장
static
메서드 추가 가능: 유틸성 -> 캐리어 역할, 인터페이스가 뭔가를 하는건 아니고 메서드를 들고 있으면서 함수 제공자가 됨- 여기서 함수라고 하는 이유는 클래스 안에 있는 함수를 메서드라고 함, 인터페이스 -> 함수 제공자
함수형 인터페이스(Functional Interface)
- 추상 메서드를 딱 하나만 가지고 있는 인터페이스
- 인터페이스임에도 static 메서드를 가질 수 있고 default 메서드도 가질 수 있음
- 추상 메서드만 하나 있으면 된다
- SAM (Single Abstract Method) 인터페이스
@FuncationInterface
애노테이션 을 가지고 있는 인터페이스 → 애노테이션 있으면 추상 메서드가 여러 개 있을 때 컴파일 에러가 난다@FunctionalInterface public interface RunSomething { void doIt(); }
자바에서 미리 정의해둔 자주 사용할만한 함수 인터페이스
- Function<T, R>
- T 타입을 받아서 R 타입을 리턴하는 함수 인터페이스
- R apply(T t)
- 함수 조합용 메소드
- andThen
- compose
import java.util.function.Function; public class StringCalculator { public static void main(String[] args) { Function<Integer, Integer> plus10 = (number) -> number + 10; Function<Integer, Integer> multiply2 = (number) -> number * 2; //입력값을 가지고 ()안을 미리 실행 후 그 후 return 값을 가지고 전자의 함수의 매개변수로 사용 plus10.compose(multiply2); } }
import java.util.function.Function; public class StringCalculator { public static void main(String[] args) { Function<Integer, Integer> plus10 = (number) -> number + 10; Function<Integer, Integer> multiply2 = (number) -> number * 2; //앞을 먼저 System.out.println(plus10.andThen(multiply2).apply(10)); } }
- BiFunction<T, U, R>
- 두 개의 값(T, U)를 받아서 R 타입을 리턴하는 함수 인터페이스
- R apply(T t, U u)
- 두 개의 값(T, U)를 받아서 R 타입을 리턴하는 함수 인터페이스
- Consumer
- T 타입을 받아서 아무값도 리턴하지 않는 함수 인터페이스
- void Accept(T t)
- 함수 조합용 메소드
- andThen
import java.util.function.Consumer; public class StringCalculator { public static void main(String[] args) { Consumer<Integer> printT = (i) -> System.out.println(i); printT.accept(10); } }
- T 타입을 받아서 아무값도 리턴하지 않는 함수 인터페이스
- Supplier
- T 타입의 값을 제공하는 함수 인터페이스
- T get()
import java.util.function.Supplier; public class StringCalculator { public static void main(String[] args) { Supplier<Integer> get10 = () -> 10; System.out.println(get10); } }
- T 타입의 값을 제공하는 함수 인터페이스
- Predicate
- T 타입을 받아서 boolean을 리턴하는 함수 인터페이스
- boolean test(T t)
- 함수 조합용 메소드
- And
- Or
import java.util.function.Predicate; public class StringCalculator { public static void main(String[] args) { Predicate<String> startsWithKeesun = (s) -> s.startsWith("keesun"); Predicate<Integer> isEven = (i) -> i % 2 == 0; } }
- T 타입을 받아서 boolean을 리턴하는 함수 인터페이스
- UnaryOperator
- Function<T, R>의 특수한 형태로, 입력값 하나를 받아서 동일한 타입을 리턴하는 함수 인터페이스
import java.util.function.UnaryOperator; public class StringCalculator { public static void main(String[] args) { UnaryOperator<Integer> plus10 = (i) -> i + 10; UnaryOperator<Integer> multiply2 = (i) -> i * 2; } }
- BinaryOperator
- BiFunction<T, U, R>의 특수한 형태로, 동일한 타입의 입력값 두개를 받아 리턴하는 함수 인터페이스
익명 클래스
- 인터페이스 매번 구현체 만들어서 그 안에있는 메서드 쓰기 힘들지 않나?
- ⏩ 익명 클래스 (인터페이스 임시 생성하기 인터페이스의 인스턴스를 생성하고 구현을 바로 정의)
- 함수형 인터페이스에 있는 메서드 하나밖에 없음 -> 당연 그 메서드 쓰겠지 -> 줄임
(인자 리스트) -> {바디}
람다
(인자 리스트) -> {바디}
- 인자 리스트
- 인자가 없을 때: ()
- 인자가 한개일 때: (one) 또는 one
- 인자가 여러개 일 때: (one, two)
- 인자의 타입은 생략 가능, 컴파일러가 추론(infer)하지만 명시할 수도 있다. (Integer one, Integer two)
- 바디
- 화살표 오른쪽에 함수 본문을 정의한다.
- 여러 줄인 경우에 { }를 사용해서 묶는다.
- 한 줄인 경우에 생략 가능, return도 생략 가능.
-
변수 캡쳐 Variable Capture
package stringcalculator; import java.util.function.Consumer; import java.util.function.IntConsumer; import java.util.function.UnaryOperator; public class StringCalculator { public static void main(String[] args) { StringCalculator sc = new StringCalculator(); sc.run(); } private void run() { final int baseNumber = 10; // 로컬 클래스 class LocalClass { void printBaseNumber() { System.out.println(baseNumber); } } // 익명 클래스 Consumer<Integer> integerConsumer = new Consumer<Integer>() { @Override public void accept(Integer integer) { System.out.println(baseNumber); } }; // 람다 IntConsumer printInt = (i) -> { System.out.println(i + baseNumber); }; printInt.accept(10); } }
- 로컬, 익명 & 람다의 공통점 → baseNumber 변수를 참조할 수 있음
- java 8의 경우에는 final 생략 가능 (사실상 final)
-
로컬, 익명 // 람다의 차이점 → 쉐도윙 O // X
- 로컬 변수 캡처
- final이거나 effective final 인 경우에만 참조할 수 있다.
- 그렇지 않을 경우 concurrency 문제가 생길 수 있어서 컴파일러가 방지
- effective final
- 이것도 역시 자바 8부터 지원하는 기능으로 “사실상” final인 변수.
- final 키워드 사용하지 않은 변수를 익명 클래스 구현체 또는 람다에서 참조할 수 있다.
-
익명 클래스 구현체와 달리 ‘쉐도윙’하지 않는다.
package stringcalculator; import java.util.function.Consumer; import java.util.function.IntConsumer; import java.util.function.UnaryOperator; public class StringCalculator { public static void main(String[] args) { StringCalculator sc = new StringCalculator(); sc.run(); } private void run() { **int baseNumber = 10;** // 로컬 클래스 class LocalClass { **int baseNumber = 11; //쉐도윙** void printBaseNumber() { System.out.println(baseNumber); } } // 익명 클래스 Consumer<Integer> integerConsumer = new Consumer<Integer>() { @Override public void accept(Integer **baseNumber**) { //쉐도윙 System.out.println(baseNumber); } }; **// 람다 IntConsumer printInt = (baseNumber) -> { // 같은 scope -> 쉐도윙 X System.out.println(baseNumber); };** printInt.accept(10); } }
- 익명 클래스는 새로 스콥을 만들지만, 람다는 람다를 감싸고 있는 스콥과 같다.
- 참고
메서드 레퍼런스
- 람다 표현식에서 입력되는 값을 변경없이 바로 사용
- 스태틱 메서드 참조
타입::스태틱 메서드
Person::compareByAge
MethodReferencesExamples::appendStrings
- 특정 객체의 인스턴스 메서드 참조
객체 레퍼런스::인스턴스 메서드
myComparisonProvider::compareByName
- 임의 객체의 인스턴스 메서드 참조
타입::인스턴스 메서드
String::compareToIgnoreCase
String::concat
- 생성자 참조
타입::new
HashSet::new
- 메서드 또는 생성자의 매개변수로 람다의 입력값을 받음
- 리턴값 또는 생성한 객체는 람다의 리턴값
참고
강의 - 더 자바, Java 8
깨달은 점 FEELING
- 오전에 이틀에 한 번 꼴로 뛰고 있는데 유산소만 하고 있어서 어서 근력 운동도 하고 싶다. 근데 공복이라 뛰고 나서 근력운동까지 하려니 쉽지 않다.😂 유산소 - 근력 번갈아서 할까 생각중이다.
- 줌으로 코어타임 보낼 때 내가 내 얼굴을 자꾸 보게 되어서 그런지 피로감이 심해서 이번엔 허들을 사용했다. 덜 피곤한게 장점이라면 화면공유를 하지 않아서 집중력이 떨어지는 단점도 있는 것 같기도 하고…
- 인터페이스와 람다를 알고 있고 사용도 하고 있었는데 오늘 강의를 듣고 갑자기 단순히 외워서 알던 부분의 원리를 깨달았다. 생각이 갑자기 트인 느낌?
- TIL을 정리하면서 노션에만 정리했던 람다 내용을 블로그에 포스팅할 수 있게 됐다. 옮기면서 내 지식으로 만들기가 목표!!