Post

Java 여러 컬렉션 결합

1. 설정 컬렉션

1
2
Collection<String> collectionA = Arrays.asList("S", "T");
Collection<String> collectionB = Arrays.asList("U", "V");

2. 자바 8 스트림 API 사용

Java API의 Stream 인터페이스는 컬렉션을 보다 쉽게 처리할 수 있는 유용한 메서드를 제공한다. 컬렉션을 결합하는데 사용되는 concat()flatMap() 메서드이다.

Stream을 얻으면 집계 작업을 수행할 수 있다.

1) concat() 메서드 사용

정적 메서드 concat()은 요소가 첫 번째 Stream의 모든 요소와 두 번째 Stream의 모든 요소인 느리게 연결된 Stream을 생성하여 두 개의 Stream을 논리적으로 결합 한다.

아래 예제에서는 concat() 메서드를 사용하여 collectionA 와 collectionB를 결합한다.

1
2
3
Stream<String> combinedStream = Stream.concat(
  collectionA.stream(),
  collectionB.stream());

둘 이상의 Streams를 결합해야 하는 경우 원래 호출 내에서 concat() 메서드를 다시 호출할 수 있다.

1
2
3
Stream<String> combinedStream = Stream.concat(
  Stream.concat(collectionA.stream(), collectionB.stream()), 
  collectionC.stream());

Java 8 스트림은 재사용할 수 없으므로 변수에 할당할 때 이를 고려해야 한다.

2) flatMap() 메서드 사용

flatMap() 메서드는 이 Stream의 각 요소를 제공된 매핑 함수를 각 요소에 적용하여 생성된 매핑된 Stream의 내용으로 교체한 후 Stream을 반환한다.

아래 예제는 flatMap() 메서드를 사용하여 컬렉션을 병합하는 방법이다. 처음에는 요소가 두 컬렉션인 Stream을 가져온 다음 병합된 목록으로 수집하기 전에 Stream을 평면화한다.

1
2
3
4
Stream<String> combinedStream = Stream.of(collectionA, collectionB)
  .flatMap(Collection::stream);
Collection<String> collectionCombined = 
  combinedStream.collect(Collectors.toList());

3. 구아바 사용

Google의 Guava 라이브러리는 컬렉션에서 작동하기 위한 몇 가지 편리한 방법을 제공하며 Java 6 이상에서 사용할 수 있다.

1) Iterables.concat() 메서드 사용

Iterables.concat() 메서드는 컬렉션 병합에 사용되는 Guava의 편리한 메서드 중 하나이다.

1
2
Iterable<String> combinedIterables = Iterables.unmodifiableIterable(
  Iterables.concat(collectionA, collectionA));

반환된 Iterable은 컬렉션 으로 변환할 수 있다.

1
Collection<String> collectionCombined = Lists.newArrayList(combinedIterables);

2) 메이븐 종속성

프로젝트에 Guava 라이브러리를 포함하려면 Maven pom.xml 파일에 다음 종속성을 추가한다.

1
2
3
4
5
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

Maven Central 리포지토리에서 최신 버전의 Guava 라이브러리를 찾을 수 있다.

4. Apache Commons Collection 사용

Apache Commons Collections는 다양한 컬렉션 작업을 지원하는 또 다른 유틸리티 라이브러리이다. 라이브러리는 컬렉션을 결합하는데 사용할 수 있는 두 가지 유틸리티 메서드를 제공한다.

1) IterableUtils.chainedIterable() 메서드 사용

IterableUtils 클래스는 Iterable 인스턴스에 대한 유틸리티 메서드 및 데코레이터를 제공 한다. 여러 Iterable을 하나로 결합하는데 사용할 수 있는 chainedIterable() 메서드를 제공한다.

1
Iterable<String> combinedIterables = IterableUtils.chainedIterable(collectionA, collectionB);

2) CollectionUtils.union() 메서드 사용

Collection 인스턴스에 대한 유틸리티 메서드 및 데코레이터는 CollectionUtils 클래스에서 제공한다. 이 클래스의 union() 메서드는 주어진 Iterable 인스턴스의 합집합을 포함하는 Collection을 반환한다.

1
Iterable<String> combinedIterables = CollectionUtils.union(collectionA, collectionB);

union() 메서드의 경우 반환된 컬렉션의 각 요소의 카디널리티는 주어진 두 Iterables에서 해당 요소의 카디널리티의 최대값과 같다. 즉, 결합된 컬렉션은 첫 번째 컬렉션의 요소와 첫 번째 컬렉션에 없는 두 번째 컬렉션의 요소로만 구성된다.

3) 메이븐 종속성

프로젝트에 Apache Commons Collections 라이브러리를 포함하려면 Maven pom.xml 파일에 다음 종속성을 추가한다.

1
2
3
4
5
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.1</version>
</dependency>

Maven Central 리포지토리에서 최신 버전의 Apache Commons 라이브러리를 찾을 수 있다.

5. 자바 7 사용

여전히 Java 7을 사용 중이고 Guava와 같은 타사 라이브러리를 사용하지 않으려면 addAll() 메서드를 사용하여 여러 컬렉션의 요소를 결합하거나 자체 유틸리티 메서드를 작성하여 Iterables를 결합할 수 있다.

1) addAll() 메서드 사용

컬렉션을 결합하는 가장 간단한 솔루션은 다음 List 예제와 같이 addAll() 메서드를 사용 하는 것이지만 이 메서드는 처음 두 컬렉션에 있는 동일한 개체에 대한 추가 참조를 사용하여 새 컬렉션을 생성한다는 점에 유의할 가치가 있다.

1
2
3
List<String> listC = new ArrayList<>();
listC.addAll(listA);
listC.addAll(listB);

2) 사용자 지정 concat() 메서드 작성

아래 예제는 두 개의 Iterable을 허용 하고 병합된 Iterable 객체를 반환하는 concat() 메서드를 정의한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public static <E> Iterable<E> concat(
  Iterable<? extends E> i1,
  Iterable<? extends E> i2) {
        return new Iterable<E>() {
            public Iterator<E> iterator() {
                return new Iterator<E>() {
                    Iterator<? extends E> listIterator = i1.iterator();
                    Boolean checkedHasNext;
                    E nextValue;
                    private boolean startTheSecond;

                    void theNext() {
                        if (listIterator.hasNext()) {
                            checkedHasNext = true;
                            nextValue = listIterator.next();
                        } else if (startTheSecond)
                            checkedHasNext = false;
                        else {
                            startTheSecond = true;
                            listIterator = i2.iterator();
                            theNext();
                        }
                    }

                    public boolean hasNext() {
                        if (checkedHasNext == null)
                            theNext();
                        return checkedHasNext;
                    }

                    public E next() {
                        if (!hasNext())
                            throw new NoSuchElementException();
                        checkedHasNext = null;
                        return nextValue;
                    }

                    public void remove() {
                        listIterator.remove();
                    }
                };
            }
        };
    }

concat() 메서드는 두 컬렉션을 인수로 전달하여 호출할 수 있다.

1
2
Iterable<String> combinedIterables = concat(collectionA, collectionB);
Collection<String> collectionCombined = makeListFromIterable(combinedIterables);

Iterable을 List로 사용할 수 있어야 하는 경우 Iterable의 멤버를 사용하여 List를 생성하는 makeListFromIterable() 메서드를 사용할 수 있다.

1
2
3
4
5
6
7
public static <E> List<E> makeListFromIterable(Iterable<E> iter) {
    List<E> list = new ArrayList<E>();
    for (E item : iter) {
        list.add(item);
    }
    return list;
}

[출처 및 참고]

This post is licensed under CC BY 4.0 by the author.