반응형
익명 클래스
- 이름이 없는 클래스
- 내부 클래스 중 특별한 클래스
- 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원
스트림
- 데이터가 흐른다를 뜻한다.
- 자바에서 스트림을 이용하게 되면 많은 데이터에서 원하는 조건에 따라 필터링을 하여 데이터를 걸러내거나 필요한 데이터만 꺼내올 수 있음
스트림 생성
- Arrays.stream()
- Collections.stream()
- 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#");
}
}
스트림 사용
- 중간 연산(Intermediate Operation) : filter, map, sorted, distinct, skip, ...
- 최종 연산(Terminal Operation) : count, min, max, sum, forEach, anyMatch, allMatch, ...
- 스트림은 필터링 매핑을 통해 안에 있는 데이터를 소진한다 -> 한번 쓰고난 스트림은 재사용 불가
- 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("---------------------------------------------");
}
}
참고자료
반응형
'Java' 카테고리의 다른 글
[Java] 클래스 내의 public 변수와 getter 메서드의 대체 방법 (1) | 2023.10.25 |
---|---|
[Java] private 생성자의 사용 이유, final, 자바 메모리 구조 (0) | 2023.10.25 |
[Java] 컬렉션 프레임워크(List, Set, Map, Iterator) (0) | 2023.10.11 |
[Java] 제네릭스(Generics) (0) | 2023.10.11 |
[Java] 람다식(Lambda Expression)과 함수형 인터페이스(Functional Interface) (0) | 2023.09.10 |