본문 바로가기
[스파르타코딩클럽]/Java 문법 종합반

Chapter 13. 모던 자바(람다, 스트림, Optional)

by 진진리 2023. 10. 18.
728x90
  • 함수형 프로그래밍
    • 순수 함수: 수학의 함수처럼 특정한 데이터에 의존하지 않고, 관련없는 데이터를 변경하지도 않으며, 결과값이 오직 입력값에만 영향을 받는 함수
    • 효용
      1. 검증이 쉽다
      2. 성능 최적화가 쉽다
      3. 동시성 문제를 해결하기 쉽다

 

  • 모던 자바 : 자바 8 변경점
    • 함수형 프로그래밍 아이디어 1: 함수를 일급 값(일급 객체)으로
      • 일급 객체 특징
        1. 함수에 인자로 넘길 수 있다.
        2. 함수의 결과로 반환할 수 있다.
        3. 값을 수정할 수 있다.
        4. 값을 변수에 대입할 수 있다.
      • 결론: 메서드 참조 기능 도입
    • 함수형 프로그래밍 아이디어 2: 람다(익명함수)
      • 익명함수란 이름이 없는 함수를 뜻하며 일급 객체로 취급됨
      • 함수를 값으로 사용할 수 있으며 파라미터에 전달 가능
      • 연산 가능
    • 스트림
      • 데이터 처리연산을 지원하도록 소스에서 추출된 연속된 요소
      • 컬렉션의 반복을 처리하는 일종의 기능이자 멀티스레드 관련 코드를 구현하지 않아도 알아서 병렬로 추가해주는 기능

람다와 스트림 문법 살펴보기

  • 함수를 값으로 전달하기: 함수형 인터페이스
    • 추상 메소드를 딱 하나만 가지고 있는 인터페이스
    • @FunctionalInterface 어노테이션으로 검증할 수 있음
interface Predicate<T> {
    boolean test(T t);
}

함수형 인터페이스를 타입 삼아 인자로 전달받는 함수

// 변경점 1 : Predicate<Car> 인터페이스를 타입 삼아 함수를 전달합니다!
public static List<Car> parkCars(List<Car> carsWantToPark, Predicate<Car> function) {
      List<Car> cars = new ArrayList<>();

      for (Car car : carsWantToPark) {
					// 변경점 2 : 전달된 함수는 다음과 같이 사용됩니다!
          if (function.test(car)) {
              cars.add(car);
          }
      }

      return cars;
  }

위의 함수를 사용

parkingLot.addAll(parkCars(carsWantToPark, Car::hasTicket));
parkingLot.addAll(parkCars(carsWantToPark, Car::noTicketButMoney));
  • 함수를 값으로 취급하기 때문에 함수를 참조로 불러서 사용
  • Car :: Car 클래스 내부의 메소드

 

  • 람다
// 기본적으로 문법은 다음과 같습니다.
(파라미터 값, ...) -> { 함수 몸체 }

// 아래의 함수 두개는 같은 함수입니다.
// 이름 반환타입, return문 여부에 따라 {}까지도 생략이 가능합니다.
public int toLambdaMethod(int x, int y) {
	return x + y;
}

(x, y) -> x + y

// 이런 함수도 가능하겠죠?
public int toLambdaMethod2() {
	return 100;
}

() -> 100

// 모든 유형의 함수에 가능합니다.
public void toLambdaMethod3() {
	System.out.println("Hello World");
}

() -> System.out.println("Hello World")
// 주말의 주차장 추가
ArrayList<Car> weekendParkingLot = new ArrayList<>();

weekendParkingLot
.addAll(parkCars(carsWantToPark, (Car car) -> car.hasParkingTicket() && car.getParkingMoney() > 1000));

 

  • 스트림

한번 더 추상화된 자료구조와 자주 사용하는 프로그래밍 API를 제공한 것

자료구조의 “흐름”을 객체로 제공해주고, 그 흐름동안 사용할 수 있는 메서드들을 api로 제공

컬렉션에 정의되어 있으므로 컬렉션을 상속하는 구현체들은 스트림을 반환할 수 있

  • 스트림의 특징
    1. 원본 데이터를 변경하지 않음: 자바 컬렉션으로부터 스트림을 받아서 한 번 사용
    2. 일회용: 한 번 사용한 스트림은 어디에도 남지 않음
  • 사용 예시
List<Car> benzParkingLot =
    // carsWantToPark의 스트림값을 받아와서
    carsWantToPark.stream()
		// 거기 구현되어 있는 filter()메서드를 사용합니다.
		// filter메서드는 함수를 파라미터로 전달받습니다.
		// 여기서 함수는 제조사가 벤츠면 true를 반환하는 함수네요.
		// 필터 메서드는 이름처럼 false를 반환한 스트림의 원소들을 제거합니다.
            .filter((Car car) -> car.getCompany().equals("Benz"))
		// 이 결과도 반환을 받아서 다시 리스트로 묶어줍니다.
            .toList();

 

  • 대표적인 스트림 API

forEach()

넘겨받은 함수를 각각의 원소에 대하여 실행

반환값이 있어도 무시됨

List<String> carNames = Arrays.asList("Series 6", "A9", "Ionic 6");

carNames.stream()
    .forEach(System.out::println);

// 결과 
// Series 6
// A9
// Ionic 6

map()

조건에 맞는 것만 반환하는 filter()와 달리 모든 요소를 변환하여 반환

carNames.stream()
	.map(name -> name.toUpperCase()).toList();

// 결과
// ["SERIES 6", "A9", "IONIC 6"]

NULL

기본적으로 아무것도 참조하지 않는다는 것을 의미

  • null을 다룰 때 조심해야 하는 점
    1. null이 반환될 여지를 명시하고 그 메서드를 사용할 때 조심하기
    2. null 체크를 매번하기 보다 객체 감싸서 반환하기
    3. 감싸는 객체를 추상화하기  ->  java.util.Optional 객체
  • Optional 기본 정리
    • Optional<T> 클래스로 Nulll Pointer Exception을 방지할 수 있도록 도와줌
    • null이 올 수 있는 값을 감싸는 Wrapper 클래스
    • Optional이 비어있더라도 참조할 때 Null Pointer Exception이 발생하지 않음
  • Optional 간단 사용법

1. 값이 null인 Optional 생성

 

Optional<Car> emptyOptional = Optional.empty();

2. 값이 있는 Optional 생성

Optional<Car> hasDataOptional = Optional.of(new Car());

3. 값이 있을수도 없을수도 있는 Optional 생성

Optional<Car> hasDataOptional = Optional.ofNullable(getCarFromDB());

4. Optional 객체 사용하기

Optional<String> carName = getCarNameFromDB();
// orElse() 를 통해 값을 받아옵니다, 파라미터로는 null인 경우 반환할 값을 적습니다.
String realCarName = carName.orElse("NoCar");

// 위는 예시코드고 실제는 보통 아래와 같이 사용하겠죠?
String carName = getCarNameFromDB().orElse("NoCar");

// orElseGet()이라는 메서드를 사용해서 값을 받아올 수 있습니다.
// 파라미터로는 없는 경우 실행될 함수를 전달합니다.
Car car = getCarNameFromDB().orElseGet(Car::new);

// 값이 없으면, 그 아래 로직을 수행하는데 큰 장애가 되는경우 에러를 발생시킬수도 있습니다.
Car car = getCarNameFromDB()
		.orElseThrow(() -> new CarNotFoundException("NO CAR!)

'[스파르타코딩클럽] > Java 문법 종합반' 카테고리의 다른 글

Chapter 12. 스레드  (0) 2023.10.18
Chapter 11. 제네릭(Generic)  (0) 2023.10.17
Chapter 10. 예외처리  (0) 2023.10.17
Chapter 9. 인터페이스  (0) 2023.10.17
Chapter 8. 상속  (0) 2023.10.16