Language/Java

Stream, Optional & Lambda

do-oni 2021. 8. 17. 20:25

08.16 TIL

 

Stream

Java SE 8 부터 추가 된 함수형 프로그래밍으로
컬렉션, 배열등의 저장 요소를 하나씩 참조하여 람다식을 적용해 반복적으로 처리할 수 있게 해줌
데이터를 추상화 하여 다룸

 

< Stream >

• 데이터의 흐름

• 데이터를 변경하지 않고 읽기만 함
• 한번 사용하면 재사용 불가, 일회성
• 작업을 내부 반복으로 처리
• 다양한 자료구조 인스턴스를 여러개 결합하여 결과 도출 가능
• lambda와 병행 사용하여 코드를 간결화
• 다중 thread를 이용한 병렬 처리 지원 (Parallel processing)

 

Java Platform SE 8

 

docs.oracle.com

• 스트림 연산 단계

- 스트림 생성 : 스트림 인스턴스 생성
› stream(), Stream.builder(), Stream.generate(), Stream.iterate()

- 중간 연산 (스트림 변환, 가공) : 필터링(filtering), 맵핑(mapping) 등 원하는 결과를 만들어 가는 중간 작업
› map(), filter(), sorted(), limit(), peek(), distinct()

- 최종 연산 (스트림 사용, 결과) : 최종 결과를 만드는 작업
› min(), max(), sum(), count(), average(), reduce(), collect()
import java.util.Arrays;
import java.util.List;

import org.junit.jupiter.api.Test;

public class Step01StreamAPI {
	@Test
	public void m1() {
		List<Integer> list = new ArrayList<>();
		list.add(1);
		list.add(2);
		list.add(3);
		list.add(4);
		list.add(5);
		
		/* asList() : 가변인자 즉 parameter수 제한없이 호출해서 데이터 구성 가능, List 객체로 반환
		 */
		List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
		list.stream().forEach(System.out::println);
    		list.forEach(data -> System.out.println(data + "\t"));  //1 2   3   4   5
    		list.forEach(System.out::print);  			//12345
		
		//? 3이상인 데이터만 출력(조건식 = 필터링)
		//filter()는 stream()의 반환값 객체에서 호출 가능
		list.stream().filter(v -> v >= 3).forEach(System.out::print);   //345
		
		
		System.out.println("\n---1---");
		list.stream().filter(v -> v > 3).forEach(System.out::println);
		
		System.out.println("---2---");
		list.stream().filter(v -> v > 2).forEach(System.out::println);
		
		//matToInt() : 문자(객체타입)를 숫자로 변환해주는 메소드
		System.out.println("---3---");
		int r1 = list.stream().filter(v -> v > 2).mapToInt(i -> i).sum();
		System.out.println(r1);
        
        	System.out.println("---4---");
		r1 = list.stream().filter(v -> v > 2).sum();  //문법 오류
		System.out.println(r1);

 

< Optional >

null이나 null이 아닌 값을 담을 수 있는 래퍼 클래스 (Wrapper class)
• NullPointerException(NPE) 을 예방 할 수 있음
 

Java Platform SE 8

 

docs.oracle.com

/*
	 * Optional 객체 생성 방법 +
	 * - ofNullable() : null 또는 객체로 생성
	 * - isPresent() : Optional 내부에 객체가 존재할 경우 true/null 즉 Optional.empty인 경우 false
	 */
	@Test
	public void m2() {
		String s1 = null;
		Optional<String> opt = Optional.ofNullable(s1);  //null 또는 객체 다 parameter로 적용 가능
		System.out.println(opt);  //Optional[playdata]
		
		System.out.println("====");
		
		s1 = "playdata";
		Optional<String> opt2 = Optional.ofNullable(s1);
		System.out.println(opt2);
		
		System.out.println(opt2.isPresent());  //true 데이터가 존재할 경우 true/ null인 경우는 false
		System.out.println(opt.isPresent());  //true 데이터가 존재할 경우 true/ null인 경우는 false
		
		if(opt2.isPresent()) {
			System.out.println("null이 아니에요");
		}else {
			System.out.println("null 입니다");
		}
	}
	
	@Test
	public void m3() {
		String s1 = "playdata";
		Optional<String> opt = Optional.ofNullable(s1);  //null 또는 객체로 생성
		
		String s2 = null;
		Optional<String> opt2 = Optional.ofNullable(s2);
		
		//playdata라는 문자열 객체를 보유한 Optional 객체로 문자열 같이 출력
		opt.ifPresent(data -> {
			System.out.println(data.length());  //8
			});
		
		opt.ifPresent(data -> System.out.println(data.length()));  //8
		
		//null로 만들어진 Optional 객체 따라서 ifPresent() 로직에서 필터링 즉 실행 자체가 안되기 때문에 람다식 무시
		opt2.ifPresent(data -> {
			System.out.println(data.length());
		});
	}

 

 

Lambda(람다)식

메소드를 하나의 식으로 표현한 것
메소드의 이름이 필요하지 않기 때문에 익명 함수 (Anonymous function) 라고 함
객체 지향 언어인 Java를 함수 지향 프로그래밍 가능하게 해줌

 

• 람다식 내에서 사용되는 지역변수는 final이 붙지 않아도 상수로 간주
• 람다식으로 선언된 변수명은 다른 변수명과 중복 불가
• 장점
- 코드의 간결화
- 가독성이 좋음
- 함수를 만드는 과정이 없어 생산성이 좋음
- 병렬 프로그래밍 용이

• 단점
- 재사용 불가
- 디버깅이 어려움
- 비슷한 함수가 중복 생성되어 코드가 지저분해질 수 있음
- 재귀에 부적합
public class Step02Lambda {
	@Test
	public void m1() {
		AddFunction addR = (no1,no2) -> no1 + no2;
		System.out.println(addR.sum(1, 2));
		
		addR = (no1,no2) -> no1 - no2;
		System.out.println(addR.sum(1, 2));
		
		MessageFunction msg = () -> "A";
		System.out.println(msg.message());
		
		MessageFunction2 mess = () -> System.out.println("A");
		mess.message();
	}
	
	@Test
	public void m2() {
		Map<String, String> map = new HashMap<>();
		map.put("1", "A");
		map.put("2", "B");
		map.put("3", "C");
		map.put("4", "D");
		map.put("5", "E");
		map.put("6", "F");
		
		System.out.println("--- 1. class");
		for(Map.Entry<String, String> entry :map.entrySet() ) {
			System.out.println(entry.getKey() + " :  " + entry.getValue());
		}
		
		System.out.println(" -- 2. java 8, forEach & lambda --");
		map.forEach((k,v) ->  System.out.println( k+ " : " +v ));
		
		
		System.out.println("--- 3. class");
		for(Map.Entry<String, String> entry :map.entrySet() ) {
			if(entry.getValue().equals("A")) {
				System.out.println(entry.getKey() + " :  " + entry.getValue());
			}
		}
		
		System.out.println(" -- 4. java 8, forEach & lambda --");
		map.forEach((k,v) ->  System.out.println( k+ " : " +v ));
		map.entrySet().stream().filter(entry -> entry.getValue().equals("A")).forEach(data -> System.out.println(data.getKey() + " : " + data.getValue()));
		
		System.out.println(" -- 5. 이해를 위한 코드 --");
		List<Integer> l1 = Arrays.asList(1,2,3,4,5);
		l1.stream().filter(v -> v == 2 ).forEach(System.out::println);
		l1.stream().filter(v -> v == 2 ).forEach(x -> System.out.println(x));
	}
	
	
}