람다식은 데이터가 많을 때는 느리다. 하지만 데이터가 적을 때는 직관적이고 좋다.
스트림은 병렬처리를 해서 속도를 극대화하는 용도이다.
컬렉션의 정보를 전달해서 컬렉션을 반복 처리하기 위해서 사용한다
Stream<String> stream = list.stream();
stream.forEach(item -> {...});
stream과 iterator의 차이
1.내부반복자 이므로 처리 속도가 빠르고 병렬처리에 효율적이다.
-> 콜백함수인 인터페이스 참조변수를 통해 전달되기 때문에 속도가 빠르지 않다 하지만 병렬처리를 했을때는 빠르다.
2.람다식으로 다양한 요소처리를 정의 할 수 잇다.
3.중간처리와 최종처리를 수행하도록 파이프라인을 형성할 수 잇다.
--> 스트림은 멀티스레드 병렬 처리시 fork와 join을 자동으로 수행한다.
외부반복자
컬렉션을 순회하기 위해서 while문이나 for문을 돌면서 컬렉션의 내용을 하나 씩 가져오는 것 향상된 for-loop문일때는 내부반복자보다 빠르다.
내부반복자
forEach에 처리 함수를 등록하고 컬렉션을 하나씩 가져다 처리해준다 외부반복자보다는 느리지만 데이터를 공유하지 않고 자체 데이터를 사용하는 멀티스레드를 구현 할 수 잇다는 점에서 장점이 있다. 병렬처리시 향상된 for-loop문보다 빨라진다.
스트림 파이프 라인
스트림생성 | 중간처리 | 최종처리 |
파이프를 나눴다고 해서 각각 따로 돌아가는게 아니라 중간처리 부분에서 최종처리를 위해서 요소를 걸러내는 필터링(클래스중에 내가 쓰고 싶은 데이터를 get해온다.)을 진행하거나, 요소를 변환시키거나(person -> integer), 정렬하는 작업을 수행한다.
//스트림의 매핑을 사용하지 않을 때 원본코드
int total = 0;
for (Student s : list){
total += s.getScore();
}
double avg2 = (double) total / list.size();
//스트림의 매핑방법 두가지
//방법1
Stream<Student> studentStream = list.stream();
//중간 처리(학생 객체를 점수로 매핑)
IntStream scoreStream = studentStream.mapToInt(student -> student.getScore());
//최종 처리(평균 점수)
double avg = scoreStream.average().getAsDouble();
//방법2
double avg = list.stream()
.mapToInt(student -> student.getScore())
.average()
.getAsDouble();
System.out.println("평균 점수: " + avg);
스트림 얻기
컬렉션으로부터 스트림 얻기
list.stream()
//객체 스트림 얻기
Stream<Product> stream = list.stream();
stream.forEach(p -> System.out.println(p));
배열로부터 스트림 얻기
Arrays.stream()
String[] strArray = { "홍길동", "신용권", "김미나"};
Stream<String> strStream = Arrays.stream(strArray);
//Stream<String> strStream = Arrays.stream(new String[] {"홍길동", "신용권", "김미나"});
strStream.forEach(item -> System.out.print(item + ","));
숫자범위로부터 스트림얻기
IntStream에서 rangeClosed는 1~100까지 딱 나오는데 range()는 1~99까지 나옴
IntStream stream = IntStream.rangeClosed(1, 100);
stream.forEach(a -> sum += a);
파일로부터 스트림얻기
파일의 경로를 Paths클래스의 get에 URI를 전달해서 파일을 가져와 지정된 문자셋으로 읽어오도록한다.
Path path = Paths.get(StreamExample.class.getResource("data.txt").toURI());
Stream<String> stream = Files.lines(path, Charset.defaultCharset());
stream.forEach(line -> System.out.println(line) );
stream.close();
필터링
중간처리 기능으로 요소를 걸러낸다
distinct()
- 중복을 제거한다 사용하려면 equals와 hashCode가 재정의 되어 있어야한다.
--> 중복을 허용하지 않으려면 애초에 set에다가 대입하는 방법도 있다.
filter()
함수형 인터페이스를 재정의하여 조건으로 스트림을 필터링한다.
filter()
hashCode와 equals를 반드시 재정의 해주어야한다. 안에 추상메소드로 test가 boolean값을 반환한다.
//신으로 시작하는 요소만 필터링
list.stream()
.filter(n -> n.startsWith("신"))
.forEach(n -> System.out.println(n));
System.out.println();
//2번째 방법
list.stream()
.filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("신");
}
})
.forEach(n -> System.out.println(n));
System.out.println();
//for 루프 문으로 사용시
for (String name : list){
// if (name.indexOf("신") == 0){
if (name.startsWith("신")){ //해당 문자로 시작하니?
System.out.println(name);
}
}
System.out.println();
매핑
중간처리 기능으로 스트림의 요소를 다른 요소로 변환하는 역할을 한다.
map() : T -> R
mapToInt() : T ->int
mapToDouble() : T -> double
매핑
map은 함수형 인터페이스를 매개변수로 추상메소드 apply()를 갖고 있다.
//매핑~
studentList.stream().mapToInt(new ToIntFunction<Student>() {
@Override
public int applyAsInt(Student value) {
// TODO Auto-generated method stub
return value.getScore();
}
})
.forEach(score -> System.out.println(score));
//Student를 score 스트림으로 변환
studentList.stream()
.mapToInt(student -> student.getScore())
.forEach(score -> System.out.println(score));
기본타입요소를 래퍼 객체요소로 변환하는 것도 있음
asLongStream(): int->long
asDoubleStream() : int ->double or long->double
boxed() : int->Integer, long->Long , double ->Double
요소를 복수개의 요소로 변환
flatMapXXX() 메소드는 하나의 요소를 복수 개의 요소들로 변환한 새로운 스트림을 리턴한다.
flatMapXXX()
//기본 생김새
for(String str: list1) {
String[] tokens = str.split(" ");
for(String word : tokens) {
System.out.println(word);
}
}
//익명 객체로 구현
list1.stream()
.flatMap(new Function<String,Stream<String>>() {
@Override
public Stream<String> apply(String str) {
// TODO Auto-generated method stub
return Arrays.stream(str.split(" "));
}
}).forEach(word ->System.out.println(word));
//람다식으로 구현
list1.stream().
flatMap(data -> Arrays.stream(data.split(" ")))
.forEach(word -> System.out.println(word));
System.out.println();
요소정렬
요소를 오름차순이나 내림차순으로 정렬하는 중간 처리 기능이다. Comparable을 사용자정의 자료형(내가만든클래스)에 대해서 정의해 주어야 정렬을 수행할수 있다. 기본형 타입들은 클래스에서 이미 구현하고 있기 때문에 comparable을 안 만들어도 된다.
comparator 정렬
//점수를 기준으로 오름차순으로 정렬한 새 스트림 얻기
//오름차순 람다식
studentList.stream()
.sorted((s1, s2) -> s1.getScore()- s2.getScore())
.forEach(s -> System.out.println(s.getName() + ": " + s.getScore()));
System.out.println();
//오름차순 익명객체
studentList.stream()
.sorted(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// TODO Auto-generated method stub
return o1.getScore()-o2.getScore();
}
})
.forEach(s -> System.out.println(s.getName() + ": " + s.getScore()));
System.out.println();
역순정렬
compareTo의 결과 값을 내부적으로 반대로 쓴다.
stream.sorted(Comparator.reverseOrder());
comparator를 이용한 정렬
요소 객체가 comparable을 구현하고 있지 않다면 비교자를 제공한다.
sorted((s1, s2) -> s1.getScore()- s2.getScore())
루핑
스트림에서 요소를 하나씩가져와 반복해서 가져와 처리하는 것을 말한다.
peek()
중간처리자로 원본데이터를 변경하지 않고 모니터링 할때 사용한다. 최종처리 메소드를 뒤에 붙여주어야한다. 최종함수인 집계함수 나 forEach써준다. accept()함수 재정의해서 사용한다.
forEach()
최종처리메소드
//값도 구하고 싶고 값을 찍어보고도 싶고
int sum2 = Arrays
.stream(intArr)
.filter(n -> n % 2 == 0)
.sum();
System.out.println("sum = " + sum2);
//최종 처리 메소드 forEach()를 이용해서 반복 처리
Arrays.stream(intArr)
.filter(a -> a%2==0)
.forEach(n -> System.out.println(n));
//peek함수로 한꺼번에 할 수 있지롱
//중간 처리 메소드 peek()을 이용해서 반복 처리
int total = Arrays.stream(intArr)
.filter(a -> a%2==0)
.peek(n -> System.out.println(n)) //동작함
.sum(); //최종 처리
System.out.println("총합: " + total + "\n");
매칭
요소들이 특정 조건에 만족하는지 여부를 조사하는 최종처리 기능이다.
allMatch() -and
모든 요소가 만족하는지 여부
anyMatch() -or
최소한 하나의 요소가 만족하는지
noneMatch() -not
모든요소가 만족하지 않는지 여부
int[] intArr = { 2, 4 ,6 };
//allMatch를 걍 쓰면
boolean result1=true;
for(int value : intArr) {
if(value %2==1) {
result1 = false;
break;
}
}
if(result1) {
System.out.println("모든 값이 짝수");
}else {
System.out.println("값 중에 홀수 가 존재함");
}
//allMatch로 구현
boolean result = Arrays.stream(intArr)
.allMatch(a -> a%2==0);
System.out.println("모두 2의 배수인가? " + result);
요소기본집계
optional리턴 - 스트림에 내용이 없으면 null값을 리턴하는 애들
findFirst() -첫번째 요소 출력
max()
min()
average()
일반 숫자 타입리턴 - 스트림에 내용이 없으면 0을 리턴한다
count()
sum()
Optional클래스
isPresent() -집계값이 있는지 여부
orElse() - 집계값이 없을 경우 디폴트 값 설정
ㄴ집계값을 산출할 수없을때 나올수 잇는 예외를 방지하기 위함
ifPresent() - 집계값이 있을 경우 consumer에서 처리
요소 커스텀 집계
reduce(초기값, (인자)-> ..)
1~3덧셈
s=0 초기값
s= s+1
s=s+2
s=s+3
이러한 과정으로 굴러가는 함수이다.
요소 수집
필요한 요소들만 챙기기
collect()메소드에 collector를 통해 어떤 요소를 수집할 것인지 결정한다.
toList() -> 리스트로~
toSet() -> set으로~
toMap() -> Map으로~
요소그룹핑
Collectors.groupingBy() 함수를 통해 그룹핑키 리턴
Collectors
//이 기본 코드를
List<Student> maleList2 = new ArrayList<>();
for(Student student : totalList) {
if(student.getSex().equals("남")) {
maleList2.add(student);
}
}
//collect를 통해서 리스트로 넘김
List<Student> maleList = totalList.stream()
.filter(s->s.getSex().equals("남"))
.collect(Collectors.toList());
//collector를 이용해 map을 통해서 map으로 변환
//학생 이름을 키, 학생의 점수를 값으로 갖는 Map 생성
Map<String, Integer> map = totalList.stream()
.collect(
Collectors.toMap(
s -> s.getName(), //Student 객체에서 키가 될 부분 리턴
s -> s.getScore() //Student 객체에서 값이 될 부분 리턴
)
);
병렬 스트림사용
parallelStream()메소드는 컬렉션(List,set)으로부터 병렬스트림을 바로 리턴한다. 스레드를 코어 갯수만큼 만들어 각자 수행하고 join으로 합쳐온다. 멀티스레드의 fork()와 join()을 대신 해주기 때문에 개발자가 신경쓸 필요없다.
Stream<Integer> parallelStream = scores.parallelStream();
'JAVA공부(이것이 자바다)' 카테고리의 다른 글
입출력스트림 (0) | 2023.06.14 |
---|---|
컬렉션 자료구조 (0) | 2023.06.12 |
스레드 (3) | 2023.06.09 |
java.base 이어서 (0) | 2023.06.08 |
java.base 모듈 (2) | 2023.06.07 |