스트림을 사용하면, 데이터 소스가 무엇이냐에 관계없이 같은 방식으로 데이터를 가공/처리 할 수 있습니다. 다른 말로, 배열이냐 컬렉션이냐에 관계없이 하나의 통합된 방식으로 데이터를 다룰 수 있게 되었다는 뜻이다.
public class StreamOperator {
public static void main(String[] args) {
// ArrayList
List<String> fruitList = new ArrayList<>();
fruitList.add("바나나 ");
fruitList.add("사과 ");
fruitList.add("오렌지 ");
// 배열
String[] fruitArray = {"바나나 ", "사과 ", "오렌지 "};
// 각각 스트림 생성
Stream<String> ListStream = fruitList.stream();
Stream<String> ArrayStream = Arrays.stream(fruitArray);
// 출력
ListStream.forEach(System.out::print);
ArrayStream.forEach(System.out::print);
}
}
//출력값
바나나 사과 오렌지 바나나 사과 오렌지
1)스트림 만들기
2)중간 연산(0~n번) : 연산 결과가 스트림인 연산, 반복 허용
3)최종 연산(0~1번) : 연산 결과가 스트림이 아닌 연산, 단 한번만 적용 가능
중간연산
distinct() : 중복제거
limit() : 자르기
sorted() : 정렬
최종 연산
forEach(System.out::println) : forEach가 스트림의 요소를 하나씩 꺼내 출력함
- 스트림 처리 과정은 생성, 중간 연산, 최종 연산 세 단계의 파이프라인으로 구성된다.
- 스트림은 원본 데이터 소스를 변경하지 않는다.
- 스트림은 일회용이다.
- 스트림은 내부 반복자이다.
3.스트림은 Iterator처럼 일회용이다.
4.스트림은 내부 반복자이다.
위에서 확인할 수 있는 것처럼, 외부 반복자의 경우 요소가 필요할 때마다 순차적으로 컬렉션에서 필요한 요소들을 불러오는 반면, 내부반복자는 데이터 처리 코드만 컬렉션 내부로 주입해줘서 그 안에서 모든 데이터 처리가 이뤄지도록 한다.
5.기본형 스트림 - IntStream, LongStream, DoubleStram
왜 사용? 오토박싱&언박싱의 비효율이 제거.(오토박싱 : 객체로 변환, 언박싱 : 오토박싱 반대)
sum, average,count,min,max 대표적인 메서드가 있다.
public class StreamCreator {
public static void main(String[] args) {
// int형 배열로 스트림 생성
int[] intArr = {1,2,3,4,5,6,7};
IntStream intStream = Arrays.stream(intArr);
// 숫자와 관련된 경우 intStream을 사용하는 것을 권장
System.out.println("sum=" + intStream.sum());
}
}
//출력값
sum=28
public class StreamCreator {
public static void main(String[] args) {
// 문자열 배열 선언 및 할당
String[] arr = new String[]{"김코딩", "이자바", "박해커"};
// 문자열 스트림 생성
Stream<String> stream = Arrays.stream(arr);
// 출력
stream.forEach(System.out::println);
}
}
// 출력값
김코딩
이자바
박해커
public class StreamCreator {
public static void main(String[] args) {
String[] arr = new String[]{"김코딩", "이자바", "박해커"};
Stream<String> stream = Stream.of(arr);
stream.forEach(System.out::println);
}
}
Arrays.stream() 와 Stream.of() 메서드 모두 동일한 값을 출력하고 있기에
배열을 스트림을 생성할 때 편한거 쓰시면 된다.
List,Set 컬렉션 타입의 경우 최상위 클래스인 Collection에 정의된 stream() 메서드를 사용해서 스트림을 생성할 수 있다.
public class StreamCreator {
public static void main(String[] args) {
// asList()를 사용해서 List 객체를 만듬
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
Stream<Integer> stream = list.stream();
stream.forEach(System.out::println); ->람다식 (i) -> System.out.println(i)
}
}
빈번하게 사용되는 필터링, 매핑, 정렬등 중심으로 설명하겠다.
public class FilteringExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("김코딩", "이자바", "박해커", "김코딩", "박해커");
names.stream()
.distinct()
.forEach(element -> System.out.print(element + " "));
System.out.println();
names.stream()
// .filter(element -> element.startsWith("김")) // 김씨 성을 가진 요소만 필터링
.filter(element -> element.contains("김")) // contains 비교 메서드 이용 가능
.forEach(element -> System.out.print(element + " "));
System.out.println();
names.stream()
.distinct()
.filter(element -> element.contains("김"))
.forEach(element -> System.out.println(element + " "));
}
}
filter()메서드와 마찬가지로 값을 변환하기 위한 조건을 람다식으로 정의함.
public class IntermediateOperationExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("kimcoding", "javalee", "hackerna", "luckyguy");
names.stream()
.map(element -> element.toUpperCase()) //요소들을 하나씩 대문자로 변환
.forEach(element -> System.out.println(element + " "));
}
}
-> 특정 형태로 변환
public class IntermediateOperationExample {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,3,6,9);
list.stream()
.map(num -> num*3)
.forEach(num -> System.out.print(num + " "));
}
}
public class IntermediateOperationExample {
public static void main(String[] args) {
String[][] namesArray = new String[][]{
{"박해커","이자바"} , {"김코딩","나박사"}
};
Arrays.stream(namesArray)
.map(inner -> Arrays.stream(inner))
.forEach(element -> System.out.println(element + " "));
}
}
객체값을 출력한다. 이유는 map() 메서드는 Stream<String[]> 즉 문자열 배열들의 스트림을 반환하기 때문이다. '박해커, 이자바, 김코딩, 나박사'로 나오려면 문자열 배열이 아닌 Stream(String)이 되어야 한다.
이때 flatMap() 메서드를 사용한다.
public class IntermediateOperationExample {
public static void main(String[] args) {
String[][] namesArray = new String[][]{
{"박해커","이자바"} , {"김코딩","나박사"}
};
Arrays.stream(namesArray)
.flatMap(Arrays::stream)
.forEach(element -> System.out.println(element + " "));
}
}
flatMap()은 중첩 구조를 제거하고 단일 컬렉션(Stream(string))으로 만들어주는 역할을 한다.
public class IntermediateOperationExample {
public static void main(String[] args) {
List<String> animals = Arrays.asList("Tiger","Lion","Monkey","Duck","Horse","Cow");
animals.stream()
.sorted()
.forEach(element -> System.out.print(element + " "));
}
}
public class IntermediateOperationExample {
public static void main(String[] args) {
List<String> animals = Arrays.asList("Tiger","Lion","Monkey","Duck","Horse","Cow");
animals.stream()
.sorted(Comparator.reverseOrder())
.forEach(element -> System.out.print(element + " "));
}
}
Comparator 인터페이스 안에 reverseOrder() 메서드를 통해 역순 정렬 한다.
🔻skip() - 스트림의 일부 요소들을 건너뜀
public class IntermediateOperationExample {
public static void main(String[] args) {
// 1~10 범위의 정수로 구성된 스트림 생성
IntStream intStream = IntStream.rangeClosed(1, 10);
// 앞의 5개의 숫자를 건너뛰고 숫자 6부터 출력
intStream.skip(5).forEach(System.out::println);
}
}
🔻limit() - 스트림의 일부를 자름
public class IntermediateOperationExample {
public static void main(String[] args) {
// 1~10 범위의 정수로 구성된 스트림 생성
IntStream intStream = IntStream.rangeClosed(1, 10);
// 앞에서부터 5개의 숫자만 출력
intStream.limit(5).forEach(System.out::println);
}
}
🔻peek() - forEach() 와 마찬가지로, 요소들을 순회하며 특정 작업을 수행합니다. forEach() 와의 핵심적인 차이는 중간 연산자인지의 여부
public class IntermediateOperationExample {
public static void main(String[] args) {
// 요소들을 사용하여 IntStream 생성
IntStream intStream3 = IntStream.of(1, 2, 2, 3, 3, 4, 5, 5, 7, 7, 7, 8);
// 짝수만 필터링하여 합계 구하기
int sum = intStream3.filter(element -> element % 2 == 0)
.peek(System.out::println)
.sum();
System.out.println("합계 = " + sum);
}
}
// 출력값
2
2
4
8
합계 = 16
public class TerminalOperationExample {
public static void main(String[] args) {
int[] intArray = {1,2,3,4,5};
//카운팅
long count = Arrays.stream(intArray)
.count();
System.out.println("카운트 개수 : " + count);
//합계
long sum = Arrays.stream(intArray)
.sum();
System.out.println("합계 : " + sum);
//평균
double average = Arrays.stream(intArray)
.average()
//average값을 더블형 변수에 넣기 위해 추출하는 메서드
.getAsDouble();
System.out.println("평균값 : " + average);
//최대값
int max = Arrays.stream(intArray)
.max()
.getAsInt();
System.out.println("최대값 : " + max);
//최소값
int min = Arrays.stream(intArray)
.min()
.getAsInt();
System.out.println("최소값 : " + min);
//배열의 첫번째 요소
int first = Arrays.stream(intArray)
.findFirst()
.getAsInt();
System.out.println("배열의 첫번째 요소 : " + first);
}
}
그룹
분할