Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 자바의 정석 기초편 ch7
- 스프링 고급 - 스프링 aop
- 자바의 정석 기초편 ch1
- 스프링 mvc2 - 로그인 처리
- 타임리프 - 기본기능
- 스프링 mvc1 - 서블릿
- 자바의 정석 기초편 ch8
- 스프링 mvc1 - 스프링 mvc
- 스프링 mvc2 - 검증
- 스프링 입문(무료)
- jpa 활용2 - api 개발 고급
- 스프링 db1 - 스프링과 문제 해결
- 자바의 정석 기초편 ch12
- 2024 정보처리기사 수제비 실기
- 자바의 정석 기초편 ch13
- 스프링 mvc2 - 타임리프
- 2024 정보처리기사 시나공 필기
- 자바의 정석 기초편 ch2
- 게시글 목록 api
- 자바의 정석 기초편 ch14
- jpa - 객체지향 쿼리 언어
- 자바의 정석 기초편 ch4
- 스프링 db2 - 데이터 접근 기술
- 코드로 시작하는 자바 첫걸음
- 자바의 정석 기초편 ch6
- 자바의 정석 기초편 ch5
- @Aspect
- 자바의 정석 기초편 ch11
- 자바의 정석 기초편 ch3
- 자바의 정석 기초편 ch9
Archives
- Today
- Total
나구리의 개발공부기록
자바의 정석 기초편 ch14 - 7 ~ 14[java.util.function패키지, Predicate의 결합, CF와 함수형 인터페이스, 메서드 참조, 생성자의 메서드 참조] 본문
유튜브 공부/JAVA의 정석 기초편(유튜브)
자바의 정석 기초편 ch14 - 7 ~ 14[java.util.function패키지, Predicate의 결합, CF와 함수형 인터페이스, 메서드 참조, 생성자의 메서드 참조]
소소한나구리 2023. 12. 20. 12:551) java.util.function패키지
- 자주 사용되는 다양한 함수형 인터페이스를 제공함
- 각 함수형 인터페이스별로 가지고있는 추상메서드가 다르며 반환값, 매개변수가 있는것도있고 없는것도 있음
함수형 인터페이스 | 메서드 |
설 명 | ||
java.lang.Runnable | void run() | 매개변수, 반환값 없음 | ||
Supplier<T> | T get() | -> T | 매개변수 없음, 반환값 있음 | |
Consumer<T> | T -> | void accept(T t) | 매개변수 있음, 반환값 없음(supplier와 반대) | |
Function<T, R> | T -> | R apply(T t) | -> R | 하나의 매개변수를 받아 결과를 반환(일반적인 함수) |
Predicate<T> | T -> | boolean test(T t) | -> boolean | 조건식을 표현, 매개변수는 하나, 반환 타입은 boolean |
(1) Predicate 사용 예시
Predicate<String> isEmptyStr = s -> s.length()==0;
String s = "";
if(isEmptyStr.test(s)) // if(s.length()==0)
System.out.println("This is an empty String.");
(2) 문제
- Supplier <Integer> : 반환값이 있음
- Consumer <Integer> : 매개변수가 있음
- Predicate <Integer> : 매개변수가 있고 반환값은 boolean
- Function <Integer, Integer> : 매개변수,반환값이 있음
(3) 매개변수가 2개인 함수형 인터페이스
- Bi로 시작하는 함수형 인터페이스, (Bi 두개)
함수형 인터페이스 | 메서드 |
설 명 | ||
Biconsumer<T,U> | T,U -> | void accept(T t, U u) | 두개의 매개변수만 있고 반환값 없음 | |
BiPredicate<T,U> | T,U -> | boolean test(T t, U u) | -> boolean | 조건식을 표현, 매개변수 둘, 반환값 boolean |
BiFunction<T,U,R> | T,U -> | R apply(T t, U u) | -> R | 두 개의 매개변수를 받아 하나의 결과를 반환 |
(4) 매개변수가 3개 이상인 함수가 필요한 경우 직접 만들면 됨
- 제네릭스에 타입변수의 개수를 입력하여 추상메서드를 정의하면 됨
(4) 매개변수의 타입과 반환타입이 일치하는 함수형 인터페이스
- 입력값의 개수만 차이가 있고 두 함수형 인터페이스는 입력과 반환타입이 동일함
함수형 인터페이스 | 메서드 |
설 명 | ||
UnaryOperator<T> | T -> | T apply(T t) | -> T | Function의 자손, Function과 달리 매개변수와 결과의 타입 동일 |
BinaryOperator<T> | T, T -> | T apply(T t, T t) | -> T | BiFuction의 자손, BiFuction과 달리 매개변수와 결과 타입이 동일 |
(5) 예제
- 각 함수형 인터페이스의 참조변수로 람다식의 결과를 저장함
- 메서드의 매개변수로 각 참조변수를 입력하여 메서드 각 참조형 인터페이스의 메서드를 사용하여 로직을 구성함
import java.util.function.*;
import java.util.*;
public class Ex14_2 {
public static void main(String[] arags) {
// 1 ~ 100사이의 난수를 반환
Supplier<Integer> s = () -> (int)(Math.random()*100)+1;
// 화면에 i + ", "를 출력
Consumer<Integer> c = i -> System.out.print(i+ ", ");
// 짝수인지 검사 후 True / false로 반환
Predicate<Integer> p = i -> i%2 == 0;
// 1의 자리를 없앰, 1의자리만 있는 수의 경우 0으로 반환
Function<Integer, Integer> f = i -> i/10*10;
List<Integer> list = new ArrayList<>(); // ArrayList생성
// makeRandomList메서드 호출
makeRandomList(s, list);
System.out.println(list);
// printEvenNum메서드 호출
printEvenNum(p, c, list);
// doSomething메서드를 호출 하여 newList에 저장
List<Integer> newList = doSomething(f, list);
System.out.println(newList);
}
// list와 똑같은 크기의 ArrayList를 생성 후 list의 값을 일의자리수를 0으로 변경
static <T> List<T> doSomething(Function<T,T> f, List<T> list){
List<T> newList = new ArrayList<T>(list.size());
for(T i : list) {
newList.add(f.apply(i)); // 일의자리수를 0으로 변경
}
return newList;
}
// 매개변수로 받은 list의 값중 짝수만 ", "와 함께 출력
static <T> void printEvenNum(Predicate<T> p, Consumer<T> c, List<T> list) {
System.out.print("[");
for(T i : list) { // 매개변수로 받은 list의 요소를 하나씩 꺼냄
if(p.test(i)) // 짝수인지 검사 -> true이면 c.accept(i); 실행
c.accept(i); // 화면에 i+", "를 출력
}
System.out.println("]");
}
// list를 랜덤값으로 10개를 채움
static <T> void makeRandomList(Supplier<T> s, List<T> list) {
for(int i=0; i<10; i++ ) {
list.add(s.get());
}
}
}
2) Predicate의 결합
- Predicate 함수형 인터페이스에는 다양한 디폴트 메서드가 정의되어있음
- 디폴트 메서드와 static 메서드로 정의되어있기 때문에 함수형 인터페이스에는 하나의 추상메서드만 있다는 정의에 영향을 주지 않음
- Java8 이후로 인터페이스에 디폴트메서드와 static메서드를 추가할 수 있게 되었음
(1) and() = &&, or() = ||, negate() = !(논리부정)
- 디폴드 메서드로 작성되어있음
- 두개의 Predicate를 하나로 결합하여 최종 연산결과를 반환
- and()는 두개의 연산결과가 모두 true여야만 true
- or()는 둘 중 하나만 true이면 true
- negate()는 람다식의 결과를 반대로 반환
public class PredicateExample {
public static void main(String[] args) {
Predicate<Integer> p = i -> i < 100;
Predicate<Integer> q = i -> i < 200;
Predicate<Integer> r = i -> i % 2 == 0;
Predicate<Integer> notP = p.negate(); // i >= 100
Predicate<Integer> all = notP.and(q.or(r)); // 100 <= i && (i < 200 || i%2==0)
Predicate<Integer> all2 = notP.or(q.or(r)); // 100 <= i || (i < 200 || i%2==0)
System.out.println(all.test(2)); // false
System.out.println(all2.test(2)); // true
}
}
(2) isEqual()
- static 메서드로 작성되어있음
- 등가비교를 위한 Predicate의 작성에는 isEqual()를 사용
import java.util.function.Predicate;
public class PredicateEqualExample {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "World";
// 첫 번째 방법
Predicate<String> p = Predicate.isEqual(str1); // isEqual()은 static메서드
Boolean result = p.test(str2); // str1과 str2가 같은지 비교한 결과를 반환
// 두 번째 방법 (위의 2줄을 1줄로 축약)
boolean result2 = Predicate.isEqual(str1).test(str2);
System.out.println("Result 1: " + result);
System.out.println("Result 2: " + result2);
}
}
(3) 예제
import java.util.function.*;
class Ex14_3 {
public static void main(String[] args) {
// 16진수로 변경
Function<String, Integer> f = (s) -> Integer.parseInt(s, 16);
// 2진수로 변경
Function<Integer, String> g = (i) -> Integer.toBinaryString(i);
// 자바의 정석 3판 : andThen(), compose() - 자바의정석 기초편 ppt에도 설명이 있음
// Function을 하나로 합치는 메서드(처음 함수의 반환타입과 다음 함수의 입력 타입이 같아야 함)
// f.andThen(g); f -> 시작함수, g -> 다음함수
// f(String 시작 Integer 반환) -> g(Integer 시작 String 반환)
Function<String, String> h = f.andThen(g);
// f.compose(g); g -> 시작함수, f -> 다음함수 (andThen의 반대)
// g(Integer 시작 String 반환) -> f(String 시작 Integer 반환)
Function<Integer, Integer> h2 = f.compose(g);
System.out.println(h.apply("FF")); // "FF" -> 16진수(255) -> 2진수("11111111")로 변환
System.out.println(h2.apply(2)); // 숫자2 -> 2진수("10") -> 16진수(16)로 변환
// 항등함수(identity function) -> 입력한 값이 그대로 출력
Function<String, String> f2 = x -> x;
System.out.println(f2.apply("AAA")); // "AAA"가 그대로 출력
// Predicate의 결합
Predicate<Integer> p = i -> i < 100;
Predicate<Integer> q = i -> i < 200;
Predicate<Integer> r = i -> i % 2 == 0;
Predicate<Integer> notp = p.negate(); // i >= 100;
// all = i >= 100 && (i < 200 || i % 2 == 0);
Predicate<Integer> all = notp.and(q.or(r));
System.out.println(all.test(150)); // true
// 등가비교를 위한 Predicate
String str1 = new String("abc");
String str2 = new String("abc");
// isEqual()메서드를 사용하여 str1과 str2가 같은지 비교후 결과를 반환
// Predicate<String> p2 = Predicate.isEqual(str1);
// boolean result = p2.test(str2);
//위 두줄을 한번에 작성
boolean result = Predicate.isEqual(str1).test(str2);
System.out.println(result);
/*
출력값
11111111
16
AAA
true
true
*/
3) 컬렉션 프레임워크와 함수형 인터페이스
- 함수형 인터페이스를 사용하는 컬렉션 프레임워크의 메서드들(와일드 카드는 생략하여 표시)
인터페이스 | 메서드 | 설명 |
Collection | boolean removeIf(Predicate<E> filter) | 조건에 맞는 요소를 삭제 |
List | void replaceAll(UnaryOperator<E> operator) | 모든 요소를 변환하여 대체 |
Iterable | void forEach(Consumer<T> action) | 모든 요소에 작업 action을 수행 |
Map | V compute(K key, BiFunction<K,V,V> f) | 지정된 키의 값에 작업 f를 수행 |
V computeIfAbsent(K key, Function<K,V> f) | 키가 없으면 작업 f를 수행 후 추가 | |
V computeIfPresent(K key, BiFunction<K,V, V> f) | 지정된 키가 있을 때 작업 f를 수행 | |
V merge(K key, V value, BiFunction<V,V,V> f) | 모든 요소에 병합작업 f를 수행 | |
void forEach(Biconsumer<K,V> action) | 모든 요소에 작업 action을 수행 | |
void replaceAll(BiFunction<K,V,V> f) | 모든 요소에 치환작업 f를 수행 |
(1) 예제
import java.util.*;
public class Ex14_4 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
// list의 모든 요소 출력
list.forEach(i -> System.out.print(i + ","));
System.out.println();
// list의 요소 중 2 or 3의 배수를 제거
list.removeIf(x -> x % 2 == 0 || x % 3 == 0);
System.out.println("list = " + list);
// list의 모든 요소에 10을 곱함
list.replaceAll(i -> i * 10);
System.out.println("list = " + list);
Map<String, String> map = new HashMap<>();
map.put("1", "1");
map.put("2", "2");
map.put("3", "3");
map.put("4", "4");
map.forEach((k, v) -> System.out.print("{" + k + " " + v + "},"));
}
}
/*
출력값
0,1,2,3,4,5,6,7,8,9,
list = [1, 5, 7]
list = [10, 50, 70]
{1 1},{2 2},{3 3},{4 4},
*/
3) 메서드 참조
- 클래스이름::메서드이름
- 하나의 메서드만 호출하는 람다식은 메서드 참조로 간단히 표현할 수 있음
종류 | 람다 | 메서드참조 |
static 메서드 참조 | (x) -> ClassName.method(x) | ClassName::method |
인스턴스메서드 참조 | (obj, x) -> obj.method(x) | ClassName::method |
특정 객체 인스턴스메서드 참조(거의안씀) | (x) -> obj.method(x) | obj::method |
(1) static메서드 참조 예시
- 기능이 하나인 메서드를 람다식, 메서드 참조로 변환
// 원본 메서드
Integer method(String s) {
return Integer.parseInt(s);
}
// 람다 표현식으로 변환
Function<String, Integer> f = (String s) -> Integer.parseInt(s);
// 메서드 참조로 최종 변환
Function<String, Integer> f = Integer::parseInt; // 메서드 참조
(2) 생성자와 메서드 참조
- 생성자, 즉 객체를 생성할 때에도 메서드 참조를 사용할 수 있음
- 생성자에 매개변수가 없을 때 = 참조변수의 타입은 Supplier
- 매개변수가 하나 = Function
- 배열 = Function <입력타입, 배열타입>
- 매개변수가 둘 = BiFunction
생성자의 인수 | 객체 생성 예시 | 참조변수 타입 | 메서드참조 변환 |
인수가 없음 | new MyClass() | Supplier<T> | MyClass::new |
인수가 하나일 때 | new MyClass(i) | Function<T> | MyClass::new |
인수가 두개일 때 | new MyClass(i, y) | BiFunction<T, T> | MyClass::new |
배열 생성 시 | new int[x] | Function<입력타입, 배열타입> | int[]::new |
// 기본 생성자를 사용하는 Supplier
Supplier<MyClass> s = MyClass::new; // () -> new MyClass()
// 정수 매개변수를 받는 생성자를 사용하는 Function
Function<Integer, MyClass> f2 = MyClass::new; // (i) -> new MyClass(i)
// 정수를 받아 해당 크기의 int 배열을 생성하는 Function
Function<Integer, int[]> f2 = int[]::new; // x -> new int[x]
(3) 예제
- 람다식을 메서드참조로 변환
public class Ex14_MethodRef {
public static void main(String[] args) {
// 람다식
Function<String, Integer> f = (String s) -> Integer.parseInt(s);
System.out.println(f.apply("100")+200);
// 메서드참조
Function<String, Integer> f1 = Integer::parseInt;
System.out.println(f1.apply("100")+200);
// 기본 생성자 람다식
Supplier<MyClass> s = () -> new MyClass();
System.out.println(s.get());
// 메서드 참조
Supplier<MyClass> s1 = MyClass::new;
System.out.println(s1.get());
// 매개변수가 있는 람다식
Function<Integer, MyClass> f3 = (i) -> new MyClass(i);
System.out.println(f3.apply(100).iv);
// 메서드 참조
Function<Integer, MyClass> f4 = MyClass::new;
System.out.println(f4.apply(100).iv);
// 배열 람다식
Function<Integer, int[]> fArr = (i) -> new int[i];
System.out.println(fArr.apply(100).length); // 길이가 100인 배열의 길이를 출력
// 위 코드를 풀어서 작성
int[] arr = fArr.apply(100);
System.out.println(arr.length);
// 메서드 참조
Function<Integer, int[]> fArr2 = int[]::new;
System.out.println(fArr2.apply(200).length); // 길이가 200인 배열의 길이를 출력
}
}
class MyClass {
int iv;
MyClass() {
}
MyClass(int iv) {
this.iv = iv;
}
}
** 출처 : 남궁성의 정석코딩_자바의정석_기초편 유튜브
'유튜브 공부 > JAVA의 정석 기초편(유튜브)' 카테고리의 다른 글
자바의 정석 기초편 ch14 - 23 ~ 34[스트림의 연산들, 스트림의 중간연산] (1) | 2023.12.21 |
---|---|
자바의 정석 기초편 ch14 - 15 ~ 22[스트림, 스트림의 특징, 스트림 만들기] (1) | 2023.12.20 |
자바의 정석 기초편 ch14 - 1 ~ 6 [람다식이란?, 람다식 작성하기, 함수형 인터페이스] (0) | 2023.12.19 |
자바의 정석 기초편 ch13 - 33 ~ 36 [쓰레드의 동기화, wait(), notify()] (0) | 2023.12.19 |
자바의 정석 기초편 ch13 - 22 ~ 29 [sleep(), interrupt(), suspend(), resume(), stop(),join(),yield()] (1) | 2023.12.18 |