프로그래밍/- java

스트림 , 래퍼클래스(optional)

즐겁게 하하하 2022. 2. 5. 08:57
728x90

 

 

직렬화   : 객체를 데이터 스트림으로 만드는것
역직렬화 : 스트림으로부터 데이터를 읽어서 객체를 만드는것 

★ 스트림
  - 다양한 데이터 소스를 표준화된 방법으로 다루기 위함 
  - 데이터 소스로부터 읽기만 할뿐 변경하지 않는다.
  - Iterator 처럼 일회용이다. 필요하면 다시 스트림을 생성해야함.
  - 최종 연산 전까지 중간연산이 수행되지 않는다.( 지연된 연산 ) :: 중간 → 최종 (x)
  - 작업을 내부 반복으로 처리한다.( forEach 사용 가능 )
  - 작업을 병렬로 처리가 가능하다. ( 멀티 쓰레드 ) 
    병렬:  parallel();  /  직렬: sequential();
  - 컬렉션( List , Set , Map ) , 배열  => Stream => 중간연산(n번) => 최종연산(1번)
    중간연산 : 결과가 스트림 , 최종연산 : 스트림이 아님


★ 기본형 스트림
  - IntStream , LongStream , DoubleStream
  - 오토박싱 언박싱의 비효율 제거됨( Stream<Integer> 대신 IntStream 사용 )


★ 파일과 빈 스트림
  Stream<Path> File.list(Path dir); :: path는 파일 또는 디렉토리
  Stream<String> File.lines(Path path)
  Stream<String> File.lines(Path path , Charset cs)
  Stream<String> lines() :: BufferedReader클래스의 메서드


★ 특정 범위의 정수 스트림 만들기
   IntStream intStream = IntStream.range(1,5);        :: 1,2,3,4
   IntStream intStream = IntStream.rangeClosed(1,5);  :: 1,2,3,4,5


★ 람다식 스트림 만들기 ( iterate() , generate() )
   static <T> Stream<T> iterate( 초기값 , 람다식 );  :: 이전 요소에 종속적
   static <T> Stream<T> generate( 람다식 );          :: 이전 요소에 독립적 , 초기값이 없다.
  
   Stream<Integer> intStream = Stream.iterate(1, n-> n+2 );
   intStream.limit(5).forEach(System.out::print);  
   Stream<Integer> oneStream = Stream.generate(()->1);
   oneStream.limit(5).forEach(System.out::print);


★ 임의의수 ( 난수 ) 스트림 만들기
   1. IntStream intStream = new Random().ints();
      intStream.limit(5).forEach(System.out::println); :: limit(5) 안붙이면 무한 스트림
   2. IntStream intStream = new Random().ints(5);
 

 

★ T 타입 객체의 래퍼클래스 Optional<T>
   => null을 직접 다루는 것은 위험하다.
   => null 체크시 if 문 필수 > 코드 지저분 
   Optional<String> optVal = Optional.of("abc");
   Optional<String> optVal = Optional.ofNullable(null);
   
   String str1 = optVal.get() :: 저장된 값을 반환 , null 이면 예외 발생
   String str1 = optVal.orElse("") :: 저장된 값이 null인 경우 "" 반환
   String str2 = optVal.orElseer(String::new) :: 람다식 사용가능 () -> new String()
   String str2 = optVal.orElseThrow(NullPointerException::new) :: null이면 예외 발생
   if( Optional.ofNullable(str).ifPresent() ) :: null이면 false


★ 기본형 값을 감싸는 래퍼 클래스
   OptionalInt , OptionalLong , OptionalDouble
   OptionalInt opt = OptionalInt.of(0);    
   OptionalInt opt2 = OptionalInt.empty();

   System.out.printf(opt.isPresent) :: true 
   System.out.printf(opt2.isPresent) :: false
   System.out.printf(opt.equals(opt2)) :: false

   Integer a = opt.getAsInt();
   Long a    = opt.getAsLong();
   Double a  = opt.getAsDouble();
 

 

Optional<String>  optStr = Optional.of("abcde");
Optional<Integer> optInt = optStr.map(String::length); // s -> s.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));
 
추가 정렬 기준을 정할 경우 .thenComparing( String::length )

 

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class hello {
	public static void main(String[] args) { 
		
		// list를 Stream으로 변환
		 List<Integer> list = Arrays.asList(1,2,3,4,5);
		 Stream<Integer> intStream = list.stream(); 
		 intStream.forEach(System.out::print);
		 System.out.println("===============");
		 
		 //객체 배열로 부터 스트림 생성하기
		 Stream<String> strStream = Stream.of("a","b","c"); 
		 Stream<String> strStream2 = Stream.of(new String[]{"a","b","c" }); 		 
		 Stream<String> strStream3 = Arrays.stream(new String[]{"a","b","c" });
		 Stream<String> strStream4 = Arrays.stream(new String[]{"a","b","c" },0,3);
		 strStream.forEach(System.out::println);
		 System.out.println("===============");
		 
		 Integer[] intArr = { 1,2,3,4,5 };		 
		 Stream<Integer> intStream2 = Arrays.stream(intArr);
		 System.out.println("Count=" + intStream2.count());
		 
		 int[] intArr2 = { 1,2,3,4,5 };		
		 IntStream intStream3 = Arrays.stream(intArr2); 
		 System.out.println("Count=" + intStream3.average());
         System.out.println("===============");
         
         //중간 연산하기
         IntStream intStream2 = IntStream.rangeClosed(1, 10);
		 intStream2.skip(3).limit(5).forEach(System.out::print);
		 System.out.println();
		 
		 IntStream intStream3 = IntStream.rangeClosed(1, 10);
		 intStream3.filter( i->i%2 == 0 && i%3!=0 ).forEach(System.out::print);
		 System.out.println();
         System.out.println("===============");

         File[] fileArr = { new File("Ex1.java"), new File("Ex1.bak") };
		 Stream<File> fileStream = Stream.of(fileArr);

		 // map()으로 Stream<File>을 Stream<String>으로 변환
		 Stream<String> filenameStream = fileStream.map(File::getName);
		 filenameStream.forEach(System.out::println); // 모든 파일의 이름을 출력 
		 fileStream = Stream.of(fileArr);  // 스트림을 다시 생성

		 fileStream.map(File::getName)     // Stream<File> → Stream<String>
			  .filter(s -> s.indexOf('.')!=-1)   // 확장자가 없는 것은 제외
			  .map(s -> s.substring(s.indexOf('.')+1)) // 확장자만 추출
              .peek(s->System.out.printf("filename=%s%n" , s)) //중간 디버깅
			  .map(String::toUpperCase)     // 모두 대문자로 변환
			  .distinct()                   //  중복 제거
			  .forEach(System.out::print);  // JAVABAKTXT	

       // 문자열 배열을 하나의 스트림으로 합치고 싶다.
		Stream<String[]> strArrStrm = Stream.of(
			new String[]{"abc", "def", "jkl"},
			new String[]{"ABC", "GHI", "JKL"}
		);
		
		Stream<Stream<String>> strStrmStrm = strArrStrm.map(Arrays::stream);
		strStrmStrm.forEach(System.out::println);
		System.out.println();
		
		Stream<String[]> strArrStrm2 = Stream.of(
				new String[]{"abc", "def", "jkl"},
				new String[]{"ABC", "GHI", "JKL"}
			);

		Stream<String> strStrm = strArrStrm2.flatMap(Arrays::stream);
		strStrm.map(String::toLowerCase)
			.distinct()
			.sorted()
			.forEach(System.out::println);
			System.out.println();
		
		// 단어 하나하나를 스트림의 요소로 만들고 싶다
		String[] lineArr = {
			"Believe or not It is true",
			"Do or do not There is no try",
		};

		Stream<String> lineStream = Arrays.stream(lineArr);
		lineStream.flatMap(line -> Stream.of(line.split(" +"))) //하나 이상의 공백
			.map(String::toLowerCase)
			.distinct()
			.sorted()
			.forEach(System.out::println);
	}
} 
 

 

import java.util.*;
import java.util.stream.*;
class Ex14_5 {
	public static void main(String[] args) {
		Stream<Student> studentStream = Stream.of(
						new Student("이자바", 3, 300),
						new Student("김자바", 1, 200),
						new Student("안자바", 2, 100),
					);

		studentStream.sorted(Comparator.comparing(Student::getBan) // 반별 정렬
		 	.thenComparing(Comparator.naturalOrder()))     	// 기본 정렬
			.forEach(System.out::println);
	}
}

class Student implements Comparable<Student> {
	String name;
	int ban;
	int totalScore;
	
	Student(String name, int ban, int totalScore) { 
		this.name =name;
		this.ban =ban;
		this.totalScore =totalScore;
	}

	public String toString() { 
	   return String.format("[%s, %d, %d]", name, ban, totalScore); 
	}

	String getName()     { return name;}
	int getBan()         { return ban;}
	int getTotalScore()  { return totalScore;}

   // 총점 내림차순을 기본 정렬로 한다.
	public int compareTo(Student s) { 
		return s.totalScore - this.totalScore;
	}	
}
 

 

 

★ reduce() :: identity 초기값 , accumulator 수행할 연산 , 
               conbiner 병렬처리된 결과 합칠때 사용할 연산

import java.util.*;
import java.util.stream.*;
class Ex14_9 {
	public static void main(String[] args) {
		String[] strArr = {
			"Inheritance", "Java", "Lambda", "stream",
			"OptionalDouble", "IntStream", "count", "sum"
		};

		Stream.of(strArr)
		.parallel() 						 // 병렬 처리
		.forEachOrdered(System.out::printf); // 순서 유지
		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); //true
		System.out.println("sWord="+ sWord.get());    //stream

		// Stream<String>을 Stream<Intteger>으로 변환
		// Stream<Integer> intStream1 = Stream.of(strArr).map(String::length);
		
		// Stream<String>을 IntStream으로 변환, 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.getAsInt());
		System.out.println("min="+ min.getAsInt());
	}
}
 

 

★ collect() : 최종연산  
   - Collector는 수집(collect)에 필요한 메서드를 정의해 놓은 인터페이스
   - Collectors 클래스는 다양한 기능의 컬렉터를 제공한다.
      변환 : mapping() , toList() , toMap() , toCollection() ...
      통계 : counting() , summingInt() , averagingInt() , maxBy() ,
             minBy() , summarizingInt() , comparingInt()
      문자열 결합 : joining();
      리듀싱 : reducing(); :: 그룹별로 reduce() 하는 방법
      그룹화와 분할 : groupingBy() :: n분할, partitioningBy() :: 2분할 ,
                      collectiongAndThen()

   - 스트림을 컬렉션으로 변환하기
    1. Stream<String> -> List<String>
       List<String> name = aa.map(Student::getName)
           .collect( Collectors.toList() ); 

    2. Stream<String> -> ArrayList<String>
       ArrayList<String> list = name.stream()
           .collect( Collectors.toCollection(ArrayList::new) ); 
   
   3. Stream<Person> -> Map<String , Person>
       Map<String , Preson> map = personStream
           .collect( Collectors.toMap(p->p.getRegId() , p->p) ); // 항등함수(입력>출력)

   - 스트림을 배열로 변환하기
       Student[] aa = studentStream.toArray(Student[]::new);
       Student[] aa = studentStream.toArray(); :: 에러
       Object[] aa = studentStream.toArray();
 
 
 
//Map<Boolean, List<Student2>> :: 입력boolean , 출력List<Student2>

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

class Student3 {
	String name;
	boolean isMale; // 성별
	int hak;        // 학년
	int ban;        // 반
	int score;

	Student3(String name, boolean isMale, int hak, int ban, int score) { 
		this.name	= name;
		this.isMale	= isMale;
		this.hak   	= hak;
		this.ban	= ban;
		this.score 	= score;
	}

	String	getName() 	 { return name;    }
	boolean isMale()  	 { return isMale;  }
	int		getHak()   	 { return hak;	   }
	int		getBan()  	 { return ban;	   }
	int		getScore()	 { return score;   }

	public String toString() {
		return String.format("[%s, %s, %d학년 %d반, %3d점]", name, isMale ? "남" : "여", hak, ban, score);
	}

	enum Level {
		HIGH, MID, LOW
	}
}

class Ex14_11 {
	public static void main(String[] args) {
		Student3[] stuArr = {
			new Student3("나자바", true,  1, 1, 300),	
			new Student3("김지미", false, 1, 1, 250),	
			new Student3("김자바", true,  1, 1, 200),	
			new Student3("이지미", false, 1, 2, 150),	
			new Student3("남자바", true,  1, 2, 100),	
			new Student3("안지미", false, 1, 2,  50),	
			new Student3("황지미", false, 1, 3, 100),	
			new Student3("강지미", false, 1, 3, 150),	
			new Student3("이자바", true,  1, 3, 200),	
			new Student3("나자바", true,  2, 1, 300),	
			new Student3("김지미", false, 2, 1, 250),	
			new Student3("김자바", true,  2, 1, 200),	
			new Student3("이지미", false, 2, 2, 150),	
			new Student3("남자바", true,  2, 2, 100),	
			new Student3("안지미", false, 2, 2,  50),	
			new Student3("황지미", false, 2, 3, 100),	
			new Student3("강지미", false, 2, 3, 150),	
			new Student3("이자바", true,  2, 3, 200)	
		};

		System.out.printf("1. 단순그룹화(반별로 그룹화)%n");
		Map<Integer, List<Student3>> stuByBan = Stream.of(stuArr)
				.collect(groupingBy(Student3::getBan));

		for(List<Student3> ban : stuByBan.values()) {
			for(Student3 s : ban) {
				System.out.println(s);
			}
		}

		System.out.printf("%n2. 단순그룹화(성적별로 그룹화)%n");
		Map<Student3.Level, List<Student3>> stuByLevel = Stream.of(stuArr)
				.collect(groupingBy(s-> {
						 if(s.getScore() >= 200) return Student3.Level.HIGH;
					else if(s.getScore() >= 100) return Student3.Level.MID;
					else                         return Student3.Level.LOW;
				}));

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

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

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

		System.out.printf("%n3. 단순그룹화 + 통계(성적별 학생수)%n");
		Map<Student3.Level, Long> stuCntByLevel = Stream.of(stuArr)
				.collect(groupingBy(s-> {
					     if(s.getScore() >= 200) return Student3.Level.HIGH;
					else if(s.getScore() >= 100) return Student3.Level.MID;
					else                         return Student3.Level.LOW;
				}, counting()));
		for(Student3.Level key : stuCntByLevel.keySet())
			System.out.printf("[%s] - %d명, ", key, stuCntByLevel.get(key));
		System.out.println();
/*
		for(List<Student3> level : stuByLevel.values()) {
			System.out.println();
			for(Student3 s : level) {
				System.out.println(s);
			}
		}
*/
		System.out.printf("%n4. 다중그룹화(학년별, 반별)");
		Map<Integer, Map<Integer, List<Student3>>> stuByHakAndBan =
          Stream.of(stuArr)
				.collect(groupingBy(Student3::getHak,
						 groupingBy(Student3::getBan)
				));

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

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

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

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

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

		for(String key : keySet2) {
			System.out.println("["+key+"]" + stuByScoreGroup.get(key));
		}
	}  // main의 끝
}
 

 

 

728x90
댓글수0