반응형

스트림의 중개 연산(intermediate operation)

  • 스트림 API에 의해 생성된 초기 스트림은 중개 연산을 통해 또 다른 스트림으로 변환됩니다.
  • 이러한 중개 연산은 스트림을 전달받아 스트림을 반환하므로, 중개 연산은 연속으로 연결해서 사용할 수 있습니다.
  • 또한, 스트림의 중개 연산은 필터-맵(filter-map) 기반의 API를 사용함으로 지연(lazy) 연산을 통해 성능을 최적화할 수 있습니다.
  • 스트림 API에서 사용할 수 있는 대표적인 중개 연산과 그에 따른 메소드는 다음과 같습니다.
    1. 스트림 필터링 : filter(), distinct()
    2. 스트림 변환 : map(), flatMap()
    3. 스트림 제한 : limit(), skip()
    4. 스트림 정렬 : sorted()
    5. 스트림 연산 결과 확인 : peek()

스트림 필터링

  • filter() 메소드는 해당 스트림에서 주어진 조건(predicate)에 맞는 요소만으로 구성된 새로운 스트림을 반환합니다.
  • 또한, distinct() 메소드는 해당 스트림에서 중복된 요소가 제거된 새로운 스트림을 반환합니다.
  • distinct() 메소드는 내부적으로 Object 클래스의 equals() 메소드를 사용하여 요소의 중복을 비교합니다.
IntStream stream1 = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);
//7, 5, 2, 1, 3, 4, 6
//입력된 컬렉션인터페이스간의 비교도 가능한가
IntStream stream2 = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);

// 스트림에서 중복된 요소를 제거함.
stream1.distinct().forEach(e -> System.out.print(e + " "));
System.out.println();

// 스트림에서 홀수만을 골라냄.
stream2.filter(n -> n % 2 != 0).forEach(e -> System.out.print(e + " "));

스트림 변환

  • map() 메소드는 해당 스트림의 요소들을 주어진 함수에 인수로 전달하여, 그 반환값들로 이루어진 새로운 스트림을 반환합니다.
  • 만약 해당 스트림의 요소가 배열이라면, flatMap() 메소드를 사용하여 각 배열의 각 요소의 반환값을 하나로 합친 새로운 스트림을 얻을 수 있습니다.
  • 다음 예제는 문자열로 이루어진 스트림을 map() 메소드를 이용하여 각 문자열의 길이로 이루어진 스트림으로 변환하는 예제입니다.
Stream<String> stream = Stream.of("HTML", "CSS", "JAVA", "JAVASCRIPT");
stream.map(s -> s.length()).forEach(System.out::println);

  • 다음 예제는 여러 문자열이 저장된 배열을 각 문자열에 포함된 단어로 이루어진 스트림으로 변환하는 예제입니다.
String[] arr = {"I study hard", "You study JAVA", "I am hungry"};

Stream<String> stream = Arrays.stream(arr);
// split "+"는 크게 필요 없음
stream.flatMap(s -> Stream.of(s.split(" +"))).forEach(System.out::println);

스트림 제한

  • limit() 메소드는 해당 스트림의 첫 번째 요소부터 전달된 개수만큼의 요소만으로 이루어진 새로운 스트림을 반환합니다.
  • skip()메소드는 해당 스트림의 첫 번째 요소부터 전달된 개수만큼의 요소를 제외한 나머지 요소만으로 이루어진 새로운 스트림을 반환합니다.
IntStream stream1 = IntStream.range(0, 10);
IntStream stream2 = IntStream.range(0, 10);
IntStream stream3 = IntStream.range(0, 10);

// 0, 1, 2, 3을 스킵 4번째 배열까지 스킵
stream1.skip(4).forEach(n -> System.out.print(n + " "));
System.out.println();

// 5, 6, 7, 8, 9을 제한 5번째 배열까지 제한 -> 6번째 이후는 출력안함
stream2.limit(5).forEach(n -> System.out.print(n + " "));
System.out.println();

// 앞에서 3개 스킵하고 난뒤 5개만 제한
stream3.skip(3).limit(5).forEach(n -> System.out.print(n + " "));

스트림 정렬

sorted() 메소드는 해당 스트림을 주어진 비교자(comparator)를 이용하여 정렬합니다.

이때 비교자를 전달하지 않으면 기본적으로 사전 편찬 순(natural order)으로 정렬하게 됩니다.

Stream<String> stream1 = Stream.of("JAVA", "HTML", "JAVASCRIPT", "CSS");
Stream<String> stream2 = Stream.of("JAVA", "HTML", "JAVASCRIPT", "CSS");

// 정방향
stream1.sorted().forEach(s -> System.out.print(s + " "));
System.out.println();

// 역방향
stream2.sorted(Comparator.reverseOrder()).forEach(s -> System.out.print(s + " "));

스트림 연산 결과 확인

  • peek() 메소드는 결과 스트림으로부터 요소를 소모하여 추가로 명시된 동작을 수행합니다.
  • 이 메소드는 원본 스트림에서 요소를 소모하지 않으므로, 주로 연산과 연산 사이에 결과를 확인하고 싶을 때 사용합니다.
  • 따라서 개발자가 디버깅 용도로 많이 사용합니다.
  • peek는 원본 저장소가 변경되면 영향을 받는다.
    • skip(2) 후에 peek를 실행한 것도 limit(5)를 실행한 후에는 skip(2)후에 peek 실행한 것도 limit(5)를 실행한 원본 스트림 만큼만 수행한다.

IntStream stream = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);

stream.peek(s -> System.out.println("원본 스트림 : " + s))
    .skip(2)
    .peek(s -> System.out.println("skip(2) 실행 후 : " + s))
    .limit(5)
    .peek(s -> System.out.println("limit(5) 실행 후 : " + s))
    .sorted()
    .peek(s -> System.out.println("sorted() 실행 후 : " + s))
    .forEach(n -> System.out.println(n));

  • 위의 예제에서 첫 번째 요소인 7과 두 번째 요소인 5는 skip() 메소드에 의해 삭제되므로, 원본 스트림에서만 나타납니다.
  • 하지만 세 번째 요소인 5는 skip() 메소드와 limit() 메소드가 실행된 후에도 존재하므로, 모두 나타납니다.
  • 이렇게 peek() 메소드는 스트림의 각 요소가 해당 중개 연산 후에 어떻게 변화하는지를 보여줍니다.

대표적인 중개 연산 메소드

스트림 API에서 사용할 수 있는 대표적인 중개 연산을 위한 메소드는 다음과 같습니다.

메소드 설명
Stream<T> filter(Predicate<? super T> predicate) 해당 스트림에서 주어진 조건(predicate)에 맞는 요소만으로 구성된 새로운 스트림을 반환함.
<R> Stream<R> map(Functoin<? super T, ? extends R> mapper) 해당 스트림의 요소들을 주어진 함수에 인수로 전달하여, 그 반환값으로 이루어진 새로운 스트림을 반환함.
<R> Stream<R> flatMap(Functoin<? super T, ? extends Stream<? extends R>> mapper) 해당 스트림의 요소가 배열일 경우, 배열의 각 요소를 주어진 함수에 인수로 전달하여, 그 반환값으로 이루어진 새로운 스트림을 반환함.
Stream<T> distinct() 해당 스트림에서 중복된 요소가 제거된 새로운 스트림을 반환함.내부적으로 Object 클래스의 equals() 메소드를 사용함.
Stream<T> limit(long maxSize) 해당 스트림에서 전달된 개수만큼의 요소만으로 이루어진 새로운 스트림을 반환함.
Stream<T> peek(Consumer<? super T> action) 결과 스트림으로부터 각 요소를 소모하여 추가로 명시된 동작(action)을 수행하여 새로운 스트림을 생성하여 반환함.
Stream<T> skip(long n) 해당 스트림의 첫 번째 요소부터 전달된 개수만큼의 요소를 제외한 나머지 요소만으로 이루어진 새로운 스트림을 반환함.
Stream<T> sorted()Stream<T> sorted(Comparator<? super T> comparator) 해당 스트림을 주어진 비교자(comparator)를 이용하여 정렬함.비교자를 전달하지 않으면 영문사전 순(natural order)으로 정렬함.

[참고 자료]

http://www.tcpschool.com/java/java_stream_intermediate

반응형
반응형

스트림 API란?

Java SE 8부터 추가된 스트림 API는 기존의 스트림과는 전혀 다른 개념입니다.

자바에서는 많은 양의 데이터를 저장하기 위해서 배열이나 컬렉션을 사용합니다.

이렇게 저장된 데이터에 접근하기 위해서는 반복문이나 반복자(iterator)를 사용하여 매번 새로운 코드를 작성해야 합니다.

하지만 이렇게 작성된 코드는 길이가 너무 길고 가독성도 떨어지며, 코드의 재사용이 거의 불가능합니다.

즉, 데이터베이스의 쿼리와 같이 정형화된 처리 패턴을 가지지 못했기에 데이터마다 다른 방법으로 접근해야만 했습니다.

이러한 문제점을 극복하기 위해서 Java SE 8부터 스트림(stream) API를 도입합니다.

스트림 API는 데이터를 추상화하여 다루므로, 다양한 방식으로 저장된 데이터를 읽고 쓰기 위한 공통된 방법을 제공합니다.

따라서 스트림 API를 이용하면 배열이나 컬렉션뿐만 아니라 파일에 저장된 데이터도 모두 같은 방법으로 다룰 수 있게 됩니다.

 

스트림 API 특징

스트림 API는 다음과 같은 특징을 가집니다.

  1. 스트림은 외부 반복을 통해 작업하는 컬렉션과는 달리 내부 반복(internal iteration)을 통해 작업을 수행합니다.
  2. 스트림은 재사용이 가능한 컬렉션과는 달리 단 한 번만 사용할 수 있습니다.
  3. 스트림은 원본 데이터를 변경하지 않습니다.
  4. 스트림의 연산은 필터-맵(filter-map) 기반의 API를 사용하여 지연(lazy)연산을 통해 성능을 최적화합니다.
  5. 스트림은 parallelStream() 메소드를 통한 손쉬운 병렬 처리를 지원합니다.

스트림 API의 동작 흐름

스트림 API는 다음과 같이 세 가지 단계에 걸쳐서 동작합니다.

  1. 스트림의 생성
  2. 스트림의 중개 연산 (스트림의 변환)
  3. 스트림의 최종 연산 (스트림의 사용)

다음 그림은 자바 스트림 API가 동작하는 흐름을 나타냅니다.

스트림의 생성

스트림 API는 다음과 같은 다양한 데이터 소스에서 생성할 수 있습니다.

 

1. 컬렉션

  • 자바에서 제공하는 모든 컬렉션의 최고 상위 조상인 Collection 인터페이스에는 stream() 메소드가 정의되어 있습니다.
  • 따라서 Collection 인터페이스를 구현한 모든 List와 Set 컬렉션 클래스에서도 stream() 메소드로 스트림을 생성할 수 있습니다.
  • 또한, parallelStream() 메소드를 사용하면 병렬 처리가 가능한 스트림을 생성할 수 있습니다.
ArrayList<Integer> list = new ArrayList<Integer>();

list.add(4);
list.add(2);
list.add(3);
list.add(1);

// 컬렉션에서 스트림 생성
Stream<Integer> stream = list.stream();
// forEach() 메소드를 이용한 스트림 요소의 순차 접근
stream.forEach(System.out::println);

  • Stream 클래스의 forEach() 메소드는 해당 스트림의 요소를 하나씩 소모해가며 순차적으로 요소에 접근하는 메소드입니다.
  • 따라서 같은 스트림으로는 forEach() 메소드를 한 번밖에 호출할 수 없습니다.
  • 단, 원본 데이터의 요소를 소모하는 것은 아니므로, 같은 데이터에서 또 다른 스트림을 생성하여 forEach() 메소드를 호출하는 것은 가능합니다.

2. 배열

  • 배열에 관한 스트림을 생성하기 위해 `Arrays 클래스`에는 다양한 형태의 `stream()` 메소드가 클래스 메소드로 정의되어 있습니다.
  • 또한, 기본 타입인 `int, long, double` 형을 저장할 수 있는 배열에 관한 스트림이 별도로 정의되어 있습니다.
  • 이러한 스트림은 `java.util.stream 패키지`의 `IntStream, LongStream, DoubleStream` 인터페이스로 각각 제공됩니다.
String[] arr = new String[]{"넷", "둘", "셋", "하나"};

// 배열에서 스트림 생성
Stream<String> stream1 = Arrays.stream(arr);
stream1.forEach(e -> System.out.print(e + " "));
System.out.println();

// 배열의 특정 부분만을 이용한 스트림 생성
Stream<String> stream2 = Arrays.stream(arr, 1, 3);
stream2.forEach(e -> System.out.print(e + " "));

// IntStream 사용시 long, double도 비슷하게 사용가능
int[] int_arr = new int[]{1, 2, 3, 4};
IntStream intStream = Arrays.stream(int_arr);
intStream.forEach(e -> System.out.print(e + " "));

Arrays 클래스의 stream() 메소드는 전체 배열뿐만 아니라 배열의 특정 부분만을 이용하여 스트림을 생성할 수도 있습니다.

 

3. 가변 배개변수

  • Stream 클래스의 of() 메소드를 사용하면 가변 매개변수(variable parameter)를 전달받아 스트림을 생성할 수 있습니다.
// 가변 매개변수에서 스트림 생성
Stream<Double> stream = Stream.of(4.2, 2.5, 3.1, 1.9);
stream.forEach(System.out::println);

4. 지정된 범위의 연속된 정수

  • 지정된 범위의 연속된 정수를 스트림으로 생성하기 위해 IntStream나 LongStream인터페이스에는 range()와 rangeClosed() 메소드가 정의되어 있습니다.
  • range()메소드는 명시된 시작 정수를 포함하지만, 명시된 마지막 정수는 포함하지 않는 스트림을 생성합니다.
  • rangeClosed()메소드는 명시된 시작 정수뿐만 아니라 명시된 마지막 정수까지도 포함하는 스트림을 생성합니다.
// 지정된 범위의 연속된 정수에서 스트림 생성
IntStream stream1 = IntStream.range(1, 4);
stream1.forEach(e -> System.out.print(e + " "));
System.out.println();

IntStream stream2 = IntStream.rangeClosed(1, 4);
stream2.forEach(e -> System.out.print(e + " "));

5. 특정 타입의 난수들

  • 특정 타입의 난수로 이루어진 스트림을 생성하기 위해 Random 클래스에는 ints(), longs(), doubles()와 같은 메소드가 정의되어 있습니다.
  • 이 메소드들은 매개변수로 스트림의 크기를 long타입으로 전달받을 수 있습니다.
  • 이 메소드들은 만약 매개변수를 전달받지 않으면 크기가 정해지지 않은 무한 스트림(infinite stream)을 반환합니다.
  • 이때에는 limit()메소드를 사용하여 따로 스트림의 크기를 제한해야 합니다.
// 특정 타입의 난수로 이루어진 스트림 생성
IntStream stream = new Random().ints(4);
stream.forEach(System.out::println);

6. 람다 표현식

  • 람다 표현식을 매개변수로 전달받아 해당 람다 표현식에 의해 반환되는 값을 요소로 하는 무한 스트림을 생성하기 위해 Stream 클래스에는 iterate()와 generate() 메소드가 정의되어 있습니다.
  • iterate() 메소드는 시드(seed)로 명시된 값을 람다 표현식에 사용하여 반환된 값을 다시 시드로 사용하는 방식으로 무한 스트림을 생성합니다.
  • 반면에 generate() 메소드는 매개변수가 없는 람다 표현식을 사용하여 반환된 값으로 무한 스트림을 생성합니다.
  • 다음 예제는 iterate() 메소드를 이용하여 홀수만으로 이루어진 무한 스트림을 생성하는 예제입니다.
IntStream stream = Stream.iterate(2, n -> n + 2); // 2, 4, 6, 8, 10, ...
stream.forEach(System.out::println);

7. 파일

  • 파일의 한 행(line)을 요소로 하는 스트림을 생성하기 위해 java.nio.file.Files 클래스에는 lines() 메소드가 정의되어 있습니다.
  • 또한, java.io.BufferedReader 클래스의 lines() 메소드를 사용하면 파일뿐만 아니라 다른 입력으로부터도 데이터를 행(line) 단위로 읽어 올 수 있습니다.
String<String> stream = Files.lines(Path path);
/*
//파일을 지정해서 스트림에 입력및 출력 가능
Stream<String> stream = Files.lines(Paths.get("C://agentlog.txt"));
stream.forEach(System.out::println);
*/

8. 빈 스트림

  • 아무 요소도 가지지 않는 빈 스트림은 Stream 클래스의 empty()메소드를 사용하여 생성할 수 있습니다.
// 빈 스트림 생성
Stream<Object> stream = Stream.empty();
System.out.println(stream.count()); // 스트림의 요소의 총 개수를 출력함.


[참고 자료]

http://www.tcpschool.com/java/java_stream_concept

http://www.tcpschool.com/java/java_stream_creation

반응형
반응형

Comparable<T> 인터페이스

  • Comparable인터페이스는 객체를 정렬하는 데 사용되는 메소드인 compareTo()메소드를 정의하고 있습니다.
  • 자바에서 같은 타입의 인스턴스를 서로 비교해야만 하는 클래스들은 모두 Comparable인터페이스를 구현하고 있습니다.
  • 따라서 Boolean을 제외한 래퍼 클래스나 String, Time, Date와 같은 클래스의 인스턴스는 모두 정렬 가능합니다.
  • 이때 기본 정렬 순서는 작은 값에서 큰 값으로 정렬되는 오름차순이 됩니다.

다음 예제는 인스턴스의 비교를 위해 사용자 정의 클래스인 Car 클래스가 Comparable인터페이스를 구현하는 예제입니다.

class Car {
    private String modelName;
    private int modelYear;
    private String color;

    Car(String mn, int my, String c) {
        this.modelName = mn;
        this.modelYear = my;
        this.color = c;
    }

    public int getModelYear() {
        return this.modelYear;
    }

    public String getModel() {
        return this.modelYear + "식 " + this.modelName + " " + this.color;
    }

    public int compareTo(Car obj, Comparable<Car> carComparable) {
        System.out.println(carComparable.compareTo(obj));
    }
}

public class Comparable01 {
    public static void main(String[] args) {
        Car car01 = new Car("아반떼", 2016, "노란색");
        Car car02 = new Car("소나타", 2010, "흰색");

        car01.compareTo(car02, (obj) -> {
            if (car01.getModelYear() == obj.getModelYear()) {
                return 0;
            } else if(car01.getModelYear() < obj.getModelYear()) {
                return -1;
            } else {
                return 1;
            }
        });
    }
}
class Car implements Comparable<Car> {
    private String modelName;
    private int modelYear;
    private String color;

    Car(String mn, int my, String c) {
        this.modelName = mn;
        this.modelYear = my;
        this.color = c;
    }

    public String getModel() {
        return this.modelYear + "식 " + this.modelName + " " + this.color;
    }

    public int compareTo(Car obj) {
        if (this.modelYear == obj.modelYear) {
            return 0;
        } else if(this.modelYear < obj.modelYear) {
            return -1;
        } else {
            return 1;
        }

    }
}

public class Comparable01 {
    public static void main(String[] args) {
        Car car01 = new Car("아반떼", 2016, "노란색");
        Car car02 = new Car("소나타", 2010, "흰색");

        System.out.println(car01.compareTo(car02));
    }
}

실행 결과

Comparable인터페이스는 다음과 같은 메소드를 사용하여 객체를 정렬합니다.

메소드 설명
int compareTo(T o) 해당 객체와 전달된 객체의 순서를 비교함.

Comparator<T> 인터페이스

  • Comparable인터페이스는 Comparable인터페이스와 같이 객체를 정렬하는 데 사용되는 인터페이스입니다.
  • Comparable인터페이스를 구현한 클래스는 기본적으로 오름차순으로 정렬됩니다.
  • 반면에 Comparator인터페이스는 내림차순이나 아니면 다른 기준으로 정렬하고 싶을 때 사용할 수 있습니다.
  • 즉, Comparator인터페이스를 구현하면 오름차순 이외의 기준으로도 정렬할 수 있게 되는 것입니다.
  • 이때 Comparator인터페이스를 구현한 클래스에서는 compare()메소드를 재정의하여 사용하게 됩니다.

다음 예제는 요소를 내림차순으로 정렬하여 저장하는 TreeSet 인스턴스를 생성하기 위해 Comparator인터페이스를 구현하는 예제입니다.

public class Comparable02 {
	public static void main(String[] args) {
		TreeSet<Integer> ts = new TreeSet<>((o1, o2) -> {
		    if(o1 instanceof Comparable && o2 instanceof Comparable) {
		        Integer c1 = o1;
		        Integer c2 = o2;
		
		        return c2.compareTo(c1);
		    }
		    return -1;
		});
		
		ts.add(30);
		ts.add(40);
		ts.add(20);
		ts.add(10);
		
		Iterator<Integer> iter = ts.iterator();
		while(iter.hasNext()) {
		    System.out.println(iter.next());
		}
	}
}
import java.util.*;

class DescendingOrder implements Comparator<Integer> {
    public int compare(Integer o1, Integer o2) {
        if(o1 instanceof Comparable && o2 instanceof Comparable) {
            Integer c1 = (Integer)o1;
            Integer c2 = (Integer)o2;
            return c2.compareTo(c1);
        }
        return -1;
    }
}

public class Comparable02 {
    public static void main(String[] args) {
        TreeSet<Integer> ts = new TreeSet<Integer>(new DescendingOrder());

        ts.add(30);
        ts.add(40);
        ts.add(20);
        ts.add(10);

        Iterator<Integer> iter = ts.iterator();
        while(iter.hasNext()) {
           System.out.println(iter.next());
        }	
    }
}

실행 결과

Comparator인터페이스는 다음과 같은 메소드를 사용하여 객체를 정렬합니다.

메소드 설명
int compare(T o1, T o2) 전달된 두 객체의 순서를 비교함.
boolean equals(Object obj) 해당 comparator와 전달된 객체가 같은지를 확인함.
default Comparator<T> reversed() 해당 comparator의 역순인 comparator를 반환함.

[참고 자료]

http://www.tcpschool.com/java/java_collectionFramework_comparable

반응형
반응형

Iterator<E> 인터페이스

자바의 컬렉션 프레임워크는 컬렉션에 저장된 요소를 읽어오는 방법을 Iterator인터페이스로 표준화하고 있습니다.

Collection 인터페이스에서는 Iterator인터페이스를 구현한 클래스의 인스턴스를 반환하는 iterator()메소드를 정의하여 각 요소에 접근하도록 하고 있습니다.

따라서 Collection 인터페이스를 상속받는 List와 Set인터페이스에서도 iterator()메소드를 사용할 수 있습니다.

 

다음 예제는 연결 리스트를 반복자(iterator)를 사용하여 순회하는 예제입니다.

LinkedList<Integer> lnkList = new LinkedList<Integer>();

lnkList.add(4);
lnkList.add(2);
lnkList.add(3);
lnkList.add(1);

Iterator<Integer> iter = lnkList.iterator();
while (iter.hasNext()) {
    System.out.print(iter.next() + " ");
}

실행 결과

Iterator인터페이스는 다음과 같은 메소드를 사용하여 컬렉션의 각 요소에 접근할 수 있습니다.

메소드 설명
boolean hasNext() 해당 이터레이션(iteration)이 다음 요소를 가지고 있으면 true를 반환하고, 더 이상 다음 요소를 가지고 있지 않으면 false를 반환함.
E next() 이터레이션(iteration)의 다음 요소를 반환함.
default void remove() 해당 반복자로 반환되는 마지막 요소를 현재 컬렉션에서 제거함. (선택적 기능)

하지만 현재 자바에서는 될 수 있으면 JDK 1.5부터 추가된 Enhanced for 문을 사용하도록 권장하고 있습니다.

Enhanced for 문을 사용하면 반복자(iterator)와 같은 성능을 유지하면서도 코드의 명확성을 확보하고 발생할 수 있는 버그를 예방해 줍니다.

하지만 요소의 선택적 제거나 대체 등을 수행하기 위한 경우에는 반복자(iterator)를 사용해야만 합니다.

Enumeration<E> 인터페이스

  • Enumeration인터페이스는 JDK 1.0부터 사용해 온 Iterator인터페이스와 같은 동작을 하는 인터페이스입니다.
  • Enumeration인터페이스는 hasMoreElements()와 nextElement()메소드를 사용하여 Iterator와 같은 작업을 수행합니다.
  • 하지만 현재에는 기존 코드와의 호환성을 위해서만 남아있으므로, Enumeration인터페이스보다는 Iterator인터페이스를 사용하는 것이 좋습니다.

ListIterator<E> 인터페이스

  • ListIterator인터페이스는 Iterator인터페이스를 상속받아 여러 기능을 추가한 인터페이스입니다.
  • Iterator인터페이스는 컬렉션의 요소에 접근할 때 한 방향으로만 이동할 수 있습니다.
  • 하지만 JDK 1.2부터 제공된 ListIterator인터페이스는 컬렉션 요소의 대체, 추가 그리고 인덱스 검색 등을 위한 작업에서 양방향으로 이동하는 것을 지원합니다.
  • 단, ListIterator인터페이스는 List 인터페이스를 구현한 List 컬렉션 클래스에서만 listIterator() 메소드를 통해 사용할 수 있습니다.

다음 예제는 리스트 반복자를 사용하여 리스트의 모든 요소를 각각 순방향과 역방향으로 출력하는 예제입니다.

LinkedList<Integer> lnkList = new LinkedList<Integer>();

lnkList.add(4);
lnkList.add(2);
lnkList.add(3);
lnkList.add(1);

ListIterator<Integer> iter = lnkList.listIterator();
while (iter.hasNext()) {
    System.out.print(iter.next() + " ");
}
System.out.println();

while (iter.hasPrevious()) {
    System.out.print(iter.previous() + " ");
}

실행 결과

ListIterator인터페이스는 다음과 같은 메소드를 사용하여 컬렉션의 각 요소에 접근할 수 있습니다.

메소드 설명
void add(E e) 해당 리스트(list)에 전달된 요소를 추가함. (선택적 기능)
boolean hasNext() 이 리스트 반복자가 해당 리스트를 순방향으로 순회할 때 다음 요소를 가지고 있으면 true를 반환하고, 더 이상 다음 요소를 가지고 있지 않으면 false를 반환함.
boolean hasPrevious() 이 리스트 반복자가 해당 리스트를 역방향으로 순회할 때 다음 요소를 가지고 있으면 true를 반환하고, 더 이상 다음 요소를 가지고 있지 않으면 false를 반환함.
E next() 리스트의 다음 요소를 반환하고, 커서(cursor)의 위치를 순방향으로 이동시킴.
int nextIndex() 다음 next() 메소드를 호출하면 반환될 요소의 인덱스를 반환함.
E previous() 리스트의 이전 요소를 반환하고, 커서(cursor)의 위치를 역방향으로 이동시킴.
int previousIndex() 다음 previous() 메소드를 호출하면 반환될 요소의 인덱스를 반환함.
void remove() next()나 previous() 메소드에 의해 반환된 가장 마지막 요소를 리스트에서 제거함. (선택적 기능)
void set(E e) next()나 previous() 메소드에 의해 반환된 가장 마지막 요소를 전달된 객체로 대체함. (선택적 기능)

[참고 자료]

http://www.tcpschool.com/java/java_collectionFramework_iterator

반응형

+ Recent posts