Protonpack 소개

1. 개요

이 튜토리얼에서는 일부 무료 기능을 추가 하여 표준 Stream API 를 확장하는 라이브러리 인 Protonpack의 주요 기능을 살펴 보겠습니다 .

Java Stream API 의 기본 사항을 알아 보려면 여기에서이 글을 참조하십시오 .

2. Maven 종속성

Protonpack 라이브러리를 사용하려면 pom.xml 파일에 종속성을 추가해야 합니다.

 com.codepoetics protonpack 1.15 

Maven Central에서 최신 버전을 확인하세요.

3. StreamUtils

이것은 Java의 표준 Stream API 를 확장하는 메인 클래스입니다 .

여기에서 설명하는 모든 메서드는 중간 작업이므로 Stream 을 수정 하지만 처리를 트리거하지 않습니다.

3.1. takeWhile ()takeUntil ()

takeWhile ()제공된 조건을 충족하는 한 소스 스트림에서 값을 가져옵니다 .

Stream streamOfInt = Stream .iterate(1, i -> i + 1); List result = StreamUtils .takeWhile(streamOfInt, i -> i < 5) .collect(Collectors.toList()); assertThat(result).contains(1, 2, 3, 4);

반대로 takeUntil () 은 값이 제공된 조건을 충족 할 때까지 값을 취한 다음 중지합니다.

Stream streamOfInt = Stream .iterate(1, i -> i + 1); List result = StreamUtils .takeUntil(streamOfInt, i -> i >= 5) .collect(Collectors.toList()); assertThat(result).containsExactly(1, 2, 3, 4);

Java 9부터 takeWhile () 은 표준 Stream API의 일부입니다 .

3.2. 지퍼()

zip () 은 2 개 또는 3 개의 스트림을 입력 및 결합기 함수로 사용합니다. 이 메서드 는 각 스트림의 동일한 위치에서 값을 가져 와서 결합기에 전달합니다 .

스트림 중 하나의 값이 부족해질 때까지 이렇게합니다.

String[] clubs = {"Juventus", "Barcelona", "Liverpool", "PSG"}; String[] players = {"Ronaldo", "Messi", "Salah"}; Set zippedFrom2Sources = StreamUtils .zip(stream(clubs), stream(players), (club, player) -> club + " " + player) .collect(Collectors.toSet()); assertThat(zippedFrom2Sources) .contains("Juventus Ronaldo", "Barcelona Messi", "Liverpool Salah"); 

마찬가지로, 세 가지 소스 스트림을 사용 하는 오버로드 된 zip () :

String[] leagues = { "Serie A", "La Liga", "Premier League" }; Set zippedFrom3Sources = StreamUtils .zip(stream(clubs), stream(players), stream(leagues), (club, player, league) -> club + " " + player + " " + league) .collect(Collectors.toSet()); assertThat(zippedFrom3Sources).contains( "Juventus Ronaldo Serie A", "Barcelona Messi La Liga", "Liverpool Salah Premier League");

3.3. zipWithIndex ()

zipWithIndex () 는 값을 취하고 색인이있는 각 값을 압축하여 색인화 된 값의 스트림을 만듭니다.

Stream streamOfClubs = Stream .of("Juventus", "Barcelona", "Liverpool"); Set
    
      zipsWithIndex = StreamUtils .zipWithIndex(streamOfClubs) .collect(Collectors.toSet()); assertThat(zipsWithIndex) .contains(Indexed.index(0, "Juventus"), Indexed.index(1, "Barcelona"), Indexed.index(2, "Liverpool"));
    

3.4. merge ()

merge () 는 여러 소스 스트림과 결합기와 함께 작동합니다. 이는 각 소스 스트림에서 동일한 인덱스 위치의 값을 취하고 결합기로 전달한다 .

이 메서드는 시드 값 에서 시작하여 연속적으로 각 스트림의 동일한 인덱스에서 1 개의 값을 가져 오는 방식으로 작동 합니다.

그런 다음 값이 결합기에 전달되고 결과 결합 된 값이 결합기에 피드백되어 다음 값을 생성합니다.

Stream streamOfClubs = Stream .of("Juventus", "Barcelona", "Liverpool", "PSG"); Stream streamOfPlayers = Stream .of("Ronaldo", "Messi", "Salah"); Stream streamOfLeagues = Stream .of("Serie A", "La Liga", "Premier League"); Set merged = StreamUtils.merge( () -> "", (valOne, valTwo) -> valOne + " " + valTwo, streamOfClubs, streamOfPlayers, streamOfLeagues) .collect(Collectors.toSet()); assertThat(merged) .contains("Juventus Ronaldo Serie A", "Barcelona Messi La Liga", "Liverpool Salah Premier League", "PSG");

3.5. mergeToList ()

mergeToList () 는 여러 스트림을 입력으로받습니다. 그것은 에 각 스트림으로부터 같은 인덱스의 값이 결합 목록 :

Stream streamOfClubs = Stream .of("Juventus", "Barcelona", "PSG"); Stream streamOfPlayers = Stream .of("Ronaldo", "Messi"); Stream
    
      mergedStreamOfList = StreamUtils .mergeToList(streamOfClubs, streamOfPlayers); List
     
       mergedListOfList = mergedStreamOfList .collect(Collectors.toList()); assertThat(mergedListOfList.get(0)) .containsExactly("Juventus", "Ronaldo"); assertThat(mergedListOfList.get(1)) .containsExactly("Barcelona", "Messi"); assertThat(mergedListOfList.get(2)) .containsExactly("PSG");
     
    

3.6. 인터리브 ()

interleave () selector를 사용하여 여러 스트림에서 가져온 대체 값을 만듭니다 .

상기 방법은 각 스트림에서 하나 개의 값을 포함하는 세트를 제공 선택기선택기 하나 개의 값을 선택한다.

그러면 선택한 값이 세트에서 제거되고 선택한 값이 시작된 다음 값으로 대체됩니다. 이 반복은 모든 소스의 값이 부족해질 때까지 계속됩니다.

다음 예제에서는 interleave () 를 사용하여 라운드 로빈 전략으로 대체 값을 만듭니다 .

Stream streamOfClubs = Stream .of("Juventus", "Barcelona", "Liverpool"); Stream streamOfPlayers = Stream .of("Ronaldo", "Messi"); Stream streamOfLeagues = Stream .of("Serie A", "La Liga"); List interleavedList = StreamUtils .interleave(Selectors.roundRobin(), streamOfClubs, streamOfPlayers, streamOfLeagues) .collect(Collectors.toList()); assertThat(interleavedList) .hasSize(7) .containsExactly("Juventus", "Ronaldo", "Serie A", "Barcelona", "Messi", "La Liga", "Liverpool"); 

라운드 로빈 선택기 는 라이브러리에서 Selectors.roundRobin () 으로 제공 되기 때문에 위 코드는 자습서 용 입니다.

3.7. skipUntil ()skipWhile ()

skipUntil () 은 값 이 조건을 충족 할 때까지 값을 건너 뜁니다 .

Integer[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; List skippedUntilGreaterThan5 = StreamUtils .skipUntil(stream(numbers), i -> i > 5) .collect(Collectors.toList()); assertThat(skippedUntilGreaterThan5).containsExactly(6, 7, 8, 9, 10); 

반대로 skipWhile () 은 값이 조건을 충족하는 동안 값을 건너 뜁니다 .

Integer[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; List skippedWhileLessThanEquals5 = StreamUtils .skipWhile(stream(numbers), i -> i <= 5 || ) .collect(Collectors.toList()); assertThat(skippedWhileLessThanEquals5).containsExactly(6, 7, 8, 9, 10); 

skipWhile () 에 대한 한 가지 중요한 점은 조건을 충족하지 않는 첫 번째 값을 찾은 후에도 스트리밍을 계속한다는 것입니다.

List skippedWhileGreaterThan5 = StreamUtils .skipWhile(stream(numbers), i -> i > 5) .collect(Collectors.toList()); assertThat(skippedWhileGreaterThan5).containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 

자바 9 년 이후, dropWhile () 표준 스트림 API는 동일한 기능을 제공합니다 skipWhile ()을 .

3.8. 펴다()

unfold () 는 사용자 정의 생성기를 시드 값에 적용한 다음 생성 된 각 값에 적용하여 잠재적으로 무한한 스트림을 생성합니다.이 스트림은 Optional.empty () 를 반환하여 종료 할 수 있습니다 .

Stream unfolded = StreamUtils .unfold(2, i -> (i < 100) ? Optional.of(i * i) : Optional.empty()); assertThat(unfolded.collect(Collectors.toList())) .containsExactly(2, 4, 16, 256);

3.9. windowed ()

windowed () 는 소스 스트림의 여러 하위 집합을 List의 스트림으로 만듭니다 . 이 메서드는 소스 스트림, 창 크기건너 뛰기 값 을 매개 변수로 사용합니다.

목록 길이는 동일 , 크기 의 동안 킵 값이 하위 집합은 이전 집합을 기준으로 시작 위치를 결정 :

Integer[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8 }; List windowedWithSkip1 = StreamUtils .windowed(stream(numbers), 3, 1) .collect(Collectors.toList()); assertThat(windowedWithSkip1) .containsExactly(asList(1, 2, 3), asList(2, 3, 4), asList(3, 4, 5), asList(4, 5, 6), asList(5, 6, 7)); 

또한 다음 예에서 볼 수 있듯이 마지막 창은 원하는 크기로 보장됩니다.

List windowedWithSkip2 = StreamUtils.windowed(stream(numbers), 3, 2).collect(Collectors.toList()); assertThat(windowedWithSkip2).containsExactly(asList(1, 2, 3), asList(3, 4, 5), asList(5, 6, 7)); 

3.10. 골재()

상당히 다르게 작동하는 두 개의 aggregate () 메서드가 있습니다.

첫 번째 aggregate () 는 주어진 술어에 따라 동일한 값의 요소를 그룹화합니다 .

Integer[] numbers = { 1, 2, 2, 3, 4, 4, 4, 5 }; List aggregated = StreamUtils .aggregate(Arrays.stream(numbers), (int1, int2) -> int1.compareTo(int2) == 0) .collect(Collectors.toList()); assertThat(aggregated).containsExactly(asList(1), asList(2, 2), asList(3), asList(4, 4, 4), asList(5)); 

The predicate receives the values in a contiguous manner. Therefore, the above will give a different result if the number is not ordered.

On the other hand, the second aggregate() is simply used to group together elements from the source stream into groups of the desired size:

List aggregatedFixSize = StreamUtils .aggregate(stream(numbers), 5) .collect(Collectors.toList()); assertThat(aggregatedFixSize).containsExactly(asList(1, 2, 2, 3, 4), asList(4, 4, 5)); 

3.11. aggregateOnListCondition()

aggregateOnListCondition() groups values based on predicate and current active group. The predicate is given the currently active group as a List and the next value. It then must determine if the group should continue or start a new group.

The following example solves a requirement to group contiguous integer values together in a group, where the sum of values in each group must not be greater than 5:

Integer[] numbers = { 1, 1, 2, 3, 4, 4, 5 }; Stream
    
      aggregated = StreamUtils .aggregateOnListCondition(stream(numbers), (currentList, nextInt) -> currentList.stream().mapToInt(Integer::intValue).sum() + nextInt <= 5); assertThat(aggregated) .containsExactly(asList(1, 1, 2), asList(3), asList(4), asList(4), asList(5));
    

4. Streamable

An instance of Stream isn't reusable. For this reason, Streamable provides reusable streams by wrapping and exposing the same methods as the Stream:

Streamable s = Streamable.of("a", "b", "c", "d"); List collected1 = s.collect(Collectors.toList()); List collected2 = s.collect(Collectors.toList()); assertThat(collected1).hasSize(4); assertThat(collected2).hasSize(4);

5. CollectorUtils

CollectorUtils complements the standard Collectors by adding several useful collector methods.

5.1. maxBy() and minBy()

maxBy()finds the maximum value in a stream using supplied projection logic:

Stream clubs = Stream.of("Juventus", "Barcelona", "PSG"); Optional longestName = clubs.collect(CollectorUtils.maxBy(String::length)); assertThat(longestName).contains("Barcelona");

In contrast, minBy()finds the minimum value using the supplied projection logic.

5.2. unique()

독특한 () 수집기는 아주 간단한 일을 : 주어진 스트림이 정확히 1 개 요소가있는 경우는 유일한 값을 반환합니다 :

Stream singleElement = Stream.of(1); Optional unique = singleElement.collect(CollectorUtils.unique()); assertThat(unique).contains(1); 

그렇지 않으면 unique () 에서 예외가 발생합니다.

Stream multipleElement = Stream.of(1, 2, 3); assertThatExceptionOfType(NonUniqueValueException.class).isThrownBy(() -> { multipleElement.collect(CollectorUtils.unique()); }); 

6. 결론

이 기사에서는 Protonpack 라이브러리가 Java Stream API를 사용하기 쉽게 확장하는 방법을 배웠습니다. 일반적으로 사용할 수 있지만 표준 API에는없는 유용한 메서드를 추가합니다.

Java 9부터 Protonpack에서 제공하는 일부 기능은 표준 Stream API에서 사용할 수 있습니다.

평소처럼 코드는 Github에서 찾을 수 있습니다.