-
Collection FrameWork,StreamJAVA 2021. 7. 23. 14:48
Collection( FrameWork)클래스: List, Set, Map 컬렉션 클래스가 자식으로 있다.
1. List클래스
1) ArrayList: 탐색등에 용이(Vector와 거의 동일 , 차이점은 멀티쓰레드에서)
2) LinkedList: 추가/삭제등에 용이(배열들이 서로 전 객체의 주소, 다음 객체의 주소를 가지고 있기 때문에 , 연결된 주소만 바꿔주면 된다.)
2. Set클래스
Set 컬렉션은 HashSet, TreeSet, LinkedSet 등이 있다. Set컬렉션은 순서가 없어서 인덱스로 객체를
검색할 수 없다. 대신에 전체 객체를 한번씩 반복해서 가져오는 반복자(Iterator)를 제공한다.
반복자 Iterator인터페이스를 구현한 객체를 말하는데 Set인터페이스의 iterator() 메서드를 호출하면
Iterator형으로 자료를 얻을 수 있다.
hashCode(), equals() 메서드가 재정의 되어있지 않으므로 비교시 재정의 해줘야 한다.
3. Map클래스
Map 컬렉션은 key와 value으로 구성된 Map.Entry 객체를 저장하는 구조를 가지고 있다.
키와 값은 모두 객체이다. 키는 중복불가이나 값은 중복저장이 가능하다. 만약 기존에
저장된 key와 동일한 키로 값을 저장하면 기존의 값은 없어지고 새로운 값으로 대체가
된다.
일반형 (int등)값은 당연히 Wrapper클래스 (Integer등)로 바꿔서 넣으면 된다.
Map이라는 객체(배열) 안에 key객체, value객체
Map컬렉션에는 HashMap,HashTable,LiskedHashMap, Properties, TreeMap 등이 있다.
값을 얻고자 할 경우에는 2가지 방법이 있다. 키를 알고 있다면 get(키)메서드로 간단히
객체를 찾아올 수 있지만 저장된 전체 객체를 대상으로 하나씩 값을 가져올 경우에는
1. keyStr() 메서드로 모든 키를 Set컬렉션으로 얻은 다음 반복자를 통해 키를 하나씩
읽어서 get()메서드로 값을 얻는 방법
2. entrySet() 메서드로 모든 Map.Entry객체를 Set컬렉션으로 얻은 다음 반복자를 통해
Map.Entry 객체를 하나씩 읽어서 getKey()와 getValue() 메서드를 이용하는 방법이 있다.
즉, Map은 key에 대응하는 value 값들을 집어 넣을 수 있는 장점이 있고, 검색등은 Set과 똑같이 배열이 순서가 없기 때문에
Set으로 바꿔서 검색등을 하는 것이다(Map자체는 못하는듯)
hashCode(), equals() 메서드가 재정의 되어있지 않으므로 비교시 재정의 해줘야 한다.
Properties
Properties는 HashTable의 하위클래스이기 때문에 HashTable의 모든 속성들을 그대로 가지고 있는데
차이점은 HashTable은 키와 값을 다양한 데이터타입으로 지정할 수 있는데 비해 Properties는 키와 값이
모두 String타입으로 제한된 컬렉션이다.
Properties 애플리케이션의 옵션정보, 데이터베이스연결정보, 그리고 국제화(다국어)정보가 저장된
프로퍼티파일을 사용할 때 주로 이용한다.
프로퍼티타입은 키와 값이 "=" 기호로 연결되어 있는 텍스트파일로 ISO8859-1문자셋으로 저장된다.
이 문자셋으로 직접 표현할 수 없는 한글은 유니코드로 변환되어 저장된다.
이클립스에서 유니코드로 변환된 내용을 다시 한글로 보려면 마우스를 유니코드위에 올려 놓으면 된다.
이클립스를 사용하지 않을 경우 한글이 포함된 프로퍼티타입을 다른 에딭에서 작성하고 jdk의 설치폴더에서
native2ascii.exe를 이용해서 ISO8859-12파일로 저장하면 된다.
Tree
1. TreeSet: Set컬렉션인데 Tree의 특징인 정렬, 검색이 더 강화된 것이다.
자동으로 정렬되어 있으며 검색등이 더 쉬워진다.
stream?
일단 간단하게 바로 정렬, 필터, 출력 가능하고(메서드가 다 구비되어 있고 다들 객체를 다시 리턴하기 때문에 체인형태로 사용가능)
palleral stream 이라는 stream으로 사용하면 여러 쓰레드에서 함께 일을 분담해서 할 수 있기 때문에 시간도 절약할 수 있다.
Stream의 종류
자바8부터 새로 추가된 java.util.stream 패키지에는 stream API들이 포함되어 있다. stream의 종류는 BaseStream 인터페이스와
이를 구현한 Stream, IntStream, LongStream, DoubleStream이 있다.
BaseStream에는 모든 스트림에서 사용할 수 있는 공통메서드가 정의되어 있을 뿐 코드에서 직접 사용되지 않는다.
하위 스트림이 직접적으로 이용되는 스트림인데
- Stream은 객체요소를 처리하는 스트림이고
- IntStream,LongStream,DoubleStream은 각각 기본 타입인 int, long, double 요소를 처리하는 스트림이다.
Stream
123456789101112131415161718192021222324252627282930313233343536public static void main(String[] args) {List<Student> list = Arrays.asList(new Student("홍길동", 92), new Student("홍길순", 90));Stream<Student> stream = list.parallelStream();stream.forEach(s -> System.out.println(s.name + " - " + s.score));//forEach(): Iterator로 for문 돌려서 요소 다가져올 동안 행동을 반복하는것과 똑같다// 홍길순 - 90// 홍길동 - 92}}class Student {public String name;public int score;public Student(String name, int score) {super();this.name = name;this.score = score;}public String getName() {return name;}public int getScore() {return score;}}cs 1234567891011121314151617181920212223List<Student> list = Arrays.asList(new Student("홍길동", 92), new Student("홍길순", 90), new Student("손흥민", 92));// 중간처리(학생객체를 점수로 매핑) -> 최종처리(평균)double avg = list.stream().mapToInt(Student::getScore).average().getAsDouble();System.out.println("평균점수 = " + avg); //평균점수 = 91.33333333333333// list.stream 으로 객체를 하나씩 가져오고 매핑하여 Student 멤버중 getScore메서드를 가져온다(가져온 객체는// Student이니 당연히 사용가능 하다.// average() 중간처리 메서드, getAsDouble 최종처리 메서드// 총점int d = list.stream().mapToInt(Student::getScore).sum();// average() 중간처리 메서드이지만 sum() 은 최종처리 메서드이다.System.out.println("합계점수 = " + d); //합계점수 = 274int sum=0;for(int i = 1; i<101; i++) {if(i%3==0) {sum += i;}}System.out.println(sum); //1683}cs 1234567891011121314151617181920212223242526272829303132333435363738394041424344// 내부반복자를 이용해서 병렬처리List<String> list = Arrays.asList("홍길동", "홍길순", "소향", "손흥민", "홍길자");// 1. 순차처리Stream<String> stream = list.stream();stream.forEach(str -> System.out.println(str));//출력: 홍길동 //홍길순 //소향 //손흥민 //홍길자//forEach()메서드 다 끝나면 stream이 다 비워진다. 삭제하면서 반환됐기 때문System.out.println();stream = list.stream();stream.forEach(ParalleMain::print);/*출력: 홍길동-main 홍길순-main 소향-main 손흥민-main 홍길자-main*/System.out.println();// 2. 병렬처리stream = list.parallelStream();stream.forEach(str -> System.out.println(str));System.out.println();/*출력: 소향 홍길자 손흥민 홍길순 홍길동*/stream = list.parallelStream();// main에서 다같이 기다렸다가 실행하지 않고 쓰레드가 늘어나 평행선처럼 같은 시간에 같이 처리중stream.forEach(ParalleMain::print);/* 출력* 홍길자-ForkJoinPool.commonPool-worker-3* 홍길순-ForkJoinPool.commonPool-worker-5* 소향-main* 홍길동-ForkJoinPool.commonPool-worker-5* 손흥민-ForkJoinPool.commonPool-worker-3*/}public static void print(String str) {System.out.println(str + "-" + Thread.currentThread().getName());//현재 이 sysout이 나타난 쓰레드.이름}}cs 1234567891011121314151617181920212223242526272829// 실습// Arrays 홍길동, 손흥민, 소향// List컬렉션프레임워크로 저장// 각각 값을 출력// hint) Arrays의 asList() -> List객체를 생성// Iterator로 출력String[] name = { "홍길동", "손흥민", "소향" };List<String> per = Arrays.asList(name);//List<String> per = Arrays.asList("홍길동", "손흥민", "소향"); 한문장으로 가능// 1. 외부반복자 IteratorIterator<String> iterator = per.iterator();while(iterator.hasNext()) {String n = iterator.next();System.out.println(n);}System.out.println();/*출력: 홍길동 손흥민 소향*/// 2. 내부반복자 StreamStream<String> stream = per.stream();stream.forEach(nn -> System.out.println(nn));/*출력: 홍길동 손흥민 소향*/cs
스트림을 얻는 방법
1. 컬렉션으로부터 얻기
2. 배열로부터 얻기
3. 숫자범위로부터 얻기
4. 파일로부터 얻기
5. 디렉토리로부터 얻기
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152public class FromCollectionMain {public static int sum;public static void main(String[] args) {// 1. from CollectionList<Student> list = Arrays.asList(new Student("홍길동", 92), new Student("홍길순", 90));Stream<Student> student = list.stream();student.forEach(s -> System.out.println(s.getName() + "-" + s.getScore()));// 홍길동-92 '\n' 홍길순-90// 2. from ArraysString[] names = { "홍길동", "홍길순", "소향" };Stream<String> arrStream = Arrays.stream(names);arrStream.forEach(n -> System.out.print(n + ","));// 홍길동,홍길순,소향,System.out.println();int[] intArray = { 1, 2, 3, 4, 5 };IntStream intStream = Arrays.stream(intArray);intStream.forEach(a -> System.out.print(a + ","));// 1,2,3,4,5,System.out.println();// 3. 숫자범위로부터 얻기IntStream stream = IntStream.rangeClosed(1, 100);stream.forEach(n -> sum += n);System.out.println("1~100까지의 합 :" + sum);}}class Student {public String name;public int score;public Student(String name, int score) {super();this.name = name;this.score = score;}public String getName() {return name;}public int getScore() {return score;}}cs 12345678910111213141516171819202122232425262728293031323334public class FromFileName {public static void main(String[] args) throws IOException {// 4. 파일로부터 스트림얻기// 1) 파일의 위치확인Path path = Paths.get("src/com/lec206/ex02_kind/name1");System.out.println(path + "\n");Stream<String> stream;// 2) 파일읽기(1) - Files.lines()메서드stream = Files.lines(path);//Files는 예외를 던져줘야한다stream.forEach(System.out::println);stream.close();System.out.println();// 3) 파일읽기(2) - BufferedReader.line()메서드File file = path.toFile();FileReader filereader = new FileReader(file);BufferedReader br = new BufferedReader(filereader);stream = br.lines();stream.forEach(System.out::println);stream.close();filereader.close();br.close();System.out.println();// 5. directory로부터 스트림 얻기path = Paths.get("d:/lec206/02.java/workspace");Stream<Path> stream1 = Files.list(path);stream1.forEach(p->System.out.println(p.getFileName()));}}cs
필터링(filter(), distinct() )
필터링은 중간처리기능으로 특정요소를 걸러내는 역할을 한다. 필터링 메서드 중 distinct() 메서드는
중복을 제거하는데 Stream의 경우 Object.equals(Object) 가 true이면 동일한 객체로 판단하고 중복을 제거한다.
IntStream, DoubleStream은 동일값일 경우 중복을 제거한다.
filter() 메서드는 매개값으로 주어진 Predicate(매개변수)가 true를 리턴하는 요소만 필터링 한다.
forEach() 처럼 for문 마냥 stream()배열로 들어온 객체들의 갯수만큼 돌아가며 모든 객체들을 확인한다.
123456789101112131415161718192021222324List<String> names = Arrays.asList("홍길동", "소향", "손흥민", "소향", "홍길자", "소지섭");// 1. 중복 제거names.stream().distinct().forEach(n -> System.out.println(n));// 스트림으로가져오고.중복값제거하고.루틴돌리고/*출력: 홍길동 소향 손흥민 홍길자 소지섭*/System.out.println();// 2. 필터링: "소"로 시작하는 자료만 필터링// startWith():String의 메서드임!, 시작단어가 (매개값)인 애들만 가져옴names.stream().distinct().filter(n -> n.startsWith("소")).forEach(n -> System.out.println(n));/*출력: 소향 소지섭*/System.out.println();names.stream().filter(n -> n.startsWith("소")).distinct().forEach(n -> System.out.println(n));/*출력: 소향 소지섭*///distinct() 로 중복제거 후 filter를 하나 filter돌리고 distinct로 중복제거하나 결과는 똑같다.//그래도 distinct()로 중복제거 후 filter가 하나씩 확인하는게 낫겠지?cs 12345678910111213141516171819202122232425262728293031323334353637383940414243444546public static void main(String[] args) {List<Member> list = Arrays.asList(new Member("홍길동",Member.MALE,39),new Member("홍길자",Member.FEMALE,34),new Member("홍길녀",Member.FEMALE,23),new Member("홍길순",Member.MALE,30));//필터링은 중간처리(주로 람다식 함수를 써서 필터하면 된다.) true가 뜨는 값만 가져온다.//남자회원의 평균나이double ageAvg = list.stream().filter(m -> m.getGender() == Member.MALE) //list 스트림데이터에서 남자회원만 필터링.mapToInt(Member::getAge) //필터링결과에서 회원나이만 mapping, int를 찾아 int로 리턴.average()//회원나이의 평균을 OptionalDouble에 저장, Double로 저장하는 메서드라서 마지막 getAsDouble()로 받아줘야 한다?.getAsDouble();System.out.println("남자회원의 평균나이 = " + ageAvg);}}class Member{public static int MALE = 0;public static int FEMALE = 1;private String name;private int gender;private int age;public int getGender() {return gender;}public int getAge() {return age;}public Member(String name, int gender, int age) {super();this.name = name;this.gender = gender;this.age = age;}}cs
asDoubleStream(),boxed()
asDoubleStream() -> int,long 을 double로 변환후에 stream으로 리턴
boxed() -> int,long,double을 wrapper 클래스로 즉, Integer,Long,Double로 박싱한후에 stream으로 리턴
123456789101112131415public static void main(String[] args) {int[] intArray = {1,2,3,4,5};IntStream intStream = Arrays.stream(intArray);intStream.asDoubleStream().forEach(n -> System.out.println(n));//IntStream으로 int[]배열을 가져와 Stream으로 만든 후 double형으로 바꿔줌intStream = Arrays.stream(intArray);intStream.boxed().forEach(n -> System.out.println(n.intValue()));//int를 Integer로 변환후 int형으로 forEach돌리기. Integer로 바꾸면 Integer 메서드도 사용가능!//intValue(): Integer가 int로 반환됨//사실 출력결과는 int나 Integer나 구분이 안간다(둘다 숫자라..)}cs
매핑( flatMapXXX(), mapXXX(), asXXXStream(), boxed() )
매핑은 중간처리기능으로 스트림의 요소를 다른 요소로 대체하는 작업을 말한다. 스트림에서 재공하는 메서드는
flatXXX(), MapXXX(), asXXXStream(), boxed()가 있다.
1. flatMapXXX(): 이 메서드는 요소를 대체하는 복수개의 요소들로 구성된 새로운 스트림을 반환한다.
2. mapXXX(): 이 메서드는 요소를 대체하는 요소로 구성된 새로운 스트림을 반환한다.
3. asDoubleStream(), asLongStream(), boxed()메서드
1)asDoubleStream() 메서드는 IntStream의 int요소, LongStream의 long요소들을 double타입으로 반환한 후
DoubleStream을 생성한다.
2) asLongStream()은 IntStream의 int요소를 long요소로 타입변환해서 LongStream을 생성
3) boxed() 메서드는 int,long,double요소를 Integer,Long,Double요소로 박싱해서 Stream을 생성
12345678910111213141516171819public static void main(String[] args) {List<String> list1 = Arrays.asList("java8 lambda","stream mapping");list1.stream().flatMap(w -> Arrays.stream(w.split(" "))).forEach(n -> System.out.println(n));//flatMap() 로 결과 값이 원래 스트림안의 요소보다 더 많아진 스트림으로 반환.//split():String메서드 구분자기준으로 문자열 끊기(지금은 공백 기준으로 단어 쪼갬)System.out.println();List<String> list2 = Arrays.asList("10,20,30","40,50,60,70");list2.stream().flatMapToInt(n -> {String[] strArr = n.split(",");int[] intArr = new int[strArr.length];for(int i= 0;i<strArr.length;i++) {intArr[i] = Integer.parseInt(strArr[i].trim());}return Arrays.stream(intArr);}).forEach(n ->System.out.println(n));}cs 12345678910111213141516171819202122232425262728293031public class MappingMain {public static void main(String[] args) {List<Student1> list = Arrays.asList(new Student1("홍길동", 92), new Student1("홍길순", 90));list.stream().mapToInt(Student1::getScore).forEach(s -> System.out.println(s));}}class Student1 {public String name;public int score;public Student1(String name, int score) {super();this.name = name;this.score = score;}public String getName() {return name;}public int getScore() {return score;}}cs
정렬(sort)
스트림은 요소가 최종적으로 처리되기 전에 중간단계에서 요소를 정렬해서 최종처리로 전달한다.
전달되는 요소가 객체일 경우에는 해당 객체의 클래스가 Comparable인터페이스를 구현하지 않으면 sorted() 메서드를
호출했을 경우 ClassCastingException이 발생하기 때문에 Comparable을 구현한 요소(객체)에만 sorted() 메서드를
호출해야 한다.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354public static void main(String[] args) {// 1. 기본타입 정렬IntStream intStream = Arrays.stream(new int[] { 5, 3, 2, 1, 4 });intStream.sorted().forEach(n -> System.out.println(n));System.out.println();// 2. 객체(Student)타입 정렬List<Student> list = Arrays.asList(new Student("홍길동", 90), new Student("홍길순", 95), new Student("홍길자", 89));// 1) 오름차순list.stream().sorted().forEach(n -> System.out.println(n));System.out.println();// 2) 내림차순list.stream().sorted(Comparator.reverseOrder()).forEach(s->System.out.println(s.getScore()));//Comparable을 구현해 compareTo()메서드를 정의한 클래스만 Comparator의 static 메서드//reverseOrder()를 사용해 내가 만든 기준의 반대로 정렬할 수 있다.}}class Student implements Comparable<Student> {private String name;private int score;public Student(String name, int score) {super();this.name = name;this.score = score;}public String getName() {return name;}public int getScore() {return score;}//@Overridepublic int compareTo(Student o) {// 점수를 기준으로 Student객체를 오름차순으로 정렬하기 위해// compareTo() 메서드를 재정의했다.return Integer.compare(score, o.score);// -1, 0, 1// Integer에는 compare가 정의되어 static으로 주고 있으니 int형은 이렇게 비교하면 된다~}@Overridepublic String toString() {return "Student [" + name + "]의 점수 " + score;}}cs
루핑( peek(), forEach() )
루핑(looping)은 요소 전체를 반복하는 것이다. 루핑메서드는 peek()와 forEach()가 있는데 이 두 메서드는 루핑한다는
기능은 동일하지만 peek()는 중간처리메서드이고 forEach()는 최종처리 메서드이다.
//내생각: forEach()는 stream을 반환하지 않고 링크된 메서드들을 종료시켜주지만, peek()는 루핑해서 다른 메서드에
stream으로 반환만 해주기 때문에 종결이 되지 않는다.
peek()는 중간처리단계에서 전체요소를 루핑하면서 추가적인 작업을 하기 위해서 사용되며 최종처리메서드가 처리되지 않으면
지연이 되기 때문에 반드시 최종처리메서드가 호출되어야 동작한다. 요소처리의 최종단계가 합계를 구하는 것이라면 peek()를
호출 후에 sum()을 호출해야만 peek()가 정상적으로 동작한다.
하지만 forEach() 는 최종처리메서드이기 때문에 파이프라인 마지막에 루핑하면서 요소를 하나씩 처리한다.
forEach()는 요소를 최종처리하는 메서드이기 때문에 forEach() 뒤에는 sum()과 같은 최종처리메서드를 호출하면 안된다.
123456789101112131415161718public static void main(String[] args) {int[] intArr = { 1, 2, 3, 4, 5 };// 1. peek()Arrays.stream(intArr).filter(a -> a % 2 == 0).peek(e -> System.out.println(e)); // peek()는 중간처리이기 때문에 종착하지 않고,// 실행결과가 없음, 공백처리System.out.println();// 2. 짝수합계 : 최종처리인 sum()집계함수를 이용int sum = Arrays.stream(intArr).filter(a -> a % 2 == 0).peek(e -> System.out.println(e)).sum();// peek()에서 끝나면 컴파일러가 오류라고 알려줌(중간단계에서 끝나서 int로 돌아오는게 없으니 오류)// peek()에서 돌리는게 있어야 오류 안뜸(그냥 peek()으로 비워두면 안되나 보다.)//그리고 콘솔에 짝수숫자만 찍히고 sum에 결과도 변수에 넣어줌System.out.println("짝수의 합 = " + sum);// 3. forEach()와 sum()모두 최종처리단계이니 같이 사용 불가.}cs
매칭( allMatch(), anyMatch(), noneMatch() )
스트림클래스는 최종처리단계에서 요소들이 특정조건에 만족하는지 여부를 조사할 수 있도록 3가지 매칭메서드를
제공하고 있다.
allMatch()메서드는 모든 요소들이 매개값으로 주어진 조건에 만족여부를, anyMatch()는 최소한 한개의 요소가 주어진
조건에 만족하는지를, noneMatch()는 모든 요소들이 만족하는지 여부(없으면 true, 있으면 false 반환)를 조사하는 메서드이다.
1234567891011121314151617181920212223public static void main(String[] args) {int[] intArr = { 2, 4, 6 };// 1. allMatch()boolean result = Arrays.stream(intArr).allMatch(n -> n % 2 == 0);System.out.println("전체가 2의 배수?: " + result + "\n"); //trueresult = Arrays.stream(intArr).allMatch(n -> n % 4 == 0);System.out.println("전체가 4의 배수?: " + result + "\n"); //false// 2. anyMatch()result = Arrays.stream(intArr).anyMatch(n -> n % 2 == 0);System.out.println("일부가 2의 배수?: " + result + "\n"); //true,전체가 2배수 당연히 trueresult = Arrays.stream(intArr).anyMatch(n -> n % 4 == 0);System.out.println("일부가 4의 배수?: " + result + "\n"); //true,일부가 4배수이니 true// 3. noneMatch()result = Arrays.stream(intArr).noneMatch(n -> n % 3 == 0);System.out.println("요소중에 3의 배수?: " + result + "\n"); //false, 없는지 물어봤으니 없으면 true, 있으면 fals}cs
기본집계(sum, average, count, max, min)
집계(Aggregate)는 최종처리기능으로 요소들을 처리해서 카운트, 합계, 평균, 최소/최대값등과 같이 하나의 값을 리턴하는 것을 말한다.
집계는 대량의 데이터를 가공해서 축소하는 리덕션(Reduction)이라고 볼 수 있다. 스트림이 제공하는 기본 집계는
1. count() : 요소들의 갯수를 리턴
2. findFirst() : 첫번째 요소를 리턴
3. max(Comparator<T>) : 요소들중 최대요소를 리턴
4. min(Comparator<T>) : 요소들중 최소요소를 리턴
5. average() : 요소들의 평균값을 리턴
6. sum() : 요소들의 합계를 리턴
이 집계요소에서 리턴하는 OptionalXXX()는 자바8에서 추가한 java.util 패키지의
Optional, OptionalDouble, OptionalInt, OptionalLong 클래스 타입이다.
이들 객체에서 값을 얻기 위해서 get(), getAsDouble(), getAsInt(), getAsLong()을 호출하면 된다.
이 OptionalXXX 클래스들은 저장하는 값의 타입만 다를 뿐 제공하는 기능은 거의 유사하다.
Optional클래스는 단순히 집계만 저장하는 것이 아니고 집계의 값이 존재하지 않을 경우 디폴트 값을 설정할 수 있고
집계값을 처리하는 Comsumer을 설정할 수도 있다.
12345678910111213141516171819202122232425262728int[] intArr = { 1, 2, 3, 4, 5 };// 1. count()double count = Arrays.stream(intArr).filter(n -> n % 2 == 0).count();System.out.println("2의 배수의 개수는 " + (int) count + "개 입니다.");// 2의 배수의 개수는 2개 입니다.// 2. sum()long sum = Arrays.stream(intArr).filter(n -> n % 2 == 0).sum();System.out.println("2의 배수의 합계는 " + (int) sum + "입니다.");// 2의 배수의 합계는 6입니다.// 3. average() 중간처리단계 = getAsDouble()로 받아서 Double형으로 반환후 끝내야함double average = Arrays.stream(intArr).filter(n -> n % 2 == 0).average().getAsDouble();System.out.println("2의 배수의 평균은 " + average + "입니다.");// 2의 배수의 평균은 3.0입니다.// 4. max() 중간처리단계int max = Arrays.stream(intArr).filter(n -> n % 2 == 0).max().getAsInt();System.out.println("2의 배수의 최댓값은 " + max + "입니다.");// 2의 배수의 최댓값은 4입니다.// 5. min()int min = Arrays.stream(intArr).filter(n -> n % 2 == 0).min().getAsInt();System.out.println("2의 배수의 최솟값은 " + min + "입니다.");// 2의 배수의 최솟값 2입니다.// 6 findFirst()int first = Arrays.stream(new int[] {1,2,3,4,5,6,3}).filter(n -> n%3 == 0).findFirst().getAsInt();System.out.println("3의 배수의 첫번째 값은 " + first + "입니다.");// 3의 배수의 첫번째 값은 3입니다.cs 123456789101112131415161718192021222324252627282930List<Integer> list = new ArrayList<Integer>();// OptionalXXX클래스의 메서드// 1. Stream 예외처리: try-catch 사용try {double avg = list.stream().mapToInt(Integer::intValue).average().getAsDouble();} catch (Exception e) {System.out.println("저장된 값이 없습니다!");}// 출력: 저장된 값이 없습니다!// 2. isPresent() : 값의 존재여부를 boolean으로 리턴OptionalDouble optional = list.stream().mapToInt(Integer::intValue).average();if (optional.isPresent()) {System.out.println("평균값 = " + optional.getAsDouble());} else {System.out.println("저장된 값이 없습니다!");}// 출력: 저장된 값이 없습니다!// 3. orElse() : 값이 없을 경우 기본값을 설정double avg = list.stream().mapToInt(Integer::intValue).average().orElse(0.0);System.out.println("평균값 = " + avg);// 출력: 평균값 = 0.0// 4. ifPresent() : 값이 있다면 truelist.stream().mapToInt(Integer::intValue).average().ifPresent(a->System.out.println("ifPresent(): 평균값 = "+ a));// 출력: 값이 없으니 출력하지 않는다.cs 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253List<Student> list = Arrays.asList(new Student("홍길동",92),new Student("홍길순",98),new Student("홍길자",95));// 1. 합계구하기(1) - sum()int sum = list.stream().mapToInt(Student::getScore).sum();System.out.println("합계 = " + sum);// 출력: 합계 = 285// 2. 합계구하기(2) - reduce(), 예외처리(x)sum = list.stream().mapToInt(Student::getScore).reduce((a,b) -> a+b).getAsInt();System.out.println("합계 = " + sum);// 출력: 합계 = 285// 92+98 = 190 , 190+95 = 285 로 루핑 돈다.// for{// sum += a;// } 이 상황인것.// 3. 합계구하기(3) - reduce(), 예외처리(o)sum = list.stream().mapToInt(Student::getScore).reduce(0,(a,b) -> a+b);System.out.println("합계 = " + sum);// 출력: 합계 = 285, 만약 값이 없다면 0으로 출력(예외를 처리한 것이다.)// reduce(없을시 나올 값, 값계산)}}class Student {private String name;private int score;public Student(String name, int score) {super();this.name = name;this.score = score;}public String getName() {return name;}public int getScore() {return score;}@Overridepublic String toString() {return name + "," + score;}}cs
수집(collect)
스트림은 요소들을 filtering 또는 mapping 한 후에 요소들을 수집하는 최종처리메서드인 collect()메서드를 제공한다.
Stream의 collect(Collector<T,A,R>) 메서드는 필터링 또는 매핑된 요소들을 새로운 collection에 수집하고 이 collection을
리턴한다.
매개값인 Collector(수집기)는 어떤 요소들을 어떤 컬렉션에 수집할 것인지를 결정한다.
collector의 타입파라미터는 T는 요소, A는 누적기(Accumulator), R은 요소가 저장될 컬렉션을 의미한다.
리턴값인 collector에는 Collector<T,?,R>처럼 누적기가 "?"로 되어 있는 경우도 있는데 이것은 Collector가 T를 R에 저장하는
방법을 알고 있어서 A가 필요없기 때문이다.
Map과 ConcurrentMap의 차이점은 Map은 쓰레드에 안전하지 않고, ConcurrentMap은 쓰레드에 안전한 차이밖에 없다.
멀티쓰레드환경에는 ConcurrentMap을 사용하는 것이 좋다.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546public class Student {public enum Gender {MALE, FEMALE}public enum City {SEOUL, BUSAN}private String name;private int score;private Gender gender;private City city;public Student(String name, int score, Gender gender) {super();this.name = name;this.score = score;this.gender = gender;}public Student(String name, int score, Gender gender, City city) {super();this.name = name;this.score = score;this.gender = gender;this.city = city;}public String getName() {return name;}public int getScore() {return score;}public Gender getGender() {return gender;}public City getCity() {return city;}}cs 12345678910111213141516171819202122232425262728List<Student> list = Arrays.asList(new Student("홍길동",10,Student.Gender.MALE),new Student("홍길순",6,Student.Gender.FEMALE),new Student("홍길녀",10,Student.Gender.MALE),new Student("홍길상",60,Student.Gender.FEMALE));// 1. Collector로 남학생들만 List컬렉션을 생성List<Student> maleList = list.stream().filter(s->s.getGender() == Student.Gender.MALE).collect(Collectors.toList());maleList.forEach(s -> System.out.println(s.getName()));//출력: 홍길동 홍길녀System.out.println();//Stream을 List로 컬렉션을 하나 만들어주는 Collectors클래스의 static 메서드. 여전히 Stream메서드도 사용가능하다.//2. Collector로 여학생들만 Set컬렉션을 생성Set<Student> femaleSet = list.stream().filter(s->s.getGender() == Student.Gender.FEMALE).collect(Collectors.toCollection(HashSet::new));// .collect(Collectors.toCollection(() -> {return new HashSet<Student>();}));// .collect(Collectors.toCollection(() -> new HashSet<Student>()));femaleSet.stream().forEach(s -> System.out.println(s.getName()));//출력: 홍길순 홍길상System.out.println();cs
그루핑( groupingBy(), groupingbyConcurrent() )
요소를 그룹핑해서 수집하기
collect()메서드는 단순히 요소를 수집하는 기능이외에 컬렉션의 요소들을 그룹핑해서 Map객체를 생성하는 기능을 제공한다.
collect()메서드를 호출할 때 Collector의 groupingBy() 또는 groupingbyConcurrent()가 리턴하는 Collector를 매개값으로 전달하면 된다.
groupingBy()는 쓰레드에 안전하지 않은 Map을 생성하지만, groupingbyConcurrent()는 쓰레드에 안전한 ConcurrentMap을 생성한다.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849public class GroupingMain {public static void main(String[] args) {List<Student> list = Arrays.asList(new Student("홍길동",10,Student.Gender.MALE,Student.City.SEOUL),new Student("홍길순",6,Student.Gender.FEMALE,Student.City.BUSAN),new Student("홍길녀",10,Student.Gender.MALE,Student.City.SEOUL),new Student("홍길상",60,Student.Gender.FEMALE,Student.City.BUSAN));Map<Student.Gender, List<Student>> mapByGender = list.stream().collect(Collectors.groupingBy(Student::getGender));// 1. 남학생mapByGender.get(Student.Gender.MALE).stream().forEach(s -> System.out.print(s.getName()+ ","));//출력: 홍길동,홍길녀,System.out.println();// 2. 여학생mapByGender.get(Student.Gender.FEMALE).stream().forEach(s -> System.out.print(s.getName()+ ","));System.out.println();//출력: 홍길순,홍길상,//Map과 List로 collect()를 돌려 만들 경우의 차이점은, List는 원하는 값에 일치하는 배열을 하나씩 따로 만들어야 하고//Map은 한번에 가져온 다음 가지고 오고 싶은 요소만 그룹핑 get하면 되는듯 하다.//3. 도시별 그룹핑(부산, 서울)Map<Student.City, List<Student>> mapByCity = list.stream().collect(Collectors.groupingBy(Student::getCity));mapByCity.get(Student.City.SEOUL).stream().forEach(s -> System.out.print(s.getName()+ ","));//출력: 홍길동,홍길녀,System.out.println();mapByCity.get(Student.City.BUSAN).stream().forEach(s -> System.out.print(s.getName()+ ","));//출력: 홍길순,홍길상,System.out.println();}}cs 'JAVA' 카테고리의 다른 글
HTTP,Tomcat이론,JSP:스크립트요소 (0) 2021.07.23 IO,NIO(New I/O), Enum(열거타입) (0) 2021.07.23 Thread, Generic, Lambda, Collection Framework (0) 2021.07.23 정규표현식,Arrays,java.lang 패키지 (0) 2021.07.23 java.lang.Object 클래스 (0) 2021.07.23