배열(Array)은 같은 타입의 데이터를 연속된 메모리 공간에 저장하는 자료 구조
고정 크기 (Static Size)
동일한 타입 (Homogeneous Elements)
배열은 하나의 타입으로만 구성된 데이터를 저장할 수 있다.
인덱스(Index) 접근
배열길이 - 1까지만 유효하다.간단한 구조 & 메모리 효율
제네릭(Generics)을 사용해 다양한 타입의 데이터를 저장할 수 있다.| 인터페이스 | 대표 구현 클래스 | 특징 |
|---|---|---|
| List | ArrayList, LinkedList | - 순서가 있는 데이터 집합 |
HashSet, TreeSet | - 순서가 없는 데이터 집합HashMap, TreeMap | - 키(key)와 값(value)의 쌍Integer.parseInt() 등)스트림은 자바 8에서 도입된 기능으로, 배열이나 컬렉션의 데이터를 함수형(람다)으로 다루기 위한 추상화된 데이터 처리 방식이다.
반복문으로 하나씩 꺼내서 처리하던 방식에서 벗어나, 중간 연산(Intermediate Operation)과 최종 연산(Terminal Operation)을 체이닝(Chaining)하여 선언적으로 데이터를 처리할 수 있다.
이 과정을 체이닝(Chaining) 으로 연결하여 선언적으로 작성할 수 있다.
List<String> list = Arrays.asList("a", "b", "c", "d");
Stream<String> stream = list.stream();
String[] arr = {"a", "b", "c", "d"};
Stream<String> streamFromArray = Arrays.stream(arr);
Stream<String> streamOf = Stream.of("a", "b", "c", "d");
IntStream intStream = IntStream.range(1, 5); // 1,2,3,4
Stream<int> X
중간 연산은 스트림을 변환하거나 필터링하며, 또 다른 스트림을 반환한다.
이러한 중간 연산은 실제로 실행되지 않고 최종 연산이 호출될 때 한꺼번에 실행된다.
filter()Predicate<T>는 boolean을 반환하는 람다식을 의미List<String> list = Arrays.asList("apple", "banana", "avocado", "grape");
List<String> filteredList = list.stream()
.filter(s -> s.startsWith("a"))
.collect(Collectors.toList());
// 결과: ["apple", "avocado"]
map()Function<T, R>를 사용하여 요소를 매핑List<String> list = Arrays.asList("apple", "banana", "orange");
List<String> mappedList = list.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
// 결과: ["APPLE", "BANANA", "ORANGE"]
sorted()List<Integer> numbers = Arrays.asList(3, 1, 4, 2);
List<Integer> sortedList = numbers.stream()
.sorted()
.collect(Collectors.toList());
// 결과: [1, 2, 3, 4]
distinct()List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3);
List<Integer> distinctList = numbers.stream()
.distinct()
.collect(Collectors.toList());
// 결과: [1, 2, 3]
limit(n), skip(n)limit(n): 스트림에서 최대 n개의 요소까지만 추출skip(n): 스트림에서 처음 n개의 요소를 건너뛰고 이후 요소만 가져옴List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> limited = numbers.stream()
.limit(3)
.collect(Collectors.toList());
// [1, 2, 3]
List<Integer> skipped = numbers.stream()
.skip(2)
.collect(Collectors.toList());
// [3, 4, 5]
최종 연산이 호출되면 스트림은 소모(consume)되며, 더 이상 재사용이 불가능
forEach()list.stream()
.forEach(System.out::println);
collect()List<String> collectedList = list.stream()
.collect(Collectors.toList());
reduce()Optional<Integer> sum = numbers.stream(){1,2,3}
.reduce((a, b) -> a + b);
sum.ifPresent(System.out::println);
count(): 스트림의 요소 개수 반환max(), min(): 최대값, 최소값 반환 (Comparator 필요)anyMatch(), allMatch(), noneMatch(): 특정 조건에 부합하는지 검사 후 boolean 결과 반환findFirst(), findAny(): 스트림의 첫 번째 혹은 임의 요소 반환 (Optional)중간 연산은 최종 연산이 일어나기 전까지 실제로 실행되지 않는다. 이를 Lazy Evaluation(지연 연산) 이라고 한다.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class LazyEvaluationExample {
public static void main(String[] args) {
List<String> list = Arrays.asList("apple", "banana", "orange", "grape", "melon");
// 중간 연산만 정의
Stream<String> stream = list.stream()
.filter(s -> {
System.out.println("filtering: " + s);
return s.startsWith("a");
})
.map(s -> {
System.out.println("mapping: " + s);
return s.toUpperCase();
});
System.out.println("스트림이 정의되었지만 아직 처리되지 않았습니다.");
// 최종 연산을 호출하는 순간, 그제야 모든 중간 연산이 실행됨
List<String> result = stream.collect(Collectors.toList());
System.out.println("결과: " + result);
}
}
스트림이 정의되었지만 아직 처리되지 않았습니다.
filtering: apple
mapping: apple
filtering: banana
filtering: orange
filtering: grape
filtering: melon
실행 흐름
filter()와 map()은 중간 연산으로, 즉시 실행되지 않음collect()(최종 연산)가 호출될 때 filter()와 map()이 실제 실행병렬 스트림은 여러 쓰레드가 동시에 스트림의 요소를 처리하므로, 데이터 양이 많을 때 성능 향상을 기대할 수 있다.
import java.util.Arrays;
import java.util.List;
public class ParallelStreamExample {
public static void main(String[] args) {
List<String> list = Arrays.asList("apple", "banana", "orange", "grape", "melon");
list.parallelStream()
.map(String::toUpperCase)
.forEach(s -> System.out.println(Thread.currentThread().getName() + " => " + s));
}
}
ForkJoinPool.commonPool-worker-2 => APPLE
ForkJoinPool.commonPool-worker-4 => GRAPE
ForkJoinPool.commonPool-worker-1 => BANANA
main => ORANGE
ForkJoinPool.commonPool-worker-3 => MELON
filter(), map(), sorted(), distinct(), limit(), skip() 등forEach(), collect(), reduce(), count(), max(), min(), findFirst(), findAny() 등parallelStream()을 이용해 멀티코어를 활용