개발 메모장

[Java] Stream API(3) - 결과 도출 본문

Java

[Java] Stream API(3) - 결과 도출

yyyyMMdd 2023. 12. 14. 17:38
728x90
  • 숫자 연산 작업

    - 기본적으로 사용하는 합계, 평균, 개수, 최댓값, 최솟값 등을 처리합니다.

    - 리턴 값을 OptionalInt로 통일하기 위해 리턴이 int인 sum도 OptionalInt로 형변환 하였습니다.

    - OptionalInt 사용 시 리턴 값이 OptionalInt 객체로 처리되므로 숫자만 리턴 받고자 할 땐 .getAsInt()를 사용하면 됩니다.

    - 또한 스트림 객체에 값이 없는 경우 리턴 값은 OptionalInt.empty이므로 null 값에 대한 처리를 위해 orElse(0) 처리를 해주면 됩니다.
int[] intArray = {10, 20, 30, 40, 50};

OptionalInt sum = OptionalInt.of(IntStream.of(intArray).sum());
OptionalInt max = IntStream.of(intArray).max();
OptionalDouble avg = IntStream.of(intArray).average();
OptionalInt min = IntStream.of(intArray).min();

System.out.println(sum.getAsInt());
System.out.println(max.orElse(0));
System.out.println(avg.orElse(0));
System.out.println(min);

// 150
// 50
// 30.0
// OptionalInt[10]

 


  • forEach

    - 스트림 객체 내 데이터 개수만큼 반복하여 내부의 출력 또는 추가적인 처리를 할 수 있게 해 줍니다.
  • // 출력 시
    brandList.stream().map(BrandVO::getName).forEach(System.out::print);
    // filanikeadidaspumaunderarmor
    
    // 새 리스트에 객체 담기
    List<String> filteredNamesList = new ArrayList<>();
    brandList.stream().map(BrandVO::getName)
    		  .map(name -> name.toUpperCase())
    		  .forEach(name -> { if(name.length() > 5) { 
    					filteredNamesList.add(name);
    				    }
    		    }) ;
    // [ADIDAS, UNDERARMOR]

  • ifPresent

    - 처리한 값이 있을 경우에 대한 추가 로직을 작성해 줍니다.

    - 처리한 값이 null인 경우 ifPresent() 안의 인자는 처리되지 않습니다.

    - 고로 null검사를 별도로 하지 않아도 NPE가 발생을 방지할 수 있습니다.
int[] intArray = {10, 20, 30, 40, 50};
IntStream.of(intArray).max().ifPresent(value -> System.out.println("test ==> " + value));
// test ==> 50

int[] intArray = {};
IntStream.of(intArray).max().ifPresent(value -> System.out.println("test ==> " + value));
//

IntStream.of(intArray).max()
	.ifPresent(value -> { int test = value * value;
			      System.out.println(test);
			    });
// 2500

 


  • reduce

    - 스트림의 요소들을 단일 값으로 될 때까지 반복적으로 결합 및 도출해 내는 메서드입니다.

    - 인자 개수에 따라 오버로딩 되어 처리되며 Identity(초기 값) / Accumulator(이진 연산자) / combiner(병렬 스트림)으로 나뉩니다.
// Accumulator 파라미터가 1개인 경우
Optional<Integer> streamNum1 = Stream.of(100, 200, 300, 400, 500)
				.reduce(Integer::sum); 
// 1500

Optional<String> streamStr2 = Stream.of("momo", "gugu", "chichi")
				.reduce((s1, s2) -> s1.toUpperCase() + ", " + s2.toUpperCase());
// MOMO, GUGU, CHICHI

// Identity, Accumulator 파라미터가 2개인 경우
Optional<Integer> streamNum2 = Optional.of(Stream.of(100, 200, 300, 400, 500)
					.reduce(1, Integer::sum)); 
// 1501

// Identity, Accumulator, combiner 파라미터가 3개인 경우
// 순차처리로 인해 병렬 미처리로 syso의 값이 출력되지 않음
Optional<Integer> sequentialStreamNum3 = Optional.of(Stream.of(100, 200, 300, 400, 500)
				.reduce(10, Integer::sum, (a,b) -> {
						System.out.println("sequential -> " + a + " + " + b);
						return a+b;
					})
				); 
// 1510

// 병렬처리 시 각각의 스레드에서 처리된 값들을 결국 하나로 합쳐 보여줌
Optional<Integer> parallelStreamNum3 = Optional.of(Stream.of(100, 200, 300, 400, 500).parallel()
				.reduce(10, Integer::sum, (a,b) -> {
						System.out.println("parallel -> " + a + " + " + b); 
						return a+b;
					})
				); 

// parallel -> 410 + 510
// parallel -> 310 + 920
// parallel -> 110 + 210
// parallel -> 320 + 1230
// 1550

    - 병렬처리를 해주는 combiner를 세 번째 인자로 추가할 경우 해당 스트림을 병렬처리 메서드인 parallel()을 붙여 사용하면 됩니다.

    - 병렬처리를 하지 않을 경우 실행된 내용 확인이 어렵습니다.

 


  • match

    - 람다식으로 조건을 넣어 or, and, nor과 같은 작업을 메서드로 처리합니다.
// 전체 매칭 시 true
Boolean allMatchNames = brandList.stream().map(BrandVO::getName).allMatch(n -> n.length() > 6);
// false

// 일부 매칭 시 true
Boolean anyMatchNames = brandList.stream().map(BrandVO::getName).anyMatch(n -> n.length() > 6);
// true

// 전체 미매칭 시 true
Boolean noneMatchNames = brandList.stream().map(BrandVO::getName).noneMatch(n -> n.length() > 6);
// false

 


  • collect의 경우 객체로 처리하기 위해 VO(변수, getter, setter, toString) 생성 및 List 생성
List<BrandVO> brandList = Arrays.asList(new BrandVO("fila", 20),
                                        new BrandVO("nike", 90),
                                        new BrandVO("adidas", 80),
                                        new BrandVO("puma", 80),
                                        new BrandVO("underarmor", 20)
					);

  • collect

    - 스트림 객체를 컬렉션 등으로 변환 및 집계할 수 있도록 하는 메서드입니다.

  • Collectors.toList()

    - 이전부터 편의상 사용해 온 List 변환 기능을 제공합니다.
List<String> collectNameList = brandList.stream().map(BrandVO::getName).collect(Collectors.toList());
// [fila, nike, adidas, puma, underarmor]

  • Collectors.joining()

    - 각각의 객체를 하나의 String으로 변환합니다.

    - 인자에는 구분자, 프리픽스, 서픽스를 넣어 사용 가능합니다.
String joiningNamesStr = brandList.stream().map(BrandVO::getName).collect(Collectors.joining(", "));
// fila, nike, adidas, puma, underarmor

  • Collectors.summarizingInt()

    - 카운트, 합계, 최솟값, 평균, 최댓값을 가져오는 메서드입니다.

    - 각 값을 가져올 땐 .get키값으로 호출 가능합니다.

    - summarizingDouble과 summarizingLong도 있어 데이터에 맞게 처리하면 됩니다.

    - 해당 데이터의 타입은 IntSummaryStatistics로 받아야 합니다.
IntSummaryStatistics isStaticSince = brandList.stream().collect(Collectors.summarizingInt(BrandVO::getSince));
// IntSummaryStatistics{count=5, sum=290, min=20, average=58.000000, max=90}

  • Collectors.collectingAndThen()

    - collect를 사용하고 난 뒤 후처리할 작업에 대한 코드를 추가할 수 있는 메서드입니다.

    - 주로 list, set 등 컬렉션에 대한 수정불가 처리, 로직 추가, 검증, 변환 등의 작업을 처리합니다.
Object catList = brandList.stream().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
// [{name=fila, since=20}, {name=nike, since=90}, {name=adidas, since=80}, {name=puma, since=80}, {name=underarmor, since=20}]

 


#. 간혹 사용하는 것들과 간단히 알아볼 수 있는 것에 대해서만 정리를 했는데도 수많은 내용이 더 있습니다.

 

#. 사용하다가 필요하다고 느끼는 것이나 편하다고 느끼는 것이 있다면 업데이트해보도록 하겠습니다.

 

 

===========================================================
틀린 내용이 있거나 이견 있으시면 언제든 가감 없이 말씀 부탁드립니다!

===========================================================

728x90