Java : Lambda, Stream

김선미·2022년 8월 23일
0

Lambda

  • 함수의 명세(접근제어자, 리턴 타입 등) 없이도 함수를 실행할 수 있는 기능
  • 문법이 간결하고 편리하지만, 함수를 정의하는 것이 아니기 때문에 같은 코드를 반복해서 사용해야 함 (중복 코드가 많아짐)
  • function 파라미터를 받는 함수일 경우 람다 식을 사용할 수 있다는 의미
public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("korea");
        list.add("japan");
        list.add("france");
        Stream<String> stream = list.stream();
        stream.map(str -> {
                    System.out.println(str);
                    return str.toUpperCase();
        }).forEach(it -> System.out.println(it));

        // }).forEach(System.out::println);
        // 파라미터 변수가 하나인 경우 변수를 입력하지 않는 람다식으로 변형 할수 있음
    }
}
  • map : 앞에 입력한 값을 파라미터 내에 입력한 다른 형식 등으로 바꾸는 함수
  • toUpperCase : 소문자를 대문자로 바꾸는 함수
  • forEach : 값마다 각각 실행하는 함수
  • 람다 : 값을 하나씩 꺼내서 변수로 지칭하고 꺽쇄(->) 표시 뒤에 실행할 함수 작성 (중괄호와 return 구문을 사용하여 여러줄 작성 가능)

Stream

  • 하나의 데이터의 흐름
  • 스트림을 통해서 각 데이터를 어떻게 처리할지 유연한 코드를 작성할 수 있음
  • 대표적인 예 : Collection을 통한 스트림 만들기
  • java 8 버전부터 도입
  • Stream 코드 입력 후 어떤 메소드를 사용하든 데이터를 하나씩 불러옴
  • 기존 데이터 소스를 변경하지 않음(스트림 내에서만 데이터 형식 등 변경)
  • forEach : return type 이 void 이기 때문에 실행 후 stream이 닫힘, 뒤에 어떤 stream 구문도 추가할 수 없음.
  • 다른 스트림을 사용하고 싶을 경우 새로운 객체명으로 호출

Stream 예제

  • list를 새로운 list로 변환
List<String> list = new ArrayList<>();
list.add("서울");
list.add("부산");
list.add("대전");
list.add("서울");

System.out.println(list); // [서울, 부산, 대전, 서울]

List<String> result = list.stream() //list를 차례대로 호출함
                .limit(2) // list에서 앞의 두개만 남기고 지움
                .collect(Collectors.toList()); //새로운 리스트로 만듦
System.out.println(result); // [서울, 부산] 
  • list를 set으로 변환
Set<String> set = list.stream()
        .filter(it -> "서울".equals(it)) 
        //람다식을 사용하여 list를 순서대로 "서울"과 같은 문자열인지 확인

        // .filter("서울"::equals) 
        // 파라미터 변수가 하나이므로 람다식 변경 가능 

        .collect(Collectors.toSet()); //새로운 set으로 만듦
System.out.println(set); // [서울] 
//set은 중복을 허용하지 않고 순서가 없으므로 이렇게 출력됨
  • array를 stream으로 변환
String[] arr = {"SQL", "Java", "Python"};
Stream<String> stringStream = Arrays.stream(arr); 
stringStream.forEach(System.out::println); 
//forEach를 사용해 파라미터 안의 구문(출력)을 실행
  • map 연산 활용
class Sale {
    String fruitName;
    int price;
    float discount;

    public Sale(String fruitName, int price, float discount){
        this.fruitName = fruitName;
        this.price = price;
        this.discount = discount;
    }
}

public class Main {

    public static void main(String[] args) {

        List<Sale> sales = Arrays.asList(
                new Sale("apple", 5000, 0.05f),
                new Sale("orange", 4000, 0.02f),
                new Sale("grafe", 2000, 0)
        );

        Stream<Sale> saleStream = saleList.stream();
        saleStream.map(sale -> Pair.of(sale.fruitName, 
        sale.price * (1 - sale.discount))) 
        //파라미터 left, right 값 입력
                  .forEach(pair -> System.out.println(pair.getLeft() 
                  + " 실 구매가:  " + pair.getRight() + "원 "));
    }
}

//Pair 클래스는 build.gradel에 dependency 추가 또는 
클래스를 직접 만들어서 사용해야 함.
  • reduce 활용
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
System.out.println(list.stream().reduce(0, Integer::sum));

//asList : 고정된 List 생성
//reduce : 파라미터에 들어있는 값과 list 값을 하나씩 꺼내어 
sum 메소드를 실행하고 연산한 값을 누적함 (0+1, 1+2, 3+3...)
  • count 활용
List<String> names = Arrays.asList("김정우", "김호정", "이하늘", "이정희", 
"박정우", "박지현", "정우석", "이지수");
        long count = names.stream()
                          .filter(str -> str.startsWith("이"))
                          .count();

        System.out.println("count : " + count);
  • count() 라는 종결함수는 Stream 의 갯수를 세기 때문에 효율을 위해 중간 연산을 생략하기도 합니다. 그래서 중간 연산을 강제로 실행시키고 싶다면 filter 나 flatMap 과 같이 Stream 요소의 갯수를 변화시킬 수 있는 중간 연산을 추가하면 됩니다.
  • 출처 : https://bcp0109.tistory.com/314
profile
백엔드 개발 공부

0개의 댓글