22년 09월 03일에 작성된 글
Optional
관련 사용방법을 찾던 도중 Stream
과 같은 Optional<T>.map()
메소드를 제공한다 했다. 그런데 Stream
이 이해가 안되고 이전에 백준을 풀면서 아래와 같은 코드들도 이해가 안되서 이참에 Stream
을 공부해봤다.
Arrays.stream(numberStr.split(" ")).mapToLong(Long::parseLong).toArray()
Stream
사용법스트림은 다음과 같이 다양한 방식으로 만들 수 있다.
int[] numArr = {0, 1, 2, 3, 4, 5};
List<String> strList = Arrays.asList("a", "b", "c");
Stream<String> stm1 = strList.stream();
Stream<Integer> stm2 = Stream.iterate(0, n->n+2);
IntStream istm = Arrays.stream(numArr);
스트림은 Stream 생성 -> 중간연산 -> 최종연산 으로 진행된다.
중간연산은 연산결과가 스트림인 연산이고 여러번 적용할 수 있다.
최종연산은 연산결과가 스트림이 아니고 스트림의 모든 요소를 소모하여 단 한 번만 적용가능한 연산이다.
진행과정은 다음과 같다.
stream //이미 생성되어있는 스트림 객체
.distinct().limit(5).sorted() // 중간연산 (중복제거->5개짜르기->정렬)
.forEach(System.out::println); // 최종연산(출력)
스트림은 읽기만(ReadOnly) 할 뿐 원본을 변경하지 않는다.
List<Integer> list = Arrays.asList(3, 2, 5, 4, 2);
List<Integer> sortedList = list.stream()
.sorted()
.collect(Collectors.toList());
//원본인 list는 변경되지 않는다.
스트림은 일회용이다. 다음과 같이 재사용할 수 없다.(필요하면 다시 스트림을 생성)
strStream.forEach(System.out::println); // 최종연산 수행
int numOfStr = strStream.count(); // 에러. 스트림이 이미 닫힘
최종 연산 전까지 중간연산이 수행되지 않는다. - 지연된 연산
//로또번호 출력 예시
IntStream intStream = new Random().ints(1,46) // 1~45범위의 무한 스트림 - 지금은 그렇구나 하고 넘어가라
intStream.distinct().limit(6).sorted()
.forEach(i->System.out.println(i+","))
스트림은 작업을 내부 반복으로 처리 - 코드 간결
//for(String str : strList)
// System.out.println(str);
//위와 같은 연산을 아래처럼 수행
stream.forEach(System.out::println);
... 생략
// 객체 배열 스트림 생성
Stream<String> strSteam1 = Stream.of("a", "b", "c");
Stream<String> strSteam2 = Stream.of(new String[]{"a", "b", "c"});
Stream<String> strSteam3 = Arrays.stream(new String[]{"a", "b", "c"});
Stream<String> strSteam4 = Arrays.stream(new String[]{"a", "b", "c"}, 0, 3); //0~2 즉 a,b,c 가 들어감
//기본형 배열 스트림 생성
int[] numArr = {0, 1, 2, 3, 4, 5};
IntStream istm1 = Arrays.stream(numArr);
IntStream istm2 = IntStream.of(numArr);
무한 스트림 부분은 건너뛰겠다.
중간 연산
stream.filter(); // 조건에 안맞는 요소 제외 (중간연산)
stream.distinct(); // 중복제거 (중간연산)
stream.sort(); // 정렬 (중간연산)
stream.limit(5); // 스트림 자르기 (중간연산)
stream.skip(3); // 요소 건너뛰기
stream.map(); // 요소 변환 (중간연산) - 좀 어려움 아래서 살펴봄
//스트림이 1, 2, 3, 4, 5, 6, 7, 8의 요소를 가진다고 가정
// 스트림에서 3개의 요소를 건너뛰고 5개를 자르기 때문에
// 4,5,6,7,8 스트림이 나온다.
stream.skip(3).limit(5);
//2의 배수만을 가진 스트림이 나온다. 2,4,6,8
stream.filter(i->i%2==0)
최종연산
stream.count(); // 요소 수 세기(최종연산)
//Optional 관련
stream.max();
stream.min();
이외에도 다른 중간연산 최종연산이 있다.
Stream.map()
, Stream.flatMap()
일단 백준 알고리즘과, Optional
쪽에서 자주 사용하는 map()
부분의 원리만 보고 나중에 필요할 때 다시 공부한다.
스트림의 요소 변환하기 - map()
Stream<File> fileStream = Stream.of(new File("Ex1.java"), new File("Ex1"), new File("Ex1.bak"), new File("Ex2.java"), new File("Ex1.txt"));
//Stream<File>에서 File에 이름을 Stream<String>으로 만듦
//Stream<File> -> Stream<String>
Stream<String> fileNameStream = fileStream.map(File::getName);
fileNameStream.forEach(System.out::println);
만약 다음 예시에서 파일 확장자(대문자)를 중복없이 뽑아내고 싶다면 다음과 같은 코드를 작성하면 된다.
fileStream.map(File::getName) // Stream<File> -> Stream<String>
.filter(s->s.indexOf('.' != -1)) // 확장자 없는것 필터링
.map(s->s.substring(s.indexOf'.'+1)) // Stream<String> -> Stream<String>
.map(String::toUpperCase) // 대문자 Stream<String> -> Stream<String>
.distinct() // 중복제거
.forEach(System.out::print);
Stream.flatMap()
는
Stream strArr = Stream.of(new String[]{"abc", "def"},
new String[]{"ABC", "DEF"});
Stream<Stream<String>> strStrStrm1 = strArr.map(Arrays::stream); //우리가 원하는 형식이 아니다
// abc, def, ABC, DEF 를 원한다면 아래와 같이 사용하면 된다.
Stream<String> strStrStrm2 = strArr.flatMap(Arrays::stream);
내용출처: https://www.youtube.com/watch?v=7Kyf4mMjbTQ
메소드 참조는 람다 표현식이 단 하나의 메소드만을 호출하는 경우에 해당 람다 표현식에서 불필요한 매개변수를 제거하고 사용할 수 있독 해준다. 즉 아래와 같은 두 코드는 같은 코드이다.
//람다 표현식
(base, exponent) -> Math.pow(base, exponent);
//메소드 참조
Math::pow;
내용출처: http://www.tcpschool.com/java/java_lambda_reference
배열을 List로 변환할 때, Arrays.asList()
메소드를 사용하면 된다.
하지만, 배열의 원소가 int와 같은 primitive type인 경우 Arrays.asList()는 좀 다른 결과를 리턴한다.
List<int>
형식의 리스트를 얻기를 원하지만 Array.asList()
를 사용하면 다음과 같은 List<int[]>
형식을 반환한다.
// int 배열
int[] arr = { 1, 2, 3 };
// Arrays.asList()
List<int[]> intList = Arrays.asList(arr);
// 결과 출력
System.out.println(intList.size()); // 1
System.out.println(intList.get(0)); // I@71bb301
System.out.println(Arrays.toString(intList.get(0))); // [1, 2, 3]
하지만 다음과 같이 stream을 사용하여 변환할 수 있다.
int[] arr = { 1, 2, 3 };
// int -> List
List<Integer> intList = Arrays.stream(arr)
.boxed() // int를 Integer로 변환
.collect(Collectors.toList()); //toSet() 등등이 있음
// List 출력
System.out.println(intList.size()); // 3
System.out.println(intList); // [1, 2, 3]
출처: https://hianna.tistory.com/552 [어제 오늘 내일:티스토리]