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
- bit manipulation
- 자바
- geometry
- 파이썬
- dynamic programming
- 구현
- array
- simulation
- 코테
- SQL
- Class
- Math
- Tree
- Counting
- Matrix
- Stack
- implement
- java
- sorting
- Data Structure
- Method
- database
- string
- Number Theory
- two pointers
- 코딩테스트
- Binary Search
- greedy
- Binary Tree
- hash table
Archives
- Today
- Total
코린이의 소소한 공부노트
function 패키지와 메서드 본문
[java.util.function 패키지]
- 자주 사용되는 다양한 함수형 인터페이스를 제공하는 패키지
1. 기본 함수형 인터페이스
- 함수는 반환값이 0개 또는 1개이다.
// 1) java.lang.Runnable 인터페이스
void run() // 매개변수X, 반환값X
// 2) Supplier<T> 인터페이스
T get() // 매개변수X, 반환값 1개
// 3) Consumer<T> 인터페이스
void accept(T t) // 매개변수 1개, 반환값X -> Supplier와 반대
// 4) Function<T,R> 인터페이스
R apply(T t) // 매개변수 1개, 반환값 1개 -> 일반적인 함수
// 5) Predicate<T> 인터페이스
boolean test(T t) // 매개변수 1개, 반환값 논리형 -> 조건식을 표현하는 데 사용
// Predicate 사용 예시
Predicate<String> isEmptyStr = s -> s.length()==0; // 매개변수 s, 반환값 논리형인 람다식
// 지네릭 타입이 String이므로 s의 타입도 String이라는 것을 알 수 있다.
// 람다식을 쓸 때 test()를 호출하면 된다.
String s = "";
if(isEmptyStr.test(s)) // if(s.length()==0)와 같음
System.out.println("This is an empty String.");
// 패키지 관련 간단 퀴즈
[ ➀ ] f = ()-> (int)(Math.random()*100)+1;
[ ➁ ] f = i -> System.out.print(i+", ");
[ ➂ ] f = i -> i%2==0;
[ ➃ ] f = i -> i/10*10;
// 정답
➀ Supplier<Integer> // 매개변수X, 반환값 int 1개
➁ Consumer<Integer> // 매개변수 int 1개, 반환값X
➂ Predicate<Integer> // 매개변수 1개, 반환값 논리형
➃ Function<Integer,Integer> // 매개변수 int 1개, 반환값 int 1개
2. 매개변수가 2개인 함수형 인터페이스
- 매개변수가 없고 반환값만 있는 Supplier의 경우, 반환값이 2개일 경우 함수라고 할 수 없기 때문에 BiSupplier는 없다.
// 1) BiConsumer<T,U> 인터페이스
void accept(T t, U u) // 매개변수 2개, 반환값X
// 2) BiPredicate<T,U> 인터페이스
boolean test(T t, U u) // 매개변수 2개, 반환값은 논리형 -> 조건식을 표현하는 데 사용
// 3) BiFunction<T,U,R> 인터페이스
R apply(T t, U u) // 매개변수 2개, 반환값 1개
// 매개변수를 3개를 받아야 한다면 아래처럼 직접 만들면 된다.
@FunctionalInterface
interface TriFunction<T,U,V,R> {
R apply(T t, U u, V v);
}
3. 매개변수의 타입과 반환타입이 일치하는 함수형 인터페이스
// 1) UnaryOperator<T> 인터페이스 – 단항 연산자
T apply(T t) // Function의 자손. Function과 달리 매개변수와 결과의 타입이 같다.
// 2) BinaryOperator<T> 인터페이스 – 이항 연산자
T apply(T t, T t) // BiFunction의 자손. BiFunction과 달리 매개변수와 결과의 타입이 같다.
@FunctionalInterface
public interface Function<T,R> { // 보통의 Function은 매개변수와 반환타입을 함께 표시
R apply(T t);
}
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T,T> { // 단항 연산자는 1개만 표시한다.
static <T> UnaryOperator<T> identity() { // 항등함수
return t -> t;
}
}
4. 예제 코드
import java.util.*;
// main()
Supplier<Integer> s = ()-> (int)(Math.random()*100)+1; // [1, 100] 사이의 난수를 출력
Consumer<Integer> c = i -> System.out.print(i+", "); // 입력 받은 숫자를 출력
Predicate<Integer> p = i -> i%2==0; // 입력 받은 숫자가 짝수인지 확인
Function<Integer, Integer> f = i -> i/10*10; // 입력 받은 숫자의 일의 자리를 0으로 만듦
List<Integer> list = new ArrayList<>();
makeRandomList(s, list);
System.out.println(list); // [95, 75, 21, 87, 29, 94, 19, 6, 68, 72]
printEvenNum(p, c, list); // [94, 6, 68, 72, ] // 짝수만 출력됨
List<Integer> newList = doSomething(f, list);
System.out.println(newList); // [90, 70, 20, 80, 20, 90, 10, 0, 60, 70]
// main()에서 사용한 메서드
// list에 s를 이용해 만든 난수를 저장
static <T> void makeRandomList(Supplier<T> s, List<T> list) {
for(int i=0;i<10;i++) {
list.add(s.get());
}
}
// list에 있는 i에 대하여 p에 대입한 결과(i는 짝수?)가 참이면 c를 이용하여 i를 출력
static <T> void printEvenNum(Predicate<T> p, Consumer<T> c, List<T> list) {
System.out.print("[");
for(T i : list) {
if(p.test(i))
c.accept(i);
}
System.out.println("]");
}
// list와 같은 크기의 새 list를 만들어서 각 요소에 f를 수행한 후 list에 저장 후 반환
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));
}
return newList;
}
[Predicate의 결합]
1. and(), or(), negate()로 두 Predicate를 하나로 결합할 수 있다.
- and()는 &&, or()는 ||, negate()는 !의 역할을 하며, 모두 Predicate 인터페이스의 default 메서드이다.
- 참고: 인터페이스는 default / static / 추상 메서드를 가질 수 있다.
Predicate<Integer> p = i -> i < 100; // i < 100이면 true
Predicate<Integer> q = i -> i < 200; // i < 200이면 true
Predicate<Integer> r = i -> i%2 == 0; // i가 짝수이면 true
Predicate<Integer> notP = p.negate(); // i >= 100이면 true
Predicate<Integer> all = notP.and(q).or(r); // 100 <= i && i < 200 || i%2==0
Predicate<Integer> all2 = notP.and(q.or(r)); // 100 <= i && (i < 200 || i%2==0)
// all과 all2의 순서 유의
System.out.println(all.test(2));
// 100 <= i && i < 200 || i%2==0
// ( false && true ) || true
// false || true
// true
System.out.println(all2.test(2));
// 100 <= i && (i < 200 || i%2==0)
// false && ( true || true )
// false && true
// false
2. 등가비교를 위한 Predicate의 작성에는 isEqual()을 사용한다.
- isEqual()은 Predicate 인터페이스의 static메서드이다.
Predicate<String> p = Predicate.isEqual(str1); // static메서드는 인터페이스이름 필요
boolean result = p.test(str2); // 매개변수로 넘긴 str2가 미리 정해둔 str1과 같은지 비교한 결과를 반환
// 위의 두 줄을 합치면 다음과 같이 쓸 수 있다.
boolean result = Predicate.isEqual(str1).test(str2);
// 위 문장은 다음과 같다.
boolean result = str1.equals(str2);
3. 예제 코드
import java.util.function.*;
Function<String, Integer> f = (s) -> Integer.parseInt(s, 16); // 16진수 문자열 S를 10진수로 변환
Function<Integer, String> g = (i) -> Integer.toBinaryString(i); // 입력을 2진수 문자열로 변환
// f와 g를 이용한 합성함수
Function<String, String> h = f.andThen(g); // f 수행 후 g 수행
Function<Integer, Integer> h2 = f.compose(g); // g 수행 후 f 수행
System.out.println(h.apply("FF")); // "FF" -> f -> 255 -> g -> "11111111"
System.out.println(h2.apply(2)); // 2 -> g -> "10" -> f -> 16
Function<String, String> f2 = x -> x; // 항등 함수(identity function)
System.out.println(f2.apply("AAA")); // "AAA"
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일때 true
Predicate<Integer> all = notP.and(q.or(r));
System.out.println(all.test(150));
// i >= 100 && (i < 200 || i%2 == 0)
// true && ( true || true )
// true && true
// true
String str1 = "abc";
String str2 = "abc";
// str1과 str2가 같은지 비교한 결과를 반환
Predicate<String> p2 = Predicate.isEqual(str1);
boolean result = p2.test(str2);
System.out.println(result); // true
// str1과 str2를 new String("abc")로 선언할 경우에는 주소 비교를 하게 되는데
// equals()를 사용하고 있으므로 결과는 마찬가지로 true가 나온다.
[함수형 인터페이스를 사용하는 컬렉션 프레임워크의 메서드]
- 간단히 설명하기 위해 와일드카드는 생략한 내용이다.
1. Collection 인터페이스
boolean removeIf(Predicate<E> filter)
// 조건에 맞는 요소를 삭제
2. List 인터페이스
void replaceAll(UnaryOperator<E> operator)
// 모든 요소를 변환하여 대체
3. Iterable 인터페이스
void forEach(Consumer<T> action)
// 모든 요소에 작업 action을 수행
4. 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를 수행
5. 예제 코드
ArrayList<Integer> list = new ArrayList<>();
for(int i=0;i<10;i++)
list.add(i);
// list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
// list의 모든 요소를 출력
list.forEach(i->System.out.print(i+",")); // 0,1,2,3,4,5,6,7,8,9,
System.out.println();
// list에서 2 또는 3의 배수를 제거한다.
list.removeIf(x-> x%2==0 || x%3==0);
System.out.println(list); // [1, 5, 7]
// list의 각 요소에 10을 곱한다.
list.replaceAll(i->i*10);
System.out.println(list); // [10, 50, 70]
Map<String, String> map = new HashMap<>();
map.put("1", "1");
map.put("2", "2");
map.put("3", "3");
map.put("4", "4");
// map의 모든 요소를 {k,v}의 형식으로 출력한다.
map.forEach((k,v)-> System.out.print("{"+k+","+v+"},")); // {1,1},{2,2},{3,3},{4,4},
System.out.println();
'Java' 카테고리의 다른 글
스트림의 정의와 특징 (0) | 2023.01.30 |
---|---|
람다식과 메서드 참조 (0) | 2023.01.13 |
함수형 인터페이스의 정의와 활용 (0) | 2022.12.29 |
람다식의 정의와 작성 방법 (0) | 2022.12.28 |
쓰레드의 동기화와 실행제어 (0) | 2022.12.09 |