1. 스트림이란?
스트림은 자바8부터 추가된 컬렉션의 저장요소를 하나씩 참조해서 람다식으로 처리할수 있도록 해주는 반복자이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | package streamTest; import java.util.Arrays; import java.util.List; public class myStreamTest { public static void main(String[] args) { int count1 = 0; List<String> names = Arrays.asList("1", "2", "3", "4", "5"); // 기존의 for문 for (String w : names) { if(w.length() > 0) { count1++; } } // stream 방식 long count2 = names.stream() .filter(a->a.length()>0) .count(); // 병렬 stream 방식 long count3 = names.parallelStream() .filter(a->a.length()>0) .count(); System.out.println(count1); System.out.println(count2); System.out.println(count3); } } | cs |
count1, count2, count3의 결과는 같다.
기존for문,스트림, 병렬스트림 을 사용해서 표현한 것을 확인할 수 있다.
2. 스트림의 특징
- 스트림을 활용하면 복잡한 코드를 간결하게 표현할 수 있다.
- 스트림은 컬렉션, 배열, 파일 등의 대량의 데이터를 가공 축소하여 데이터의 합계,
평균값, 카운팅, 최대값, 최소값, 집계함수를 모두 표현할 수 있다.
- 오리지날 스트림에서 중간처리(필터, 매핑)를 하고 최종처리(집계 처리 결과물)를 하여 결과를 볼수 있다.
- 스트림은 iterator와 비슷한 역할을 하는 반복자이다.
- 스트림이 제공하는 요소처리 메서드는 함수적 인터페이스 타입이므로 람다식,
메서드 참조를 이용하여 요소처리 내용을 인자로 전달할 수 있다.
3. 컬렉션과 스트림의 공통점과 차이점
공통점
- 연속된 요소형식의 값을 저장하는 자료구조 인터페이스를 제공한다.
- 둘다 순차적으로 요소에 접근한다.
차이점
컬렉션은
- 각 계산식을 만날 때마다 데이터가 계산된다.
- 데이터의 접근, 읽기, 변경, 저장이 주요 관심사이다.
- 데이터에 접근하는 방법을 직접 작성해야한다.
- Iterator로 모든요소를 순환해야한다.
- 메모리에 모든 요소가 올라가 있는 상태에서 요소들을 누적시키며 결과를 계산한다.
- 메모리 사용량이 늘어난다.
스트림은
- 최종 연산이 실행 될 때에 데이터가 계산된다.
- 계산식(람다)을 표현하는 것이 주요 관심사이다.
- 데이터에 접근하는 방법이 추상화되어있다.
- 계산식을 미리 적어두고 계산시에 람다식으로 JVM에 넘긴다.
- 내부에서 요소들을 어떻게 메모리에 올리는 지는 관심사가 아니다.
- 메모리 사용량이 줄어든다.
스트림을 활용해 코드를 개선해보자.
4. 스트림 생성방법 예제
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | package streamTest; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; import java.util.function.IntSupplier; import java.util.stream.IntStream; import java.util.stream.Stream; public class MakingStreams { public static void main(String...args) throws Exception{ // Stream.of Stream<String> stream = Stream.of("Java8", "Lambdas", "SangHyun"); stream.map(String::toUpperCase).forEach(System.out::println); // result : UpperCase // Arrays.stream int[] numbers = {1, 2, 3, 4, 5}; System.out.println(Arrays.stream(numbers).sum()); // result : 15 // Stream.iterate Stream.iterate(0, n -> n + 2) .limit(5) .forEach(System.out::println); // result : 0 2 4 6 8 // random stream of doubles with Stream.generate Stream.generate(Math::random) .limit(10) .forEach(System.out::println); // result : random data // stream of 1s with Stream.generate IntStream.generate(() -> 1) .limit(5) .forEach(System.out::println); // result : 1 1 1 1 1 IntStream.generate(new IntSupplier(){ public int getAsInt(){ return 2; } }).limit(5) .forEach(System.out::println); // result : 2 2 2 2 2 // 피보나치 수열 IntSupplier fib = new IntSupplier(){ private int previous = 0; private int current = 1; public int getAsInt(){ int nextValue = this.previous + this.current; this.previous = this.current; this.current = nextValue; return this.previous; } }; IntStream.generate(fib).limit(10).forEach(System.out::println); // result : 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 // 유니크 단어 카운트 long uniqueWords = Files.lines(Paths.get("data2.txt"), Charset.defaultCharset()) .flatMap(line -> Arrays.stream(line.split(" "))) .distinct() .count(); System.out.println("There are " + uniqueWords + " unique words in data2.txt"); } } | cs |
5. 스트림 활용하여 문제 풀기
5.1 Developer 모델
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | package streamTest; public class Developer{ private String name; private String title; public Developer(String n, String c){ this.name = n; this.title = c; } public String getName(){ return this.name; } public String getTitle(){ return this.title; } public void setTitle(String newTitle){ this.title = newTitle; } public String toString(){ return "Developer:"+this.name + " , " + this.title; } } | cs |
5.2 BiddingCompany 모델
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | package streamTest; public class BiddingCompany{ private Developer developer; private String companyName; private int year; private int salary; public BiddingCompany(Developer developer, String companyName, int year, int salary) { this.developer = developer; this.companyName = companyName; this.year = year; this.salary = salary; } public Developer getDeveloper(){ return this.developer; } public String getCompanyName() { return companyName; } public int getYear(){ return this.year; } public int getSalary(){ return this.salary; } public String toString(){ return "{" + this.developer + ", " + "companyName: "+this.companyName+", " + "year: "+this.year+", " + "salary:" + this.salary +"}"; } } | cs |
5.3 StreamTestCode Main 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | package streamTest; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; public class StreamTestCode { public static void main(String ...args){ // 개발자의 성명과 직급 Developer sanghyun = new Developer("SangHyun", "대리"); Developer hyunYoung = new Developer("HyunYoung","사원"); Developer jiSook = new Developer("JiSook","주임"); Developer choa = new Developer("Choa","대리"); // 입찰회사에서 개발자 채용을 위해 연봉제시 // 입찰한 개발자 이름, 참여한 회사이름, 설립연도 , 제시한연봉 List<BiddingCompany> company = Arrays.asList( new BiddingCompany(sanghyun, "쿠팡",2010, 4000), new BiddingCompany(sanghyun, "위메프",2011, 5000), new BiddingCompany(sanghyun, "sk플래닛",2012, 7000), new BiddingCompany(hyunYoung, "위메프",2010, 2000), new BiddingCompany(hyunYoung, "sk플래닛",2012, 3000), new BiddingCompany(jiSook, "쿠팡",2010, 3500), new BiddingCompany(choa, "위메프",2011, 3800) ); // 쿼리 1 : 설립일이 2012년인 입찰회사를 모두 찾아서 연봉이 작은값부터 큰값으로 출력해라 // 2012년이라는 특정한 조건이 있으므로 filter사용, 작은값부터 큰값 정렬 sorted 사용 List<BiddingCompany> t1 = company.stream() .filter(a->a.getYear()==2012) .sorted(Comparator.comparing(b->b.getSalary())) .collect(Collectors.toList()); t1.forEach(System.out::println); /* result : {Developer:HyunYoung , 사원, companyName: sk플래닛, year: 2012, salary:3000} {Developer:SangHyun , 대리, companyName: sk플래닛, year: 2012, salary:7000} */ // 쿼리 2 : 입찰회사 개발자 목록에서 개발자의 중복되지 않는 직급만 출력해라. // 특정한 조건이 딱 주어지지 않았으므로 map사용, 중복제거 distinct사용 List<String> t2_1 = company.stream() .map(BiddingCompany::getDeveloper) .map(Developer::getTitle) .distinct() .collect(Collectors.toList()); System.out.println("map 2번 사용"); t2_1.forEach(System.out::println); /* result : 대리 사원 주임 */ List<String> t2_2 = company.stream() .map(tx -> tx.getDeveloper().getTitle()) .distinct() .collect(Collectors.toList()); System.out.println("map 1번 사용"); t2_2.forEach(System.out::println); /* result : 대리 사원 주임 */ // 쿼리 3: 개발자 중에서 대리직급을 찾아 이름순으로 정렬해라. company.stream() .map(a->a.getDeveloper()) .filter(b->b.getTitle().equals("대리")) .distinct() .sorted(Comparator.comparing(c->c.getName())) .forEach(System.out::println); /* result : Developer:Choa , 대리 Developer:SangHyun , 대리 */ // 쿼리 4: 알파벳 순서대로 정렬하여 개발자 이름만 출력해라 String names = company.stream() .map(a->a.getDeveloper().getName()) .distinct() .sorted() .reduce("", (a1,a2) -> a1+a2+" "); System.out.println(names); /* result : Choa HyunYoung JiSook SangHyun */ // 쿼리 5 : 사원 직급의 개발자가 있는가? boolean 사원 = company.stream() .anyMatch(tx -> tx.getDeveloper().getTitle().equals("사원")); System.out.println(사원); /* result : true */ // 쿼리 6 : 대리직급의 개발자를 과장직급으로 업데이트 해라 System.out.println("업데이트 전: "+company); company.stream() .map(a->a.getDeveloper()) .filter(a->a.getTitle().equals("대리")) .forEach(a->a.setTitle("과장")); System.out.println("업데이트 후: "+company); // 쿼리 7: 입찰한 모든회사 중에 가장 높은 연봉을 제시한 값은 얼마인가? int highSalary = company.stream() .mapToInt(a->a.getSalary()) .max() .getAsInt(); System.out.println(highSalary); /* result : 7000 */ } } | cs |
소스 코드 첨부 :
'전체 > Java' 카테고리의 다른 글
module-info.java로 서로 다른 프로젝트의 패키지(클래스) 불러와 사용하기 (1) | 2019.02.20 |
---|---|
LocalDate, LocalTime, LocalDateTime, DateTimeFormatter 사용하기 (0) | 2019.02.20 |
람다식과 스트림, 함수형 인터페이스(predicate, consumer, supplier, function, operator) 활용하기 (1) | 2019.02.20 |
객체지향 디자인 패턴(팩토리, 빌더, 싱글톤, 파사드, Iterator, MVC) (0) | 2019.01.27 |
객체지향 프로그래그래밍 5원칙 특징, 요소 (2) | 2019.01.27 |