List, Set, Map과 같은 java collection이 아니라, 우리가 직접 만든 클래스로 컨테이너를 사용하려면 어떻게 해야 할까? 스트림은 사용자 정의 컨테이너 객체에 수집할 수 있도록 Stream 인터페이스는 collect() 메소드를 제공한다. (Stream, IntStream, LongStream, DoubleStream 인터페이스의 collect 메소드) https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html collect(Supplier, BiConsumer, BiConsumer) (리턴타입 R) 첫 번째 매개변수, 공급자(Supplier) : 요소들이 수집될 컨테이너 객체(R)을 생성하는 역할을 한다. 순차 처리..
분류 전체보기
스트림은 최종 처리 단계에서 요소들을 수집하는 collect()를 제공하고 있다. 이 메소드를 이용하면 필요한 요소만 컬렉션으로 담을 수 있고, 요소들을 그룹핑한 후 집계(리덕션)할 수 있다. 필터링한 요소 수집 Stream의 collect(Collector collector) 메소드는 필터링, 매핑된 요소들을 새로운 컬렉션에 수집해서 리턴한다. 매개값인 Collector는 어떤 요소를 어떤 컬렉션에 수집할 것인가를 나타낸다. 타입 파라미터의 의미(T, A, R) T ⇒ 요소 A ⇒ 누적기(accumulator) R ⇒ 저장될 컬렉션 T 요소를 A 누적기가 R에 저장한다는 의미가 된다. Collector의 구현객체는 Collectors 클래스의 정적 메소드를 이용해서 이용할 수 있다. 참고) https:..
Stream API는 최종 처리 단계 에서 요소들이 특정 조건에 만족하는지 조사할 수 있도록 세가지 매칭 메소드를 제공한다. allMatch() 모든 요소들이 매개값으로 주어진 Predicate의 조건을 만족하는지 조사 anyMatch() 최소한 한 개의 요소가 매개값으로 주어진 조건을 만족하는지 조사 noneMatch() 모든 요소들이 매개값으로 주어진 조건을 만족하지 않는지 조사 public static void main(String[] args){ int[] intArr = {2, 4, 6}; boolean result = Arrays.stream(intArr) .allMatch(a -> a%2 == 0); System.out.println("2의 배수? " + result); result = Ar..
다량의 데이터 처리 작업을 돕고자 자바8에 스트림 API가 추가되었다. 이 API가 제공하는 추상 개념 중 핵심은 두 가지다. 스트림(stream)은 데이터 원소의 유한 혹은 무한 시퀀스(sequence)를 뜻한다. 스트림 파이프라인(stream pipleline)은 이 원소들로 수행하는 연산 단계를 표현하는 개념이다. 스트림 파이프라인 은 소스 스트림에서 시작해 종단 연산(terminal operation)으로 끝나며, 그 사이에 하나 이상의 중간 연산(intermediate operation)이 있을 수 있다. 각 중간 연산은 스트림을 어떠한 방식으로 변환(transform)한다. (중간 연산들은 모두 한 스트림을 다른 스트림으로 변환한다.) 또한 스트림 파이프라인은 지연 평가(lazy evaluat..
@ModelAttribute로 지정된 모델 오브젝트의 바인딩 작업이 실패로 끝나는 경우는 두 가지가 있다. 타입 변환이 불가한 경우 타입 변환은 성공했지만 검증기(Validator)를 이용한 검사가 통과하지 못했을 때 Validator를 통한 검증 과정의 결과는 BindingResult를 통해 확인할 수 있다. BindingResult는 Errors의 서브인터페이스다. Validator 스프링에서 범용적으로 사용할 수 있는 오브젝트 검증기를 정의할 수 있는 API @Controller로 HTTP요청을 @ModelAttribute 모델에 바인딩 할 때 주로 사용된다. 또한 비즈니스 로직에서 검증 로직을 분리하고 싶을 때도 사용할 수 있다. public interface Validator{ boolean s..
자바가 람다를 지원하면서 API를 작성하는 모범 사례도 크게 바뀌었다. 상위 클래스의 기본 메서드를 재정의해 원하는 동작을 구현하는 템플릿 매서드 패턴의 매력이 줄었다. ⇒ 함수 객체를 받는 정적 팩터리나 생성자를 제공 LinkedHashMap을 생각해보자. LinkedHashMap의 protected 메서드인 removeEldestEntry 를 재정의하면 캐시로 LinkedHashMap을 사용할 수 있다. 맵에 새로운 키를 추가하는 put 메서드는 이 메서드를 호출하여 true가 반환되면 맵에서 가장 오래된 원소를 제거하게 로직을 추가하면 된다. public class MyLinkedHashMap extends LinkedHashMap { @Override protected boolean removeE..
PropertyEditor의 여러가지 장점에도 불구하고, PropertyEditor는 매번 바인딩을 할 때마다 새로운 오브젝트를 만들어야 한다는 약점이 있다. 그래서 스프링 3.0에는 PropertyEditor를 대신할 수 있는 새로운 타입 변환 API가 도입됐다. 바로 Converter 인터페이스다. Converter는 PropertyEditor와 다르게 변환과정에서 메소드가 한 번만 호출된다. ⇒ 변환 작업 중 상태를 인스턴스 변수로 저장하지 않음 (멀티스레드 환경에서 안전) Converter Converter는 소스 타입에서 타깃 타입으로의 단방향 변환만 지원한다. (PropertyEditor는 양방향 지원) 물론 소스 타입과 타깃 타입을 바꿔서 컨버터를 하나 더 만들면 양방향 변환이 가능해 진다...
람다가 익명 클래스보다 나은 점 중 가장 큰 특징은 간결함이다. 그런데 람다보다도 더 간결하게 만드는 방법이 있으니 바로 메서드 참조(method reference)이다. 아래 코드는 키가 맵안에 없다면 키와 숫자 1을 매핑하고, 이미 있다면 기존 매핑 값을 증가시킨다. map.merge(key, 1, (count, incr) -> count + incr); 깔끔해 보이지만, 매개변수인 count와 incr은 크게 하는일 없이 공간을 꽤 차지한다. (두 인수의 합을 단순히 반환하는 역할을 한다.) 자바8의 Integer 클래스는 이 람다와 같은 기능이 같은 정적 메서드 sum을 제공하기 시작했다. 따라서 위의 코드는 아래코드로 변경할 수 있다. map.merge(key, 1, Integer::sum); ..
자바8에는 추상 메서드 하나짜리 인터페이스는 특별한 의미를 인정받아 특별한 대우를 받게 되었다. 함수형 인터페이스라 부르는 이 인터페이스들의 인스턴스를 람다식(lamda expression)을 사용해 만들 수 있게 된 것이다. Collections.sort(words, new Comparator(){ public int compare(String s1, String s2){ return Integer.compare(s1.length, s2.length()); } }); Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length()); 컴파일러가 문맥을 살펴 타입을 추론해준다. 타입을 명시해야 코드가 더 명확할 때만 제외하고는, 람..
컨트롤러 메소드에 @ModelAttribute가 지정된 파라미터를 @Controller 메소드에 추가하면 세 가지 작업이 자동으로 진행된다. 파라미터 타입의 오브젝트를 만든다. @ModelAttribute User user 라는 파림터 선언이 있다면 User타입의 오브젝트를 생성한다. 준비된 모델 오브젝트의 프로퍼티에 웹 파라미터를 바인딩해준다. 전환이 불가능한 경우라면, BindingResult 오브젝트 안에 바인딩 오류를 저장해서 컨트롤러로 넘겨주거나 예외를 발생시킨다. 모델의 값을 검증한다. 타입에 대한 검증은 끝났지만, 그 외의 검증할 내용이 있다면 적절한 검증기를 등록해서 모델의 내용을 검증할 수 있다. ⇒ 스프링에서는 컨트롤러로직과 검증 로직을 분리할 수 있다. 데이터 검증은 대개 폼의 값이 ..