이 노트는 "윤성우의 열혈 java 프로그래밍" 책을 공부하면서
내가 이해한대로 다시 정리하면서 작성되었다.
자바를 기초부터 하나하나 체화하려고 정리하면서 공부하다 보니 진도가 늦은 것이 사실이다 ㅠ
그래도 끝까지 포기하지 않고 자바를 정복해보려 노력하겠다 🥲
자바는 객체지향 언어이다. 코드의 흐름 대부분에 클래스와 인스턴스가 존재한다.
하지만 프로그램을 작성하다 보면 "기능 하나를 정의해서 전달해야 하는 상황"이 존재한다.
그럴때 람다를 사용하면 좀 더 간결한 코드를 만들 수 있다.
interface Printable {
void print(String s); // 매개변수 하나, 반환형 void
}
class OneParamNoReturn {
public static void main(String[] args) {
Printable p;
p = (String s) -> {System.out.println(s);}; // 줄임이 없는 표현
p.print("Lambda exp one.");
p = (String s) -> System.out.println(s); // 중괄호 생략
p.print("Lambda exp two.");
p = (s) -> System.out.println(s); // 매ㅐ개변수 형 생략
p.print("Lambda exp three.");
p = s -> System.out.println(s); // 매개변수 소괄호 생략
p.print("Lambda exp four.");
}
}
interface Calculate {
void cal(int a, int b); // 매개변수 둘, 반환형 void
}
class TwoParamNoReturn {
public static void main(String[] args) {
Calculate c;
c = (a, b) -> System.out.println(a + b);
c.cal(4, 3);
c = (a, b) -> System.out.println(a - b);
c.cal(4, 3);
c = (a, b) -> System.out.println(a * b);
c.cal(4, 3);
}
}
interface Calculate {
int cal(int a, int b); // 값을 반환하는 추상 메소드
}
class TwoParamAndReturn {
public static void main(String[] args) {
Calculate c;
c = (a, b) -> { return a + b; };
System.out.println(c.cal(4, 3));
c = (a, b) -> a + b;
System.out.println(c.cal(4, 3));
}
}
return
문이면 문장이 하나더라고 중괄호 생략이 불가능하다.return
문이 메소드 몸체를 이루는 유일한 문장이면 (a, b)->a+b
와 같이 작성할 수 있다.interface HowLong {
int len(String s); // 값을 반환하는 메소드
}
class OneParamAndReturn {
public static void main(String[] args) {
HowLong hl = s -> s.length();
System.out.println(hl.len("I am so happy"));
}
}
매개변수가 없는 람다식은 매개변수를 표현하는 소괄호 안을 비우면 된다.
interface Generator {
int rand(); // 매개변수 없는 메소드
}
class NoParamAndReturn {
public static void main(String[] args) {
Generator gen = () -> {
Random rand = new Random();
return rand.nextInt(50);
};
System.out.println(gen.rand());
}
}
인터페이스에 추상 메소드가 딱 하나만 존재하는 것을 함수형 인터페이스라고 한다.
람다식은 이런 함수형 인터페이스를 기반으로만 작성될 수 있다.
@FunctionalInterface
interface Calculate {
int cal(int a, int b);
}
FunctionalInterface
은 함수형 인터페이스에 부합하는지를 확인하기 위한 어노테이션 타입이다.둘 이상의 추상 메소드가 존재하면 함수형 인터페이스가 아니기 때문에 에러를 낸다.
하지만 static, default 선언이 붙은 메소드 정의는 함수형 인터페이스의 정의에 아무런 영향을 미치지 않는다.
인터페이스는 제네릭으로 정의할 수 있다.
다음은 제네릭으로 정의된 함수형 인터페이스를 대상으로 하는 람다식이다.
@FunctionalInterface
interface Calculate <T> { // 제네릭 기반의 함수형 인터페이스
T cal(T a, T b);
}
class LambdaGeneric {
public static void main(String[] args) {
Calculate<Integer> ci = (a, b) -> a + b;
System.out.println(ci.cal(4, 3));
Calculate<Double> cd = (a, b) -> a + b;
System.out.println(cd.cal(4.32, 3.45));
}
}
default boolean removeIf(Predicate<? super E> filter)
Collection<E>
인터페이스에 정의된 디폴트 메소드 중 하나인 removeIf 메소드이다.다음과 같이 정의되어 있는 제네릭 인터페이스이자 함수형 인터페이스이다.
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
이렇게 자바에서는 메소드의 반환형과 매개변수 선언에 차이를 둔 다양한 인터페이스들을 표준으로 정의하고 있다.
Predicate<T>
- boolean test(T t)
Supplier<T>
- T get()
Consumer<T>
- void accept(T t)
Funtion<T, R>
- R apply(T t)
Predicate<T>
boolean test(T t);
전달된 인자를 대상으로 true, false를 반환해야하는 상황에 유용하게 사용된다.
import java.util.List;
import java.util.Arrays;
import java.util.function.Predicate;
class PredicateDemo {
public static int sum(Predicate<Integer> p, List<Integer> lst) {
int s = 0;
for(int n : lst) {
if(p.test(n))
s += n;
}
return s;
}
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 5, 7, 9, 11, 12);
int s;
s = sum(n -> n%2 == 0, list);
System.out.println("짝수 합: " + s);
s = sum(n -> n%2 != 0, list);
System.out.println("홀수 합: " + s);
}
}
public static int sum(Predicate<Integer> p, List<Integer> lst)
에서 매개변수 선언을 볼 때 boolean test(Integer t) 메소드 정의에 해당하는 람다식을 작성해서 전달해야한다.Supplier<T>
T get();
단순히 무언가를 반환해야 할 때 사용된다.
class SupplierDemo {
public static List<Integer> makeIntList(Supplier<Integer> s, int n) {
List<Integer> list = new ArrayList<>();
for(int i = 0; i < n; i++)
list.add(s.get());
return list;
}
public static void main(String[] args) {
Supplier<Integer> spr = () -> {
Random rand = new Random();
return rand.nextInt(50);
};
List<Integer> list = makeIntList(spr, 5);
System.out.println(list);
list = makeIntList(spr, 10);
System.out.println(list);
}
}
public static List<Integer> makeIntList(Supplier<Integer> s, int n)
메소드는 정수를 담고 있는 컬렉션 인스턴스르 반환한다.Consumer<T>
void accept(T t);
전달 인자를 소비하는 령태로 매개변수와 반환형이 선언되어 있다.
(인자는 전달 받지만 반환하지 않는다.)
전달된 인자를 가지고 어떤 결과를 보여야 할 때 유용하게 사용된다.
import java.util.function.Consumer;
class ConsumerDemo {
public static void main(String[] args) {
Consumer<String> c = s -> System.out.println(s);
c.accept("Pineapple"); // 출력이라는 결과를 보인다.
c.accept("Strawberry");
}
}
Funtion<T, R>
R apply(T t);
전달한 인자와 반환 값이 모두 존재하는 가장 보편적인 형태이다.
default boolean removeIf(Predicate<? super E> filter)
Predicate<? super E>
를 보면 ArrayList<Integer>
인스턴스를 생성하면, 그 안에 존재하는정리중 ✍️