객체 지향 프로그래밍처럼 프로그래밍의 패러다임의 한 종류
“프로그램을 객체들의 협력과 상호작용으로 바라보고 구현한다”
"프로그램을 순수한 함수의 모음으로 바라보고 구현한다"
순수한 함수와 순수하지 못한 함수들
// 수학의 함수
f(x, y) = x + 2xy
// 순수한 메서드
// input에 따라 output은 항상 일정하죠!
public int someMethod(int x, int y) {
return x + 2y;
}
class notFunc {
private int y = 0;
private int result;
// 순수 메서드가 아닌 메서드
// 메서드 안에서 제어할 수 없는 y라는 값에 의해 output이 바뀔 수 있죠
public int anotherMethod(int x) {
return x + this.y * 2;
}
// 순수 메서드가 아닌 메서드 2
// 메서드 내에서 this.result 값을 변경하고 반환하기 때문에
// 순수 메서드라고 보기는 어렵습니다!
public int otherMethod(int x, int y) {
int result = x + 2 * y;
this.result = result;
return result;
}
}
효용
함수를 값으로 사용할떼 타입으로 사용되는 인터페이스
interface Predicate<T> {
boolean test(T t);
}
public static boolean hasTicket(Car car) {
return car.hasParkingTicket;
}
public int toLambdaMethod(int x, int y) { // 기존 메소드
return x + y;
}
{}
앞에 ->
추가(int x, int y) -> {
return x + y;
}
return
문, ;
생략 가능(int x, int y) -> x + y
(x, y) -> x + y
하나의 메소드만 호출하는 람다식은 '메소드 참조'로 간단히 할 수 있음
종류 | 람다식 | 메소드 참조 |
---|---|---|
static 메소드 | (x) -> ClassName.method(x) | ClassName::method |
인스턴스 메소드 | (obj, x) -> obj.method(x) | ClassName::method |
특정 객체 인스턴스 메소드 | (x) -> obj.method(x) | obj::method |
자료구조의 “흐름”을 객체로 제공해주고, 그 흐름동안 사용할 수 있는 메서드들을 api로 제공
collection에 정의되어있기 때문에,
모든 컬렉션을 상속하는 구현체들은 스트림 반환 가능
Stream<Integer> intStream = list.stream(); // Collection.stream()
Stream<String> strStream = Stream.of("a", "b", "c"); // 가변인자
Stream<String> strStream = Stream.of(new String[] {"a", "b", "c"});
Stream<String> strStream = Arrays.stream(new String[] {"a", "b", "c"});
IntSteam intStream = str.chars();
IntStream intStream = IntStream.range(1,5); // 1,2,3,4
IntStream intStream = IntStream.rangeClosed(1,5); // 1,2,3,4,5
IntStream intStream = new Random.ints(); // 무한 스트림
intStream.limit(5).forEach(System.out::println); // 5개요소만 출력
IntStream intStream = new Random.ints(5); // 크기가 5인 난수스트림 반환
Stream<Integer> evenStream = Stream.iterate(0, n->n+2); // 0,2,4,6,...
Stream<Double> randomsStream = Stream.generate(Math::random); //
skip(n)
: 앞에서부터 n개 건너뛰기limit(n)
: n개까지 잘라내기filter()
: 조건에 맞지않는 요소 제거 ✨distinct()
: 중복 제거sorted()
: 기본 정렬(오름차순)sorted(Comparator.reverseOrder())
: 지정된 비교함수로 정렬(내림차순)map(람다식)
: 스트림의 모든 요소를 변환가능 ✨forEach(i -> i를 이용한 연산)
: 스트림의 모든요소에 지정 작업 수행 ✨toArray(Class[]::new)
: 스트림의 모든요소를 Class[]에 담아 반환(생략시 Object[])sum()
, count()
, max()
, min()
, average()
: 스트림에 대한 통계정보 제공// for문을 이용한 코드
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
System.out.print("*");
}
System.out.println();
}
// 스트림을 이용한 코드
IntStream.range(0, n).forEach(i -> sb.append("*"));
IntStream.range(0, m).forEach(i -> System.out.println(sb));
🚨
max()
,min()
,average()
의 반환값은 Optional!
따라서 값을 사용하려면 이렇게 getAsType()을 호출해줘야함.max().getAsInt(); .min().getAsInt(); .average().getAsDouble();
Optional<T>
클래스를 사용해 Null Pointer Exception을 방지할 수 있도록 도와줌Optional<T>
는 null이 올 수 있는 값을 감싸는 Wrapper 클래스Optional<Car> emptyOptional = Optional.empty();
Optional<Car> hasDataOptional = Optional.of(new Car());
Optional<Car> hasDataOptional = Optional.ofNullable(getCarFromDB());
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 문법 종합반
🔗 자바의 정석