organize/자바

Java 37

001cloudid 2024. 8. 24. 15:22
728x90

Optional<T>

  • T 타입 객체의 래퍼클래스
    래퍼클래스 : Integer, Long,...
    null을 직접 다루는 것은 위험 → 간접적으로 null 다루기
    null 체크(if 문 필수) → 코드가 길어짐
    =>Optional 객체에 null을 넣음
public final class Optional<T>{
	private final T value; //T타입의 참조 변수. 모든 종류의 객체 저장 가능(null 가능)
    ...
}

Optional<T> 객체 생성하기

  • Optional<T>객체를 생성하는 다양한 방법
String str = "abc";
Optional<String> optVal = Optional.of(str);
Optional<String> optVal = Optional.of("abc");
//Optional<String> optVal = Optional.of(null); //NullPointerException 발생
Optional<String> optVal = Optional.ofNullable(null); //가능
  • null 대신 빈 Optional<T> 객체를 사용
Optional<String> optVal = null; //null로 초기화. 바람직하지 않음
Optional<String> optVal = Optional.<String>empty(); //빈 객체로 초기화

Optional<T> 객체의 값 가져오기

  • Optional 객체의 값 가져오기 - get(), orElse(), orElseGet(), orElseThrow()
Optional<String> optVal = Optional.of("abc");
String str1 = optVal.get(); //optVal에 저장된 값 반환. null이면 예외발생
String str2 = optVal.orElse(""); //optVal에 저장된 값이 null일 때는 ""를 반환
String str3 = optVal.orElseGet(String::new); //람다식 사용가능 () -> new String()
String str4 = optVal.orElseThrow(NullPointerException::new); //null이면 예외발생
  • Optional객체의 값이 null이면 false, 아니면 true를 반환 - isPresent()
if(Optional.ofNullable(str).isPresent(){ //if(str!=null){
	System.out.println(str);
}

 

package chapter14;

import java.util.Optional;

public class Study11_1 {

	public static void main(String[] args) {
		int[] arr = {};
		int[] arr1 = new int[0];
//		int[] arr2 = null;
		System.out.println("arr.length = " + arr.length);
		System.out.println("arr1.length = " + arr1.length);
//		System.out.println("arr2.length = " + arr2.length); //NullPointerException 발생
		
		Optional<String> opt = null; //가능은 하지만, 바람직하지 않음
		Optional<String> opt1 = Optional.empty();
		System.out.println("opt = " + opt);
		System.out.println("opt1 = " + opt1);
//		System.out.println("opt.get() = " + opt.get()); //NoSuchElementException 발생
//		System.out.println("opt1.get() = " + opt1.get()); NoSuchElementException 발생
		
		String str = "";
//		str = opt1.get(); //예외발생 → try-catch문 이용
		
		try {
			str = opt1.get();
		} catch (Exception e) {
			str = ""; //예외가 발생하면 빈 문자열("")로 초기화
		}
		System.out.println("str = " + str);
		
		//try-catch문을 이용하기 보다는 orElse() 메소드 사용
		 str = opt1.orElse("비어있음"); //Optional에 저장된 값이 null이면 ""반환
		 System.out.println("str = " + str);
		 
		 str = opt1.orElseGet(String::new);
		 System.out.println("str = " + str);

	}

}

 

OptionalInt, OptionalLong, OptionalDouble

  • 기본형 값을 감싸는 래퍼클래스 → 성능 때문에 사용
public final class OptionalInt{
	...
    private final boolean isPresent; //값이 저장되어 있으면 true
    private final int value; //int타입의 변수
  • OptionalInt의 값 가져오기
    Optional<T> T get()
    OptionalInt int getAsInt()
    OptionalLong long getAsLong()
    OptionalDouble double getAsDouble()
  • 빈 Optional객체와의 비교
OptionalInt opt = OptionalInt.of(0); //OptionalInt에 0을 저장
OptionalInt opt2 = OptionalInt.empty(); //OptionalInt에 0을 저장

System.out.println(opt.isPresent()); //true
System.out.println(opt2.isPresent()); //false
System.out.println(opt.equals(opt2)); //false
package chapter14;

import java.util.Optional;
import java.util.OptionalInt;

public class Study11_2 {

	public static void main(String[] args) {
		
		Optional<String> optStr = Optional.of("abcde");
		Optional<Integer> optInt = optStr.map(String::length);
		System.out.println("optStr = " + optStr.get());
		System.out.println("optInt = " + optInt.get());
		
		int result1 = Optional.of("123")
					.filter(x->x.length()>0)
					.map(Integer::parseInt).get();
		int result2 = Optional.of("")
					.filter(x->x.length()>0)
					.map(Integer::parseInt).orElse(-1);
		
		System.out.println("result1 = " + result1);
		System.out.println("result2 = " + result2);
		
		Optional.of("456").map(Integer::parseInt)
						.ifPresent(x->System.out.printf("result3 = %d%n", x));
		
		OptionalInt optInt1 = OptionalInt.of(0); //0을 저장
		OptionalInt optInt2 = OptionalInt.empty(); //빈 객체를 저장
		
		System.out.println("optInt1.isPresent() = "+optInt1.isPresent());
		System.out.println("optInt2.isPresent() = "+optInt2.isPresent());

		System.out.println("optInt1.getAsInt() = "+optInt1.getAsInt());
//		System.out.println("optInt2.getAsInt() = "+optInt2.getAsInt()); //NoSuchElementException
		System.out.println("optInt1 = " + optInt1);
		System.out.println("optInt2 = " + optInt2);
		System.out.println("optInt1.equals(optInt2) = "+optInt1.equals(optInt2));
		
	}

}

 

스트림의 최종연산 - forEach()

  • 스트림의 모든 요소에 지정된 작업을 수행 - forEach(), forEachOrdered()
void forEach(Consumer<? super T> action) //병렬스트림인 경우 순서가 보장되지 않음
void forEachOrdered(Consumer<? super T> action) //병렬스트림인 경우에도 순서가 보장됨

//sequential() : 직렬스트림, 생략가능
IntStream.range(1,10).sequential().forEach(System.out::print); //123456789
IntStream.range(1,10).sequential().forEachOrdered(System.out::print); //123456789

//parallel() : 병렬 스트림
IntStream.range(1,10).parallel().forEach(System.out::print); //순서가 보장되지 않는 1~9까지 숫자
IntStream.range(1,10).parallel().forEachOrdered(System.out::print); //123456789

 

스트림의 최종연산 - 조건 검사

  • 조건 검사 - allMatch(), anyMatch(), noneMatch()
boolean allMatch (Predicate<? super T> predicate) //모든 요소가 조건을 만족시키면 true
boolean anyMatch (Predicate<? super T> predicate) //한 요소라도 조건을 만족시키면 true
boolean noneMatch (Predicate<? super T> predicate) //모든 요소가 조건을 만족시키지 않으면 true
  • 조건에 일치하는 요소 찾기 - findFirst(), findAny()
Optional<T> findFirst() //첫 번째 요소를 반환. 순차 스트림에 사용
Optional<T> findAny() //아무거나 하나를 반환. 병렬 스트림에 사용
//Optional인 이유? 결과가 null일 수 있어서

 

스트림의 최종연산 - reduce()

  • 스트림의 요소를 하나씩 줄여가며 누적연산 수행
Optional<T> reduce(BinaryOperator<T> accumulator)
T			reduce(T identity, BinaryOperator<T> accumulator)
U			reduce(U identity, BiFunction<U,T,U> accumulator, BinaryOperator<U> combiner)
//identity 초기값, accumulator 이전 연산결과와 스트림의 요소에 수행할 연산, combiner 병렬처리된 결과를 합치는데 사용할 연산(병렬 스트림)

int count = intStream.reduce(0,(a,b)->a+1); //요소개수
int sum = intStream.reduce(0,(a,b)->a+b); //=> int a = identity; for(int b : stream) a=a+b;
int max = intStream.reduce(Integer.MIN_VALUE,(a,b)->a>b?a:b);
int min = intStream.reduce(Integer.MAX_VALUE,(a,b)->a<b?a:b);
package chapter14;

import java.util.Optional;
import java.util.OptionalInt;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class Study12_1 {

	public static void main(String[] args) {
		
		String[] strArr = {"Inheritance","Java","Lambda","stream","IntStream","OptionalDouble","count","sum"};
		Stream.of(strArr).forEach(System.out::println);

		System.out.println();
		
		boolean noEmptyStr = Stream.of(strArr).noneMatch(s->s.length()==0);
		Optional<String> sWord = Stream.of(strArr).filter(s->s.charAt(0)=='s').findFirst();
		
		System.out.println("noEmptyStr = " + noEmptyStr);
		System.out.println("sWord = " + sWord);
		
		System.out.println();
		
		//Stream<String[]>을 IntStream으로 변환
		IntStream intStream1 = Stream.of(strArr).mapToInt(String::length);
		IntStream intStream2 = Stream.of(strArr).mapToInt(String::length);
		IntStream intStream3 = Stream.of(strArr).mapToInt(String::length);
		IntStream intStream4 = Stream.of(strArr).mapToInt(String::length);
		
		int count = intStream1.reduce(0, (a,b)->a+1);
		int sum = intStream2.reduce(0, (a,b)->a+b);
		
		OptionalInt max = intStream3.reduce(Integer::max);
		OptionalInt min = intStream4.reduce(Integer::min);
		
		System.out.println("count = " + count);
		System.out.println("sum = " + sum);
		System.out.println("max = " + max);
		System.out.println("max.getAsInt() = " + max.getAsInt());
		System.out.println("min = " + min);
		System.out.println("min.getAsInt() = " + min.getAsInt());

	}

}

 

collect()와 Collectors

  • collect는 Collector를 매개변수로 하는 스트림의 최종 연산
Object collect(Collector collector) //Collector를 구현한 클래스의 객체를 매개변수로
  • Collector는 수집(collect)에 필요한 메소드를 정의해 놓은 인터페이스
public interface Collector<T,A,R>>{ //T(요소)를 A에 누적한 다음, 결과를 R로 변환해서 반환
	Supplier<A> supplier(); //StringBuilder::new 누적할 곳
    BiConsumer<A,T> accumulator(); //(sb,s)->sb.append(s) 누적방법
    BinaryOperator<A> combiner(); //(sb1,sb2)->sb1.append(sb2) 결합방법(병렬)
    Function<A,R> finisher() //sb->sb.toString() 최종변환
    Set<Characteristics> characteristics(); //컬렉터의 특성이 담긴 Set을 반환
	...
}
  • Collectors 클래스는 다양한 기능의 컬렉터(Collector를 구현한 클래스)를 제공
    변환 : mapping(), toList(), toSet, toMap(), toCollection(),...
    통계 : counting(), summingInt(), averagingInt(), maxBy(), minBy, summarizingInt(),..
    문자열 결합 : joining()
    리듀싱 : reducing()
    그룹화와 분할 : groupingBy(), partitioningBy(), collectingAndThen()

스트림을 컬렉션, 배열로 변환

  • 스트림을 컬렉션으로 변환 : toList(), toSet(), toMap(), toCollection()
  • 스트림을 배열로 변환 : toArray()
Student[] stuNames = studentStream.toArray(Student[]::new); //가능
Student[] stuNames = studentStream.toArray(); //에러
Object[] stuNames = studentStream.toArray(); //가능

스트림의 통계

  • 스트림의 통계정보 제공 : counting(), summingInt(), maxBy(), minBy(),...

스트림을 리듀싱

  • 스트림을 그룹별 리듀싱 : reducing()
Collector reducing(BinaryOperator<T> op)
Collector reducing(T identity, BinaryOperator<T> op)
Collector reducing(U identity, Function<T,U> mapper ,BinaryOperator<T> op) //map+reduce
  • 문자열 스트림의 요소를 모두 연결 : joining

스트림의 그룹화와 분할

  • partitioningBy()는 스트림을 2분할
Collector partitioningBy(Predicate predicate)
Collector partitioningBy(Predicate predicate, Collector downstream)
  • groupingBy()는 스트림을 n분할
Collector groupingBy(Function classifier)
Collector groupingBy(Function classifier, Collector downstream)
Collector groupingBy(Function classifier, Supplier mapFactory, Collector downstream)

 

package chapter14;

import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import static java.util.stream.Collectors.*;
import static java.util.Comparator.*;

class Student14_1{
	String name;
	boolean isMale; //성별
	int grade;
	int ban;
	int score;
	
	Student14_1(String name, boolean isMale, int grade, int ban, int score) {
		this.name = name;
		this.isMale = isMale;
		this.grade = grade;
		this.ban = ban;
		this.score = score;
	}
	
	String getName() {return name;}
	boolean getIsMale() {return isMale;}
	int getGrage() {return grade;}
	int getBan() {return ban;}
	int getScore() {return score;}
	
	public String toString() {
		return String.format("[%s, %s, %d학년 %d반, %3d점]", name,isMale?"남":"여",grade,ban,score);
	}
	
	//groupingBy()에서 사용
	enum Level{HIGH,MID,LOW}
	
}

public class Study14_1 {

	public static void main(String[] args) {
		Student14_1[] stuArr = {
				new Student14_1("A", false, 1, 1, 300),
				new Student14_1("B", true, 1, 1, 200),
				new Student14_1("C", false, 1, 1, 250),
				new Student14_1("D", true, 1, 2, 100),
				new Student14_1("E", true, 1, 2, 150),
				new Student14_1("F", true, 1, 2, 300),
				new Student14_1("G", true, 1, 2, 300),
				new Student14_1("H", false, 1, 3, 300),
				new Student14_1("I", false, 1, 3, 200),
				new Student14_1("J", true, 1, 3, 180),
				new Student14_1("K", true, 2, 1, 300),
				new Student14_1("L", false, 2, 1, 190),
				new Student14_1("M", false, 2, 1, 270),
				new Student14_1("N", true, 2, 2, 230),
				new Student14_1("O", true, 2, 2, 250),
				new Student14_1("P", true, 2, 2, 200),
				new Student14_1("Q", false, 2, 3, 170),
				new Student14_1("R", false, 2, 3, 300),
				new Student14_1("S", true, 2, 3, 180)
		};
		
		System.out.println("1. 단순그룹화(반별로 그룹화)");
		Map<Integer, List<Student14_1>> stuByBan = Stream.of(stuArr)
				                                     .collect(groupingBy(Student14_1::getBan));
		for(List<Student14_1> ban : stuByBan.values()) {
			for(Student14_1 s:ban) {
				System.out.println(s);
			}
		}
		
		System.out.println();
		
		System.out.printf("%n2. 단순그룹화(성적별로 그룹화)%n");
		Map<Student14_1.Level, List<Student14_1>> stuByLevel = Stream.of(stuArr)
				.collect(groupingBy(s-> {
						 if(s.getScore() >= 200) return Student14_1.Level.HIGH;
					else if(s.getScore() >= 100) return Student14_1.Level.MID;
					else                         return Student14_1.Level.LOW;
				}));

		TreeSet<Student14_1.Level> keySet = new TreeSet<>(stuByLevel.keySet());

		for(Student14_1.Level key : keySet) {
			System.out.println("["+key+"]");

			for(Student14_1 s : stuByLevel.get(key))
				System.out.println(s);
			System.out.println();
		}

		System.out.printf("%n3. 단순그룹화 + 통계(성적별 학생수)%n");
		Map<Student14_1.Level, Long> stuCntByLevel = Stream.of(stuArr)
				.collect(groupingBy(s-> {
						 if(s.getScore() >= 200) return Student14_1.Level.HIGH;
					else if(s.getScore() >= 100) return Student14_1.Level.MID;
					else                         return Student14_1.Level.LOW;
				}, counting()));

		for(Student14_1.Level key : stuCntByLevel.keySet())
			System.out.printf("[%s] - %d명, ", key, stuCntByLevel.get(key));
		System.out.println();
/*
		for(List<Student14_1> level : stuByLevel.values()) {
			System.out.println();
			for(Student s : level) {
				System.out.println(s);
			}
		}
*/
		System.out.printf("%n4. 다중그룹화(학년별, 반별)%n");
		Map<Integer, Map<Integer, List<Student14_1>>> stuByGradeAndBan =
          Stream.of(stuArr)
				.collect(groupingBy(Student14_1::getGrage,
						 groupingBy(Student14_1::getBan)
				));

		for(Map<Integer, List<Student14_1>> hak : stuByGradeAndBan.values()) {
			for(List<Student14_1> ban : hak.values()) {
				System.out.println();
				for(Student14_1 s : ban)
					System.out.println(s);
			}
		}

		System.out.printf("%n5. 다중그룹화 + 통계(학년별, 반별 1등)%n");
		Map<Integer, Map<Integer, Student14_1>> topStuByHakAndBan = Stream.of(stuArr)
				.collect(groupingBy(Student14_1::getGrage,
						 groupingBy(Student14_1::getBan,
							collectingAndThen(
								maxBy(comparingInt(Student14_1::getScore)),
								Optional::get
							)
						)
				));

		for(Map<Integer, Student14_1> ban : topStuByHakAndBan.values())
			for(Student14_1 s : ban.values())
				System.out.println(s);

		System.out.printf("%n6. 다중그룹화 + 통계(학년별, 반별 성적그룹)%n");
		Map<String, Set<Student14_1.Level>> stuByScoreGroup = Stream.of(stuArr)
			.collect(groupingBy(s-> s.getGrage() + "-" + s.getBan(),
					mapping(s-> {
						 if(s.getScore() >= 200) return Student14_1.Level.HIGH;
					else if(s.getScore() >= 100) return Student14_1.Level.MID;
						 else                    return Student14_1.Level.LOW;
					} , toSet())
			));

		 Set<String> keySet2 = stuByScoreGroup.keySet();

		for(String key : keySet2) {
			System.out.println("["+key+"]" + stuByScoreGroup.get(key));
		}
		
	}
		
}
728x90

'organize > 자바' 카테고리의 다른 글

Java36  (0) 2024.08.23
Java 35  (1) 2024.08.22
Java 34  (0) 2024.08.22
Java 33  (0) 2024.08.21
Java 32  (0) 2024.08.20