문법적 표현보다는 서술적 표현으로
리스트를 사용한 이터레이션
일반
- final List<String> friends = Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");
- for(int i = 0; i < friends.size(); i++) {
- System.out.println(friends.get(i));
- }
- for(String name : friends) {
- System.out.println(name);
- }
람다식
- friends.forEach(new Consumer<String>() {
- public void accept(final String name) {
- System.out.println(name);
- }
- });
- friends.forEach((final String name) -> System.out.println(name));
- friends.forEach((name) -> System.out.println(name));
- friends.forEach(name -> System.out.println(name));
- friends.forEach(System.out::println);
엘리먼트 찾기
일반
- final List<String> startsWithN = new ArrayList<String>();
- for (String name : friends) {
- if (name.startsWith("N")) {
- startsWithN.add(name);
- }
- }
람다식
- final List<String> startsWithN =
- friends.stream().filter(name => name.startsWith("N")).collect(Collectors.toList());
람다 표현식의 재사용성
filter에 사용되는 람다 표현식이 되는 경우
- final long countFriendsStartN =
- friends.stream()
- .filter(name -> name.startsWith("N")).count();
- final long countEditorsStartN =
- editors.stream()
- .filter(name -> name.startsWith("N")).count();
- final long countComradesStartN =
- comrades.stream()
- .filter(name -> name.startsWith("N")).count();
- <textarea>
아래와 같이 리팩토링이 가능하다.
- final Predicate<String> startsWithN = name -> name.startsWith("N");
- final long countFriendsStartN =
- friends.stream()
- .filter(startsWithN)
- .count();
- final long countEditorsStartN =
- editors.stream()
- .filter(startsWithN)
- .count();
- final long countComradesStartN =
- comrades.stream()
- .filter(startsWithN)
- .count();
렉시컬 스코프와 클로저 사용하기
아래의 코드는 사용하는 문자가 다르다는 이유만으로 두 개의 Predicate를 사용하고 있다.
- final Predicate<String> startsWithN = name -> name.startsWith("N");
- final Predicate<String> startsWithB = name -> name.startsWith("B");
- final long countFriendsStartN =
- friends.stream()
- .filter(startsWithN).count();
- final long countFriendsStartB =
- friends.stream()
- .filter(startsWithB).count();
렉시컬 스코프로 중복 제거하기
- public static Predicate<String> checkIfStartsWith(final String letter) {
- return name -> name.startsWith(letter);
- }
- final long countFriendsStartN =
- friends.stream()
- .filter(checkIfStartsWith("N")).count();
- final long countFriendsStartB =
- friends.stream()
- .filter(checkIfStartsWith("B")).count();
렉시컬 스코프란?
적용 범위를 좁히기 위한 리팩토링
- final Function<String, Predicate<String>> startsWithLetter =
- (String letter) -> {
- Predicate<String> checkStarts = (String name) -> name.startsWith(letter);
- return checkStarts;
- };
- final Function<String, Predicate<String>> startsWithLetter =
- (String letter) -> (String name) -> name.startsWith(letter);
- final Function<String, Predicate<String>> startsWithLetter =
- letter -> name -> name.startsWith(letter);
- final long countFriendsStartN =
- friends.stream()
- .filter(startsWithLetter.apply("N")).count();
- final long countFriendsStartB =
- friends.stream()
- .filter(startsWithLetter.apply("B")).count();
엘리먼트 선택
일반
- String foundName = null;
- for(String name : names) {
- if(name.startsWith(startingLetter)) {
- foundName = name;
- break;
- }
- }
람다 표현식
- final Optional<String> foundName =
- names.stream()
- .filter(name ->name.startsWith(startingLetter))
- .findFirst();
Optional 클래스는 결과가 없는 경우에 유용하다. 우연히 NullPointerException이 발생하는
것을 막아주며 "결과가 없다"라는 것을 가능한 출력해서 사용자에게 명확하게 알려준다.
isPresent() 메서드를 사용하는 경우에 객체가 존재하는지를 알아보고 get() 메서드를 사용하여 현재 값을 얻어온다.