Java 함수식 프로그래밍(4): 컬렉션에서 요소 찾기

요소 찾기
현재 우리는 이 디자인의 우아한 전환 집합 방법이 낯설지 않지만, 원소를 찾는 데도 무능하다.하지만 Filter 방법은 이를 위해 만들어진 것이다.
우리는 지금 이름 목록에서 N으로 시작하는 이름을 꺼내야 한다.물론 하나도 없을 수도 있고, 결과는 빈 집합일 수도 있다.우리는 먼저 낡은 방법으로 하나를 실현한다.

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 방법은 부울 값을 되돌려주는 lambda 표현식을 수신합니다.표현식 결과가true이면 실행 상하문에 있는 요소가 결과 집합에 추가됩니다.만약 그렇지 않다면, 그것을 뛰어넘어라.최종적으로 되돌아오는 것은 Steam입니다. 표현식으로true를 되돌아오는 요소만 포함되어 있습니다.마지막으로 우리는collect 방법으로 이 집합을 하나의 목록으로 전환시켰다. 뒤에 있는 52페이지의collect 방법과Collecters 클래스를 사용하면 우리는 이 방법에 대해 더욱 깊이 있게 연구할 것이다.
이 결과에 집중된 요소를 인쇄해 보겠습니다.

System.out.println(String.format("Found %d names", startsWithN.size()));
출력 결과에서 분명히 알 수 있듯이 이 방법은 집합에서 일치하는 원소를 모두 찾아냈다.

Found 2 names
filter 방법은 맵 방법과 마찬가지로 교체기도 되돌려주지만 이것도 똑같을 뿐이다.맵이 되돌아오는 집합과 입력 집합의 크기는 같지만 필터가 되돌아오는 것은 말할 수 없습니다.0부터 입력 집합의 요소 개수까지 집합의 크기 구간을 되돌려줍니다.맵과 달리 필터는 입력 집합의 하위 집합을 되돌려줍니다.
지금까지lambda표현식이 가져온 코드의 간결성은 우리를 만족시켰지만, 주의하지 않으면 코드의 불필요한 문제가 점점 길어지기 시작했다.다음은 우리가 이 문제를 토론해 봅시다.
lambda 표현식의 중용
lambda 표현식은 보기에 매우 간결해 보이지만, 실제로는 조심하지 않으면 코드의 군더더기가 생기기 쉽다.군더더기는 코드의 질이 저하되어 유지하기 어렵다.만약 우리가 변경을 하고 싶다면, 관련 코드를 여러 군데 함께 고쳐야 한다.
이중화를 피하면 성능을 향상시킬 수 있습니다.관련 코드는 모두 한 곳에 집중되어 있다. 그러면 우리는 그것의 성능 표현을 분석한 다음에 이 곳의 코드를 최적화하면 코드의 성능을 쉽게 향상시킬 수 있다.
이제 람다 표현식을 사용하면 코드가 번거로워지기 쉬우며, 이를 피하는 방법을 생각해 봅시다.

final List<String> friends =
Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");
final List<String> editors =
Arrays.asList("Brian", "Jackie", "John", "Mike");
final List<String> comrades =
Arrays.asList("Kate", "Ken", "Nick", "Paula", "Zach");
We want to filter out names that start with a certain letter.
우리는 어떤 자모의 시작 이름을 필터하기를 바란다.먼저 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();
lambda 표현식은 코드를 간결하게 보이지만, 어느새 코드의 군더더기를 가져왔다.위의 이 예에서 만약lambda 표현식을 바꾸려면 우리는 한 군데만 고쳐야 한다. 그러면 안 된다.다행히도, 우리는 lambda 표현식을 변수에 부여하고, 그것들을 사용 대상처럼 다시 사용할 수 있다.
filter 방법, lambda 표현식 수신자, 수신은java입니다.util.function.Predicate 함수식 인터페이스의 참조입니다.여기서 Java 컴파일러는 지정한 lambda 표현식으로Predicate의test 방법을 생성하는 데 사용됩니다.이제 우리는 매개 변수가 정의된 곳에서 다시 생성하는 것이 아니라 자바 컴파일러로 하여금 이 방법을 생성하게 할 수 있다.상기 예에서 우리는 lambda 표현식을 Predicate 형식의 인용에 명확하게 저장한 다음에 이 인용을 filter 방법에 전달할 수 있다.이렇게 하면 코드의 군더더기를 쉽게 피할 수 있다.
DRY의 원칙에 부합하도록 앞의 코드를 재구성합시다.(Don't Repeat Yoursef―DRY―원칙, The Pragmatic Programmer: From Journeyman to Master[HT00], 한 권 참조).

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();
이제 그 lambda 표현식을 다시 쓸 필요가 없습니다. 한 번만 썼고, starts WithN이라는 Predicate 형식의 인용에 저장했습니다.이 뒤에 있는 세 개의 필터 호출에서 자바 컴파일러는 Predicate에서 위장한 lambda 표현식을 보고 웃으며 묵묵히 받아들였다.
이 새로 도입된 변수는 우리를 위해 코드의 군더더기를 없앴다.그러나 불행하게도 뒤에서 우리는 적들이 곧 다시 돌아와서 원한을 갚는 것을 보게 될 것이다. 더 강한 무기가 우리를 위해 그것들을 없앨 수 있는지 다시 한번 보자.

좋은 웹페이지 즐겨찾기