Collection Framework API
람다와 스트림 API
함수형 인터페이스
단 하나의 추상메서드를 가진 인터페이스
자바 8부터 함수형 인터페이스를 사용하면 람다 표현식을 활용 할 수 있다.
인터페이스의 구현체를 람다 표현식으로 구현
@FunctionalInterface 어노테이션을 사용하여 표시
어노테이션은 선택 사항이지만 컴파일러에게 해당 인터페이스가 함수형 인터페이스 임을 알려주는 역할을 합니다.
사용하는 이유
- 람다 표현식 지원
- 메서드 참조
- Stream API와의 통합
- 병렬 프로그래밍
- 코드 재사용
인터페이스는 new를 사용하여 객체 생성을 할 수 없기 때문에 익명 클래스를 사용하여 구현체 구현
package fc.java.model2; @FunctionalInterface // 함수형 인터페이스 public interface MathOperation { public int operation(int x, int y); // 추상 메서드 } public class FunctionInterfaceTest2 { public static void main(String[] args) { // MathOperation 인터페이스를 내부 익명 내부 클래스로 구현해보자 MathOperation mo = new MathOperation() { // 익명 내부 클래스 @Override public int operation(int x, int y) { return x + y; } }; int result = mo.operation(10, 20); System.out.println(result); } }
함수형 인터페이스 메서드 참조
이미 정의된 메서드를 직접 참조하여 람다 표현식을 더욱 간결하게 만들 수 있다.
메서드 참조는 기존 메서드를 재사용하고 코드 중복을 줄이는데 도움이 된다.
메서드 참조는 다음 네가지 유형이 있다.
@FunctionalInterface public interface Converter<F, T> { T convert(F from); }
정적 메서드 참조 → 클래스명 :: 메서드명
public class IntegerUtils { // 정적 메서드, 클래스 메서드 public static int stringToInt(String s){ return Integer.parseInt(s); } } public class IntegerUtilsTest { public static void main(String[] args) { // 정적메서드 참조 Converter<String, Integer> converter = IntegerUtils::stringToInt; Integer result = converter.convert("123"); // Auto-Unboxing System.out.println(result); // 123 } }
인스턴스 메서드(static이 없는 메서드) 참조 : 객체참조 :: 메서드명
public class StringUtils { // 인스턴스 메서드(static이 없는 메서드) public String reverse(String s){ return new StringBuffer(s).reverse().toString(); } } public class StringUtilsTest { public static void main(String[] args) { StringUtils stringUtils = new StringUtils(); // 인스턴스 메서드 참조 Converter<String, String> converter = stringUtils::reverse; String result = converter.convert("hello"); System.out.println(result); } }
특정 객체의 인스턴스 메서드 참조 : 클래스명 :: 메서드명
public class SortCompareTest { public static void main(String[] args) { List<String> names = Arrays.asList("홍", "김", "이"); // String::compareTo -> 특정 객체의 메서드를 참조 Collections.sort(names, String::compareTo); System.out.println(names); } }
생성자 참조 : 클래스명 :: new
@FunctionalInterface public interface PersonFactory { public Person create(String name, int age); } public class PersonFactoryTest{ public static void main(String[] args) { // Person의 생성자 참조 PersonFactory personFactory = Person::new; Person person = personFactory.create("홍길동", 40); System.out.println(person); // 익명 내부 클래스 PersonFactory personFactory1 = new PersonFactory() { @Override public Person create(String name, int age) { return new Person(name, age); } }; Person person1 = personFactory1.create("나길동", 32); System.out.println(person1); } }
람다식이란?
자바 8부터 도입 되었으며 함수형 프로그래밍에서 사용되는 함수를 간결하게 표현하기 위한 방법 중 하나
익명 함수의 한 형태로서 메서드에 대한 구현을 간결하게 표현하는 방법
(parameters) → {expression}
- parameters : 메서드에서 사용할 매개변수
- expression : 메서드의 구현체
코드를 더 간결하고 읽기 쉽게 만들 수 있다.
람다식은 함수형 인터페이스와 함께 사용되고, 람다식으로 구현하여 사용할 수 있다.
인터페이스가 오직 하나의 추상 메서드를 가지고 있어야 사용가능하다.
public class LambdaExample { public static void main(String[] args) { /*MathOperation add = new MathOperation() { @Override public int operation(int x, int y) { return x+y; } };*/ // 람다식 : 코드가 간결 -> 구현이 쉽다 MathOperation add = (x, y) -> x+y; MathOperation multi = (x, y) -> x*y; int result = add.operation(10,20); int result1 = multi.operation(10,20); System.out.println(result); System.out.println(result1); } }
람다식 사용방법
람다 표현식을 메서드 내에서 사용
람다 표현식을 메서드의 인자로 전달
유연성을 높일 수 있다.
@FunctionalInterface public interface StringOperation { public String apply(String s); } public class LambdaApply { public static void main(String[] args) { // 람다 표현식을 메서드 내에서 사용 StringOperation toUpperCase = s -> s.toUpperCase(); StringOperation toLowerCase = s -> s.toLowerCase(); String input = "Lambda Expressions"; System.out.println(processString(input, toUpperCase)); System.out.println(processString(input, toLowerCase)); } // 메서드의 매개변수로 전달 public static String processString(String input, StringOperation operation){ return operation.apply(input); } }
Stream API
배열을 스트림으로 변환
- 배열의 원소들을 스트림 형태로 변환하여 처리 할 수 있게 하는 것
- 스트림은 원본 데이터를 변경하지 않고, 필요한 데이터 처리 작업을 적용한 결과를 생성하기 때문에 인덱스를 통한 직접 접근은 제공하지 않음
Stream(스트림)
- 자바 8에서 도입된 기능으로, 데이터의 흐름을 다루기 위한 선언형 api
- 필터링, 매핑, 정렬 등 다양한 데이터 처리 작업을 적용 할 수 있으며, 최종 결과를 배열이나 컬렉션으로 변환할 수 있다.
- 데이터 처리 작업을 연속적인 파이프라인을 나타낼 수 있어 가독성이 높고, 병렬 처리(연속적으로 스트림 기능을 점을 통해 사용가능)를 쉽게 구현할 수 있다.
- 배열을 스트림으로 변환하려면 Arrays.stream() 메서드 사용
- 스트림을 배열로 변환하려면 toArray() 메서드를 사용
- 스트림을 컬렉션으로 변환하려면 collect() 메서드를 사용
public class StreamApiTest { public static void main(String[] args) { int[] numbers = {1, 2, 3, 4, 5}; // IntStream stream = Arrays.stream(numbers); int sumOfEvens = Arrays.stream(numbers) // 배열을 스트림을 변환 .filter(n -> n % 2 == 0) .sum(); System.out.println(sumOfEvens); int[] evenNumbers = Arrays.stream(numbers) .filter(n -> n % 2 == 0) .toArray(); // 스트림을 배열로 변환 for(int even : evenNumbers){ System.out.println(even); } } }
스트림의 두 가지 연산
- 중간 연산 : 스트림을 처리하고 다른 스트림을 반환
- 최종 연산 : 스트림을 처리하고 결과를 반환
## Predicate란?
- argument를 받아 boolean 값을 반환하는 함수형 인터페이스
- functional method: test()
```java
public class StreamExample {
public static boolean isEven(int number){
return number % 2 == 0;
}
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // asList로 배열로 변환
// Predicate : 함수형 인터페이스 정의
Predicate<Integer> isEven = n -> n % 2 == 0;
int sumOfSquares = numbers.stream() // 배열을 스트림으로 변환
// .filter(isEven) // 짝수로 필터링
.filter(StreamExample::isEven) // 메서드 참조
.sorted() // 정렬
.map(n -> n * n) // 각 원소를 제곱해서 저장
.reduce(0, Integer::sum); // 0을 초기값으로 sum메서드 참조해서 모두 더하기
System.out.println(sumOfSquares);
}
}
```
```java
public class MapStreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> squaredNumbers = numbers.stream()
.map(n->n*n)
.collect(Collectors.toList()); // 배열로 변환
System.out.println(squaredNumbers);
}
}
```
```java
public class MapStreamExample2 {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "cherry", "orange");
List<String> uppercase = words.stream()
.map(word -> word.toUpperCase())
.collect(Collectors.toList()); // 컬렉션을 리스트로 바꾸기
System.out.println("uppercase = " + uppercase); // uppercase = [APPLE, BANANA, CHERRY, ORANGE]
for (String str : uppercase) {
System.out.println(str);
}
}
}
```
'개발 > Java' 카테고리의 다른 글
API 활용 (0) | 2024.01.29 |
---|---|
제네릭(Generic) (0) | 2024.01.29 |
Collection API (0) | 2024.01.29 |
인터페이스 기반의 프로그래밍 (0) | 2024.01.29 |
자바 String 클래스 (1) | 2024.01.29 |