Web/Java

Java Stream , Lambda만 보면 얼어버리는 사람의 예제코드 뿌시기 프로젝트

TLdkt 2022. 9. 13. 23:45
728x90
반응형

😂쇠사슬을 만들 때는...

어디선가 들은 얘기로는 쇠사슬 공정의 마지막은 '당겨보기'라고 했다. 꼭 전체 사슬을 당겨보는 검수를 한다는데, 각 고리에 대한 부하 테스트만 할 거라 생각했던 내게 묘한 깨달음을 준 이야기였다. 각 사슬이 아무리 압력에 강해도 사슬 간 연결부분이 약하면 제 목적을 달성하지 못하는 것이다. 하나하나는 안다고 생각해도 슬쩍 넘어갔던 부분들이 모여 나오면 당황하게 된다.. 그러니까 뿌셔보자!

 

🚀Stream method 목차 정리

더보기

Stream 생성

  • 컬렉션에서 Stream<T> intStream = list.stream()
  • 배열에서
  • 무한 스트림 -람다식
  • 파일 Files.list(디렉토리)
  • 빈 스트림
  • 두 스트림 연결 Stream.concat(strs1, strs2)

Stream 중간연산

  • 스트림 자르기
  • 스트림 요소 걸러내기
  • 정렬하기
  • 변환하기 map()

저장된 값 중에서 원하는 필드만 뽑아내기

특정 형태로 변환하기

Stream<R> map(<super T,? extends R> mapper)

Stream<File> fileStream = Stream.of(new File("EX1.java"), new File("Ex1"), new File("Ex1.bak");
Stream<String> filenameStream =fileStream.map(File::getName);
filenameStream.forEach(System.out::printLn);
  • 조회하기
  • T[ ]배열 요소를 T로

Stream 최종연산

Stream의 요소합 등 단일값 or 스트림 요소가 담긴 배열 or Collection

 

  • 스트림 요소 출력하기
void forEach(System.out::println)
  • 조건 검사
  • 통계
  • 리듀싱

🚀Lambda 생략 순서 요약

더보기

1.기본방식

2.실행문이 하나만 존재할 때

3.매개변수 타입을 쉽게 유추할 수 있는 경우

코드예제

max() 람다식 변환

반환타입, 이름 제거(익명함수이므로)

int max(int a, int b) {
	return a>b ? a:b;
}

매개변수 선언부→바디

int max(int a, int b) ->{
	return a>b ? a:b;
}

반환값이 있다면 기존의 return문을 expression으로 대체

  • return을 생략할 때는 ⭐⭐개행 ‘;’을 붙이지 않는다
  • return을 붙이고 싶다면 무조건 중괄호가 있어야 한다
int max(int a, int b) -> {a>b ? a:b}

람다식에 선언된 매개변수 타입은 보통 추론 가능→생략

(a, b) -> {a>b ? a:b}

괄호, 중괄호 생략 case

  • 선언된 매개변수가 하나→괄호 생략
a ->  a>b ? a:b;//ok
(int a) -> a>b ? a:b//ok
  • 메서드 바디 문장이 하나→ 중괄호 생략, ‘;’생략

 

 

함수형 인터페이스

람다는 메서드와 동일시했지만, 사실 익명 클래스임

익명클래스

객체의 선언과 생성을 동시에 하며

오직 하나의 객체를 생성해 단 한 번만 사용하는 일회용 클래스

즉, 람다식은 아래와 같다

(int a, int b) -> a>b?a:b
//라는 람다식은 아래와 완전히 같다
new Object(){
	int max(int a, int b){
	return a>b ? a: b
	}
}

그러나 이 익명객체의 메서드는 어떻게 쓸 수 있을 것인가?

참조변수가 있어야 메서드를 호출할 수 있기 때문에

타입 f =~방식일 텐데, 람다식과 동일한 메서드가 정의되어 있어야 하겠다.

그렇기 때문에 인터페이스를 구현한 익명 클래스 객체로서 람다를 만들고, 그런 인터페이스를 함수형 인터페이스라고 부르기로 했다

	public class LamdaExample1 {
    public static void main(String[] args) {
		   Object obj = new Object() {
            int sum(int num1, int num2) {
                return num1 + num1;
            }
        };
			// 람다식 Object obj = (num1, num2) -> num1 + num2 로 대체 가능
}

원래의 sum이라는 메서드는 온데간데 없이 사라져버렸음

그렇기 때문에 인터페이스를 1:1 매치하게 되는 것

완전히 같은 메서드가 있어야만 작동할 수 있기 떄문에

앞서 학습한 FunctionalInterface 어노태이션을 통해 확인하면서 작성하는 걸 추천

public class LamdaExample1 {
    public static void main(String[] args) {
		   /* Object obj = new Object() {
            int sum(int num1, int num2) {
                return num1 + num1;
            }
        };
			*/
		ExampleFunction exampleFunction = (num1, num2) -> num1 + num2
		System.out.println(exampleFunction.sum(10,15))
}

@FunctionalInterface // 컴파일러가 인터페이스가 바르게 정의되었는 지 확인할 수 있도록
interface ExampleFunction {
		public abstract int sum(int num1, int num2);
}

// 출력값
25

즉 람다를 쓰고 싶으면, 무조건 인터페이스를 만들어준 뒤, 인터페이스의 인스턴스를 생성해 작성한다.

 

매개변수와 리턴값이 없는 람다식

 
@FunctionalInterface
public interface MyFunctionalInterface {
    public void accept();
}

인 경우 람다식은

MyFunctionalInterface example = () -> { ... };

// example.accept();

바로 accept를 호출하게 된다

public class MyFunctionalInterfaceExample {
	public static void main(String[] args) throws Exception {
		MyFunctionalInterface example;
		example = () -> {
			String str = "첫 번째 메서드 호출!";
			System.out.println(str);
		};
		example.accept();

		example = () -> System.out.println("두 번째 메서드 호출!");
		//실행문이 하나라면 중괄호 { }는 생략 가능
		example.accept();
	}
}

// 출력값
첫 번째 메서드 호출!
두 번째 메서드 호출!

 

이렇게 따로 클래스 작성 없이도 가능하다는 큰 장점이 있다

 

📒프로젝트에서 만났던 Stream, Lambda 코드모음

1) Stream.map+ lamda 메서드 참조

List<Coffee> orderedCoffees = order.getOrderCoffeeList().stream()
                        .map(orderCoffee::getCoffee)
                        .collect(Collectors.toList());

order.getOrderCoffeeList().stream()

  • orderCoffeeList를 stream으로 변환

→Stream<OrderCoffee> orderedCoffeesStream

 

.map(orderedCoffee :: getCoffee)

 

함수형 인터페이스를 인자로 받기 때문에 메서드 레퍼런스가 들어갔다

(orderCoffee::getCoffee)

  • orderCoffee는 OrderCoffee 타입 스트림의 객체 하나하나를 의미
  • 그중에서 일부 필드인 coffee를 받기 위해 쓰는 메서드인 getCoffee
  • 즉, 각 객체에서 coffee 필드만 뽑아와라

.collect(Collection.toList())

collect()로 list 변환

 

 

2) Stream+Lambda

.filter(n -> n.startsWith(lastName))

이 람다를 풀어쓰면 어떻게 될까?

생략된 것을 찾아보면

  • 메서드명, 반환타입
  • 매개변수 소괄호
  • 메서드바디 중괄호

람다 문법을 이해했으니 다시 적어보면

stream()

	.filter(자료형 n){

		return n.startsWith(lastName)

	}

 

3) Lambda를 파라미터로 넣기 

assertThrows(BusinessLogicException.class, () -> memberService.createMember(member));

실행이 되면 exception이 날 거고, 그 익셉션이 비즈니스 익셉션일 것이라는 뜻

매개변수 , 리턴값이 없고 실행문이 한 문장이어서 생략된 케이스다.

 

 

728x90
반응형