JAVA

Java Collectors의 메소드 정리(for 람다)

람다를 제대로 활용하기 위해선 Java의 Collection과 Stream에 대한 정리가 필요할 것이라 생각하여 글을 포스팅 한다.

우선 사용하게 될 package들을 정리해 보았다.

  • java.util.Collection(Interface)
    • List, Set, Map CRUD를 위해서 활용한다.
  • java.util.Collections(Class)
    • Collection Inteface의 객체들을 관리하는 클래스이다.
    • 객체간의 변환과 객체의 데이터를 탐색하는 기능을 주로 가진다.
  • java.util.Arrays
    • [ ]형태의 배열 또는 Collection 이너페이스의 객체들을 배열로 관리하는 기능을 가진다.

람다식 활용법 

  • 1. 람다식을 활용하기 위해서 Stream으로 바꾸는 방법
    • stream() 을 사용하거나 java.util.stream의 stream.of() 함수를 이용한다.
    • stream의 객체 생성 -> 집계 연산, 탐색, 출력(중간 작업/ 종단 작업) Collection -> stream 방식을 활용하면 된다. 
  • 2. Stream에서 다시 Collection으로 바꾸는 방법
    • java.util.stream.Stream의 Collect()를 통해서 Collection 객체로 변환한다.
      • 방법 1
        • Collect(Collector c)
        • List, Set, Map 변환 작업 후 각 개체의 메소드를 통해 데이터를 처리할 경우 사용
      • 방법 2
        • Collect(Supplier, BiConsumer, BiConsumer)
        • List, set, map에 존재하지 않는 경우 사용, 확장할 수 있는 기능을 사용하고 싶을 때 사용한다.

Collectors의 메소드 정리

1. group by

  • groupingBy(Function<? super T, ? extends K> classifier):
    • 대상 조건은 function으로 이용하여 스트림의 각 요소를 변환한 결과가 true 값일 때 실행되는 구문으로 지정한다.
  • groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T,A,D> downstream)
    • 첫번째 매개인자 Function으로 스트림의 각 요소를 변환한 결과를 리턴하는 객체이며 두 번째 매개인자는 리턴되는 객체가 어떻게 유지되는 지 결정한다.
  • groupingBy(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory, Collector<? super T,A,D> downstream)
    • 첫번째 매개인자 Function으로 스트림의 각 요소를 반환한 결과를 리턴하는 객체, 두번째 매개인자는 리턴되는 객체를 Map으로 지정하고 세번째 매개인자는 Map을 어떻게 유지할지 결정한다.

2. join

  • joining()
    • 문자열 스트림 요소를 연결한 문자열을 생성하는 메소드
  • joining(CharSequence delimeter)
    • 구분자를 지정해서 문자열의 스트림 요소를 생성
  • joining(CharSequence delimeter, CharSequence prefix, CharSequence suffix)
    • 구분자의 시작태그 끝 태그 지정

GroupBy와 Join을 사용한 예제

		System.out.println("1. 나열된 문자열의 길이로 그룹핑");
		Stream<String> s= Stream.of("나","너","우리","모두","노래해요");
		
		Map<Integer, List<String>> res= s.collect(Collectors.groupingBy(t->t.length()));
		System.out.println(res);
		//결과
		//{1=[나, 너], 2=[우리, 모두], 4=[노래해요]}

groupingBy를 활용하여 문자열의 길이 별로 다르게 매핑하였다. 결과 값에서 볼 수 있듯이 길이에 따라 다르게 매핑된 것을 볼 수 있다.

		System.out.println("2. 나열된 문자열의 길이로 그룹핑 + join");
		Stream<String> s01= Stream.of("나","너","우리","모두","노래해요");
		//조인은 문자열로
		Map<Integer, String> res01=
				s01.collect(Collectors.groupingBy(t->t.length(),Collectors.joining()));
		System.out.println(res01);
		//결과
		//{1=나너, 2=우리모두, 4=노래해요}

결과 값에 Join을 사용해서 문자열을 이어붙인 결과이다. 리턴되는 객체가 어떻게 유지될지를 설정할 수 있는 매개인자 2개까지 groupingBy 문에 joining을 활용하여 문자열을 이어 붙여 주었다.

 

		System.out.println("3. 나열된 문자열의 길이로 그룹핑 + join 매개인자 세개");
		Stream<String> s02= Stream.of("나","너","우리","모두","노래해요");
		Map<Integer,String> res02
		=s02.collect(Collectors.groupingBy(t->t.length(),
				TreeMap::new,Collectors.joining()));
		System.out.println(res02);
		//결과
		//{1=나너, 2=우리모두, 4=노래해요}

매개인자 3개짜지 groupingBy문을 이용하여 리턴되는 map객체의 형태와, joining을 지정하는 방식을 활용하였다.

		Stream<String> s01= Stream.of("딸기","바나나","메론","포도");
		String str=s01.collect(Collectors.joining());
		System.out.println(str);
		//결과
		//딸기바나나메론포도
		
		s01= Stream.of("딸기","바나나","메론","포도");
		str=s01.collect(Collectors.joining(":", "<<",">>"));
		System.out.println(str);
		//결과
		//<<딸기:바나나:메론:포도>>

위의 첫번째 예제에서는 collect의 joining을 사용하여 모든 문자열을 이어 붙여 주었으며, 두 번째 예제에서는 문자열 연결시 " : "로 구분 지으며 prefix에는 << , suffix에는 >>를 넣어 주는 문자열을 만들어 주었다. 추후 문자열을 관리함에 있어 자주 사용될 수 있는 구문이므로 익혀두면 분명 도움이 될 것이다.

 

3. partition

  • partitioningBy(Predicate<? super T> predicate)
    • 매개인자 판정을 기준으로 true, false를 분할 시킨다.
  • partitioningBy(Predicate<? super T> predicate, Collector<? super T,A,D> downstream)
    • 매개인자 판정을 기준으로 true, false를 분할하고 Collector의 Map에다가 저장하는 방식이다
		Stream<Character> str= Stream.of('1','2','a','b','3');
		Map<Boolean, List<Character>> res= 
				str.collect(Collectors.partitioningBy(c->Character.isDigit(c)));
		System.out.println(res);
		//결과
		//{false=[a, b], true=[1, 2, 3]}
		
		str= Stream.of('1','2','a','b','3');
		Map<Boolean, String> res02= 
				str.collect(Collectors.partitioningBy(c->Character.isDigit(c),
						Collectors.mapping(c->c.toString(), Collectors.joining())
						   							)
						);
		System.out.println(res02);
		//결과
		//{false=ab, true=123}

위의 첫 번째 에제에서는 문자인지 숫자인지를 판별 기준으로 나누어서 각각을 다른 카테고리로 저장시켜 주었다. 반면 두번째 함수에서는 인자가 두 개 짜리인 partitioningBY를 활용하여, Map에 저장될 방식을 재정의 함으로서 만들어진 문자열들을 이어 붙여주는 방식을 활용하였다.

4. 집계

stream 컬랙션의 값을 집계를 낸 후 숫자로 변경해서 연산하는 메소드들을 정리하였다.

  • IntSummaryStatistics
    • 합계, 최소, 최대, 평균, 개수를 산출하여 int로 리턴
  • LongSummaryStatistics
  • DoubleSummaryStatistics
  • minBy
    • 최소 값
  • maxBy
    • 최대 값
		String[] my_str= {"딸기","바나나","메론","포도"};
		Stream<String> s= Stream.of(my_str);
		Optional<String> m=s.collect(Collectors.minBy(Comparator.naturalOrder()));
		System.out.println("최소값 ="+ m);
		//결과
		//최소값 =Optional[딸기]
		
		s= Stream.of(my_str);
		m=s.collect(Collectors.maxBy(Comparator.naturalOrder()));// 자연 정렬
		System.out.println("최대값 ="+ m);
		//결과최대값 =Optional[포도]
		//
		
		//카운팅
		s= Stream.of(my_str);
		System.out.println("counting:" +s.collect(Collectors.counting()));
		//결과
		//counting:4
		
		// 서머리 집계를 해보자.
		s= Stream.of(my_str);
		IntSummaryStatistics res= s.collect(Collectors.summarizingInt(t->t.length()));
		System.out.println(res);
		//결과
		//IntSummaryStatistics{count=4, sum=9, min=2, average=2.250000, max=3}
		
		Stream<String> s04= Stream.of("10","20","30","40","50");
		LongSummaryStatistics res01=s04
				.collect(Collectors
						.summarizingLong(t->Long.parseLong(t)));
		System.out.println(res01);
		//결과
		//LongSummaryStatistics{count=5, sum=150, min=10, average=30.000000, max=50}