List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
// Iterator 생성
Iterator<Integer> it = list.iterator();
// 리스트를 순회하며 값 출력
while (it.hasNext()) {
int num = it.next();
System.out.print(num);
}
원래는 위와 같이 표현되어야 함. 하지만 스트림을 이용하면 아래와 같이 됨.
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = list.stream();
stream.forEach(System.out::print);
말그대로 선언형을 사용함으로 써 더 간결하게, 알아보기 쉽게 표현할 수 있다.
예를하나 더 들어보자!
// List에 있는 숫자들 중에서 4보다 큰 짝수의 합계 구하기
List<Integer> numbers = List.of(1, 3, 6, 7, 8, 11);
int sum = 0;
for(int number : numbers){
if(number > 4 && (number % 2 == 0)){
sum += number;
}
}
위는 명령형 프로그래밍 방식! 아래는 선언형 프로그래밍 방식
// List에 있는 숫자들 중에서 4보다 큰 짝수의 합계 구하기
List<Integer> numbers = List.of(1, 3, 6, 7, 8, 11);
int sum =
numbers.stream()
.filter(number -> number > 4 && (number % 2 == 0))
.mapToInt(number -> number)
.sum();
mapToInt는 스트림에서 걸러진 값들을 int 타입의 정수로 바꿔주고 있다.
예제
// 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);
각각 데이터 소스에 따라 스트림을 생성해준 다음 forEach() 동일한 메서드를 이용하여 각 요소들을 순회하며 출력해주고 있다.
List와 배열의 스트림화에대해선 외워두자!
참고로 forEach() 메서드는 람다식 안에 정의된 어떤 명령을 실행하는 데 사용하는 최종 연산자임.

int sum =
numbers.stream()
.filter(number -> number > 4 && (number % 2 == 0))
.mapToInt(number -> number)
.sum();
// 문자열 배열 선언 및 할당
String[] arr = new String[]{"김코딩", "이자바", "박해커"};
// 문자열 스트림 생성
Stream<String> stream = Arrays.stream(arr);
// 출력
stream.forEach(System.out::println);
// 문자열 배열 선언 및 할당
String[] arr = new String[]{"김코딩", "이자바", "박해커"};
// 문자열 스트림 생성
Stream<String> stream = Stream.of(arr);
// 출력
stream.forEach(System.out::println);
두가지 방법으로 배열에서 스트림을 생성할 수 있다.
스트림을 생성할 때 문자열 배열이 숫자로 되어있다면 int형 배열로 스트림을 생성하는 것이 좋다.
IntStream 의 경우에는 숫자와 관련한 여러 유용한 메서드들이 정의되어 있기 때문임.
// int형 배열로 스트림 생성
int[] intArr = {1,2,3,4,5,6,7};
IntStream intStream = Arrays.stream(intArr);
// 숫자와 관련된 경우 intStream을 사용하는 것을 권장
System.out.println("sum=" + intStream.sum());
// System.out.println("average=" + intStream.average());
IntStream을 이용하여 sum()이나 average() 메서드를 간편하게 이용할 수 있다.
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
Stream<Integer> stream = list.stream();
stream.forEach(System.out::print);
예제
IntStream ints = new Random().ints();
ints.forEach(System.out::println);
범위를 제한 하려면 ints() 에 매개변수를 넣어주거나, Random().ints().limit(5)로 해결가능함.
//특정 범위의 정수
IntStream intStream = IntStream.rangeClosed(1, 10);
intStream.forEach(System.out::println);
//출력값
12345678910
rangeClosed() 는 해당 매개변수의 범위를 포함하여 출력하고, range()는 매개변수의 범위를 제외하고 출력한다.
List<String> names = Arrays.asList("김코딩", "이자바", "박해커", "김코딩", "박해커");
names.stream()
.distinct() //중복 제거
.forEach(element -> System.out.println(element));
System.out.println();
names.stream()
.filter(element -> element.startsWith("김")) // 김씨 성을 가진 요소만 필터링
.forEach(element -> System.out.println(element));
System.out.println();
names.stream()
.distinct() //중복제거
.filter(element -> element.startsWith("김")) // 김씨 성을 가진 요소만 필터링
.forEach(element -> System.out.println(element));
forEach 안의 문법의 경우
forEach(element -> System.out.println(element)) forEach(System.out::println)둘중에 원하는걸 써도 된다.
List<String> names = Arrays.asList("kimcoding", "javalee", "hackerna", "luckyguy");
names.stream()
.map(element -> element.toUpperCase()) // 요소들을 하나씩 대문자로 변환
.forEach(element->System.out.println(element));
// 출력값
KIMCODING
JAVALEE
HACKERNA
LUCKYGUY
toUpperCase() 는 대문자로 변환해줌
map(number -> number * 3)과 같이 이용할 수 도 있음
String[][] namesArray = new String[][]{{"박해커", "이자바"}, {"김코딩", "나박사"}};
// 기대하는 출력값
박해커
이자바
김코딩
나박사
Arrays.stream(namesArray).flatMap(Arrays::stream).forEach(System.out::println);
List<String> animals = Arrays.asList("Tiger", "Lion", "Monkey", "Duck", "Horse", "Cow");
// 인자값 없는 sort() 호출
animals.stream().sorted().forEach(System.out::println);
// 출력값
Cow
Duck
Horse
Lion
Monkey
Tiger
List<String> animals = Arrays.asList("Tiger", "Lion", "Monkey", "Duck", "Horse", "Cow");
// 인자값에 Comparator 인터페이스에 규정된 메서드 사용
animals.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
// 출력값
Tiger
Monkey
Lion
Horse
Duck
Cow
// 1~10 범위의 정수로 구성된 스트림 생성
IntStream intStream = IntStream.rangeClosed(1, 10);
// 앞의 5개의 숫자를 건너뛰고 숫자 6부터 출력
intStream.skip(5).forEach(System.out::println);
// 출력값
6
7
8
9
10
// 1~10 범위의 정수로 구성된 스트림 생성
IntStream intStream = IntStream.rangeClosed(1, 10);
// 앞에서부터 5개의 숫자만 출력
intStream.limit(5).forEach(System.out::println);
// 출력값
1
2
3
4
5
forEach() 메서드가 스트림 파이프라인에서 사용되면 해당스트림은 닫히고 모든 연산이 종료된다.
count() : 전체 요소 갯수
sum() : 전체 요소 합
average() : 전체 요소 평균값 - getAsDouble() 을 보통 같이씀.
max() : 최대값 - getAsInt() 같이씀.
min() : 최소값 - getAsInt() 같이씀.
findFirst() : 배열의 첫 요소를 찾아줌
스트림을 사용할때 정의된 이름.stream() 으로 쓰던가 아니면, stream을 정의하고 그걸로 쓴다.
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Stream<Integer> stream = list.stream(); // stream()을 정의하고 쓰는방법 stream.forEach(System.out::print); 으로 쓰던지 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); list.stream().forEach(System.out::print); //이름+stream() 으로쓰는방법 로 쓰던지
import java.util.Arrays;
public class TerminalOperationExample {
public static void main(String[] args) throws Exception {
// int형 배열 생성
int[] intArray = {2,4,6};
// allMatch()
boolean result = Arrays.stream(intArray).allMatch(element-> element % 2 == 0);
System.out.println("요소 모두 2의 배수인가요? " + result);
// anyMatch()
boolean result = Arrays.stream(intArray).anyMatch(element-> element % 3 == 0);
System.out.println("요소 중 하나라도 3의 배수가 있나요? " + result);
// noneMatch()
boolean result = Arrays.stream(intArray).noneMatch(element -> element % 3 == 0);
System.out.println("요소 중 3의 배수가 하나도 없나요? " + result);
}
}
T reduce(T identity, BinaryOperator<T> accumulator)
기본형은 이렇게 되는데, identity는 특정 연산을 시작하는 초기값 accumulator는 조건식임
예제
int[] intArray = {1,2,3,4,5};
int sum2= Arrays.stream(intArray)
.map(element -> element * 2)
.reduce(5, (a ,b) -> a + b);
System.out.println("초기값이 있는 reduce(): " + sum2);
초기값이 있는 reduce(): 35
처음에 모든 배열에 *2를하여 {2,4,6,8,10}을 만들고, 초기값 5부터 계속 더해감
public class TerminalOperationExample {
public static void main(String[] args) {
// Student 객체로 구성된 배열 리스트 생성
List<Student> totalList = Arrays.asList(
new Student("김코딩", 100, Student.Gender.Male),
new Student("박해커", 80, Student.Gender.Male),
new Student("이자바", 90, Student.Gender.Female),
new Student("나미녀", 60, Student.Gender.Female)
);
// 스트림 연산 결과를 Map으로 반환
Map<String, Integer> maleMap = totalList.stream()
.filter(s -> s.getGender() == Student.Gender.Male)
.collect(Collectors.toMap(
student -> student.getName(), // Key
student -> student.getScore() // Value
));
// 출력
System.out.println(maleMap);
}
}
class Student {
public enum Gender {Male, Female};
private String name;
private int score;
private Gender gender;
public Student(String name, int score, Gender gender) {
this.name = name;
this.score = score;
this.gender = gender;
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
public Gender getGender() {
return gender;
}
}
// 출력값
{김코딩=100, 박해커=80}