나를 기록하다
article thumbnail
Published 2023. 10. 11. 23:34
[Java] 익명클래스, 람다와 스트림 Java
반응형

자바

익명 클래스

  • 이름이 없는 클래스
  • 내부 클래스 중 특별한 클래스
  • 1회성 코드. 해당 객체 하나만을 위한 클래스

[예시] 카페에서 커피 주문. 특별한 손님을 위한 익명 클래스

public class Main {
	public static void main(String[] args) {
		//익명 클래스
		Coffee c1 = new Coffee();
		c1.order("아메리카노");
		System.out.println("------------------------");

		Coffee c2 = new Coffee();
		c2.order("카페라떼");
		System.out.println("------------------------");

		//굉장히 친한 친구 방문
		Coffee specialCoffee = new Coffee() {
			@Override
			public void order(String coffee) {
				super.order(coffee);
				System.out.println("(귓속말) 딸기 케이크는 서비스^_^");
			}

			@Override
			public void returnTray() {
				System.out.println("(귓속말) 자리에 두시면 제가 치울게요!!");
			}
		};
		specialCoffee.order("바닐라 라떼");
		specialCoffee.returnTray();
		System.out.println("------------------------");

	}
}

class Coffee {
	public void order(String coffee) {
		System.out.println("주문하신 " + coffee + " 나왔습니다.");
	}

	public void returnTray() {
		System.out.println("커피 반납이 완료되었습니다.");
	}
}

결과

주문하신 아메리카노 나왔습니다.
------------------------
주문하신 카페라떼 나왔습니다.
------------------------
주문하신 바닐라 라떼 나왔습니다.
(귓속말) 딸기 케이크는 서비스^_^
(귓속말) 자리에 두시면 제가 치울게요!!

[예시] 집에서 만드는 수제버거

  • 집마다 레시피가 다름
  • 객체를 상속하여 하는 것이 아닌 그때마다 새로운 익명 클래스 객체를 생성하여 반환
public class Main {
	public static void main(String[] args) {
		HomeMadeBurger momMadeBurger = getMomMadeBurger();
		momMadeBurger.cook();
		System.out.println("---------------------------------------------------------");

		HomeMadeBurger broMadeBurger = getBroMadeBurger();
		broMadeBurger.cook();
		System.out.println("---------------------------------------------------------");

	}

	private static HomeMadeBurger getBroMadeBurger() {
		return new HomeMadeBurger() {
			@Override
			public void cook() {
				System.out.println("집에서 만드는 동생표 군대리아");
				System.out.println("재료 : 빵, 치킨패티, 양배추 샐러드, 딸기잼, 치즈, 계란");
			}
		};
	}

	public static HomeMadeBurger getMomMadeBurger() {
		return new HomeMadeBurger() {
			@Override
			public void cook() {
				System.out.println("집에서 만드는 엄마표 수제버거");
				System.out.println("재료 : 빵, 소고기패티, 해시브라운, 양상추, 마요네즈, 피클");
			}
		};
	}
}

abstract class HomeMadeBurger {
	public abstract void cook();
}

람다식

  • 간결한 형식의 코드 뭉치
  • 접근제어자(public 등), 이름 필요 없음
  • 자동으로 return type 결정 -> void 필요 없음

[예시]

	public void print() {
		String s = "test";
		System.out.println(s);
	}
    
    --------------------------------------------------
    
	() -> {
		String s = "test";
		System.out.println(s);
	}

  • 문장이 하나일 때는 중괄호, 세미콜론 생략 가능
  • 전달되는 값의 형태는 컴파일러가 알 수 있기에 생략 가능
  • 전달되는 값이 하나일 때는 괄호 생략 가능

[예시]

    public void print(String s) {
        System.out.println(s);
    }
    
------------------------------------------------------------
	
    s -> System.out.println(s)

  • return이 포함되는 경우는 중괄호 생략 불가
  • 하지만 람다식에서는 return을 생략하면 자동으로 연산된 결과를 return 해준다.
  • return을 지우면 중괄호와 세미콜론 생략 가능
    public int add(int x, int y) {
        return x + y;
    }
    
    ------------------------------------------------------

    (x, y) -> x + y

함수형 인터페이스

[예시] 달러를 입력 시 우리 돈으로 얼마인지 변환해주는 프로그램

람다식 사용 전

Convertible 인터페이스

package converter;

public interface Convertible {
	void convert(int USD);
}

KRWConverter - 달러 -> 원화 변환

package converter;

public class KRWConverter implements Convertible {
	@Override
	public void convert(int USD) {
		//1달러 = 1340원
		System.out.println(USD + "달러 = " + (USD) * 1340 + "원");
	}
}

Main

public class Main {
	public static void main(String[] args) {
		KRWConverter converter = new KRWConverter();
		// converter.convert(2);
		convertUSD(converter, 2);
	}

	public static void convertUSD(Convertible converter, int USD) {
		converter.convert(USD);
	}
}
람다식 사용
public class Main {
	public static void main(String[] args) {
		KRWConverter converter = new KRWConverter();
		// converter.convert(2);
		convertUSD((USD) -> System.out.println(USD + "달러 = " + (USD) * 1340 + "원"), 2);
	}

	public static void convertUSD(Convertible converter, int USD) {
		converter.convert(USD);
	}
}
2달러 = 2680원
  • 변수를 메서드처럼 전달
public class Main {
	public static void main(String[] args) {
		KRWConverter converter = new KRWConverter();
		// converter.convert(2);
		Convertible convertible = (USD) -> System.out.println(USD + "달러 = " + (USD) * 1340 + "원");
		convertUSD(convertible, 1);
	}

	public static void convertUSD(Convertible converter, int USD) {
		converter.convert(USD);
	}
}

위와 같은 인터페이스를 함수형 인터페이스라고 부른다.

  • 함수는 메서드와 똑같다고 볼 수 있지만, 클래스 내에서 기능을 정의하는 것이 메서드, 클래스 밖에서 기능을 정의하는 것이 함수이다.
  • 함수형 인터페이스를 이용하기 위해서는 인터페이스에는 단 하나의 추상 메서드가 존재해야 한다는 조건이 존재
  • 하나 이상이 존재하면 어떤 메서드가 람다식과 연결되는지 알 수 없기 때문
  • 함수형 인터페이스를 구별하기 위해 @FunctionalInterface 어노테이션을 작성

 

전달값이 없는 함수형 인터페이스
package converter;

@FunctionalInterface
public interface ConvertibleWithNoParams {
	void convert();
}
public class Main {
	public static void main(String[] args) {
		//전달값이 하나도 없다면?
		ConvertibleWithNoParams c1 = () -> System.out.println("1달러 = 1340원");
		c1.convert();
	}
}
1달러 = 1340원

 

두 줄 이상의 코드
public class Main {
	public static void main(String[] args) {
		//전달값이 하나도 없다면?
		ConvertibleWithNoParams c1 = () -> System.out.println("1달러 = 1340원");
		c1.convert();

		//두 줄 이상의 코드가 있다면?
		c1 = () -> {
			int USD = 5;
			int KRW = 1340;
			System.out.println(USD + "달러 = " + USD * KRW + "원");
		};
		c1.convert();
	}
}
5달러 = 6700원

 

전달값이 2개인 경우
package converter;

@FunctionalInterface
public interface ConvertibleWithTwoParams {
	void convert(int USD, int KRW);
}
public class Main {
	public static void main(String[] args) {
		//전달값이 2개인 경우
		ConvertibleWithTwoParams c2 = (D, W) -> System.out.println(D + "달러 = " + D * W + "원");
		c2.convert(10, 1340);
	}
}
10달러 = 13400원

 

반환값이 있는 경우
package converter;

@FunctionalInterface
public interface ConvertibleWithReturn {
	int convert(int USD, int KRW);
}
public class Main {
	public static void main(String[] args) {
		//반환값이 있는 경우
		ConvertibleWithReturn c3 = (D, W) -> D * W;
		int result = c3.convert(20, 1340);
		System.out.println("20달러 = " + result + "원");
	}
}
20달러 = 26800원

스트림

  • 데이터가 흐른다를 뜻한다.
  • 자바에서 스트림을 이용하게 되면 많은 데이터에서 원하는 조건에 따라 필터링을 하여 데이터를 걸러내거나 필요한 데이터만 꺼내올 수 있음
스트림 생성
  1. Arrays.stream()
  2. Collections.stream()
  3. Stream.of()
public class Main {
	public static void main(String[] args) {
		// 스트림 생성

		//Arrays.stream()
		int[] scores = {100, 95, 90, 85, 80};
		IntStream scoreStream = Arrays.stream(scores);

		String[] langs = {"python", "java", "javascript", "c", "c++", "c#"};
		Stream<String> langStream = Arrays.stream(langs);

		//Collections.stream()
		List<String> langList = new ArrayList<>();
		langList = Arrays.asList("python", "java", "javascript", "c", "c++", "c#");
		System.out.println(langList.size()); //6
		Stream<String> langListStream = langList.stream();

		//Stream.of()
		Stream<String> langListOfStream = Stream.of("python", "java", "javascript", "c", "c++", "c#");
	}
}

 

스트림 사용
  1. 중간 연산(Intermediate Operation) : filter, map, sorted, distinct, skip, ...
  2. 최종 연산(Terminal Operation) : count, min, max, sum, forEach, anyMatch, allMatch, ...
  3. 스트림은 필터링 매핑을 통해 안에 있는 데이터를 소진한다 -> 한번 쓰고난 스트림은 재사용 불가
  4. System.out.println(x) 대신 System.out::println의 형식으로 사용 가능(클래스명과 메서드명을 ::으로 구분)

 

정수 스트림
  • forEach(): 출력
  • sorted(): 오름차순 정렬
  • count(): 개수 출력(반환값 long 타입)
  • sum(): 합계 출력(반환값 int 타입)
public class Main {
	public static void main(String[] args) {
		// 스트림 생성

		//Arrays.stream()
		int[] scores = {100, 95, 90, 85, 80};
		IntStream scoreStream = Arrays.stream(scores);

		//스트림 사용
		//중간 연산(Intermediate Operation) : filter, map, sorted, distinct, skip, ...
		//최종 연산(Terminal Operation) : count, min, max, sum, forEach, anyMatch, allMatch, ...

		//90점 이상인 점수만 출력
		Arrays.stream(scores).filter(x -> x >= 90).forEach(x -> System.out.println(x));
		System.out.println("---------------------------------------------");
		Arrays.stream(scores).filter(x -> x >= 90).forEach(System.out::println);
		System.out.println("---------------------------------------------");

		//90점 이상인 사람의 수
		long count = Arrays.stream(scores).filter(x -> x >= 90).count();
		System.out.println(count);
		System.out.println("---------------------------------------------");

		//90점 이상인 점수들의 합
		int sum = Arrays.stream(scores).filter(x -> x >= 90).sum();
		System.out.println(sum);
		System.out.println("---------------------------------------------");

		//90점 이상인 점수들을 정렬
		Arrays.stream(scores).filter(x -> x >= 90).sorted().forEach(System.out::println);
		System.out.println("---------------------------------------------");
	}
}

 

문자열 스트림
  • startWith(): 첫문자 확인
  • contains(): 포함 여부 확인
  • anyMatch(): 일치하는 게 하나라도 있는지 확인
  • allMatch(): 모두 일치하는지 확인
public class Main {
	public static void main(String[] args) {
		// 스트림 생성

		//Arrays.stream()
		String[] langs = {"python", "java", "javascript", "c", "c++", "c#"};
		Stream<String> langStream = Arrays.stream(langs);

		//Collections.stream()
		List<String> langList = new ArrayList<>();
		langList = Arrays.asList("python", "java", "javascript", "c", "c++", "c#");
		Stream<String> langListStream = langList.stream();

		//스트림 사용
		//중간 연산(Intermediate Operation) : filter, map, sorted, distinct, skip, ...
		//최종 연산(Terminal Operation) : count, min, max, sum, forEach, anyMatch, allMatch, ...

		//"python", "java", "javascript", "c", "c++", "c#"
		//c로 시작하는 프로그래밍 언어
		Arrays.stream(langs).filter(x -> x.startsWith("c")).forEach(System.out::println);
		System.out.println("---------------------------------------------");

		//java라는 글자를 포함하는 언어
		Arrays.stream(langs).filter(x -> x.contains("java")).forEach(System.out::println);
		System.out.println("---------------------------------------------");

		//글자 길이가 4 이하인 언어
		langList.stream().filter(x -> x.length() <= 4).sorted().forEach(System.out::println);
		System.out.println("---------------------------------------------");

		//4글자 이하의 언어 중에서 c라는 글자를 포함하는 언어
		langList.stream()
			.filter(x -> x.length() <= 4)
			.filter(x -> x.contains("c"))
			.sorted()
			.forEach(System.out::println);
		System.out.println("---------------------------------------------");

		//4글자 이하의 언어 중에서 c라는 글자를 포함하는 언어가 있는지를 확인
		boolean anyMatch = langList.stream()
			.filter(x -> x.length() <= 4)
			.anyMatch(x -> x.contains("c"));
		System.out.println(anyMatch);
		System.out.println("---------------------------------------------");

		//3글자 이하의 언어들은 모두 c라는 글자를 포함하는지 확인
		boolean allMatch = langList.stream()
			.filter(x -> x.length() <= 3)
			.allMatch(x -> x.contains("c"));
		System.out.println(allMatch);
		System.out.println("---------------------------------------------");
	}
}

 

map
  • 우리가 사용하는 데이터를 원하는 형태로 가공하거나 객체 중에서 꺼내고 싶은 인스턴스 변수를 지정해주는 역할
public class Main {
	public static void main(String[] args) {
		// 스트림 생성

		//Collections.stream()
		List<String> langList = new ArrayList<>();
		langList = Arrays.asList("python", "java", "javascript", "c", "c++", "c#");
		Stream<String> langListStream = langList.stream();

		//스트림 사용
		//중간 연산(Intermediate Operation) : filter, map, sorted, distinct, skip, ...
		//최종 연산(Terminal Operation) : count, min, max, sum, forEach, anyMatch, allMatch, ...

		//4글자 이하의 언어들 중에서 c라는 글자를 포함하는 언어 뒤에 (어려움) 라는 글자를 함께 출력
		//map
		langList.stream()
			.filter(x -> x.length() <= 4)
			.filter(x -> x.contains("c"))
			.map(x -> x + "(어려움)")
			.forEach(System.out::println);
		System.out.println("---------------------------------------------");

		//c라는 글자를 포함하는 언어를 대문자로 출력
		langList.stream()
			.filter(x -> x.contains("c"))
			.map(String::toUpperCase)
			.forEach(System.out::println);
		System.out.println("---------------------------------------------");

		//c라는 글자를 포함하는 언어를 대문자로 변경하여 리스트로 저장
		List<String> langListStartsWithC = langList.stream()
			.filter(x -> x.contains("c"))
			.map(String::toUpperCase)
			.collect(Collectors.toList());

		langListStartsWithC.stream().forEach(System.out::println);
		System.out.println("---------------------------------------------");
	}
}

참고자료

https://www.inflearn.com/course/%EB%82%98%EB%8F%84%EC%BD%94%EB%94%A9-%EC%9E%90%EB%B0%94-%EA%B8%B0%EB%B3%B8/dashboard

 

나도코딩의 자바 기본편 - 풀코스 (20시간) - 인프런 | 강의

배움의 즐거움을 알게 해주는 강의. 나도코딩의 자바 기본편을 소개합니다., 빠르고 효율적이면서퀴즈까지 풀 수 있는 자바 강의가 있다? 😮 '너무 재밌어요.가르쳐주시는 짧은 주제마다 응용

www.inflearn.com

반응형
profile

나를 기록하다

@prao

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

profile on loading

Loading...