익명 객체
인터페이스 타입으로 변수를 선언하고, 구현 객체를 초기값으로 대입하는 경우를 생각해보자.
인터페이스의 구현 클래스를 선언하고, new 연산자를 이용해 구현 객체를 생성한 후, Field나 Local 변수에 대입하는 것이 기본이다.
▶ 구현 클래스가 매번 달라지거나, 한 번만 사용되는 경우, 굳이 구현 클래스를 생성하지 않고
익명 클래스로(이름 없는 클래스)로 선언 할 수 있다.
☞ 멤버 변수 Car 에는 구현 클래스가 들어가야 한다.
Main Class
package api.ramda.basic;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class MainClass {
public static void main(String[] args) {
Person p = new Person();
p.greeting( new Say01() {
@Override
public void talking() {
System.out.println("hello");
}
});
p.greeting( new Say01() {
@Override
public void talking() {
System.out.println("안녕하세요");
}
});
p.greeting( new Say01() {
@Override
public void talking() {
System.out.println("니취팔로마");
}
});
System.out.println("---------------------------------");
//함수적인터페이스를 구현하는 익명객체를 -> 람다식으로 표현이 가능
p.greeting( () -> { System.out.println("hello"); });
p.greeting( () -> System.out.println("안녕하세요") ); //표현할 코드가 한줄이면 {}생략이 됩니다
System.out.println("---------------------------------");
// String r = p.greeting( new Say02() {
// @Override
// public String talking() {
// return "hello";
// }
// } );
String r = p.greeting( () -> "hello" ); //한줄이면서, return이 생략되면 자동으로 return됩니다
System.out.println(r);
System.out.println("---------------------------------");
// int r2 = p.greeting( new Say03() {
// @Override
// public int talking(String a, int b) {
// //처리할 코드
// int sum = 0;
// for(int i = 1; i <= b; i++) {
// sum += i;
// }
// return sum;
// }
// });
int r2 = p.greeting( (a, b) -> { //자동타입추론 ()안에는 타입을 생략합니다. 매개변수가 1개라면 ()도 생략가능합니다
int sum = 0;
for(int i = 1; i <= b; i++) {
sum += i;
}
return sum;
});
System.out.println(r2);
}
}
Person Class
package api.ramda.basic;
public class Person {
public void greeting(Say01 say) {
say.talking();
}
//say02를 받는 인사법
public String greeting(Say02 say) {
String result = say.talking();
return result;
}
//say03을 받는 인사법
public int greeting(Say03 say) {
int result = say.talking("hello", 10);
return result;
}
}
package api.ramda.basic;
//추상메서드가 1개인 인터페이스를 함수적인터페이스 라고 부릅니다.
public interface Say01 {
public void talking();
}
//////////////////////////////////////////////////////////////////////
package api.ramda.basic;
public interface Say02 {
public String talking();
}
//////////////////////////////////////////////////////////////////////
package api.ramda.basic;
public interface Say03 {
public int talking(String a, int b);
}
람다식
함수적 인터페이스의 익명 구현 객체를 대신한다.( 자바의 람다식 )
먼저 람다식의 이해 이전에 함수적 프로그래밍과 근래 기법에 대해 간단히 알아본다.
함수적 프로그래밍
y = f(x) 형태의 함수로 구성된 프로그래밍 기법
▶ 함수를 매개값으로 전달하고 결과를 받는 코드로 구성
※ 함수적 프로그래밍이 객체 지향 프로그래밍보다 효율적인 경우
1. 대용량 데이터의 처리시
2. 이벤트 지향 프로그램 처리 시
최근 프로그래밍 기법
객체 지향 프로그래밍에 함수적 프로그래밍 기법을 추가한다.
1. 자바 8부터 함수적 프로그래밍 기법 지원
- 람다식(Lamda Expression)을 제공한다.
- 익명 함수를 생성한기 위한 식 : (매개변수, 매개변수) ▶ {실행문}
2. 람다식의 장점
- 코드가 간결해진다.
- 컬렉션 요소 처리가 쉬워진다.
람다식(Lambda Expression)은 코드블럭(Code Block)을 메소드에 넣을 때 사용하는 기술이다.
람다식을 적용하기 위한 스트림
1. 반복자 스트림
- 자바 8부터 추가된 Collection의 저장 요소를 하나씩 참조하도록 도와주는 반복자이다.
- 람다식으로 처리할 수 있도록 해주는 반복자이다.
- 파일 입출력 Stream과는 다른 개념이다.
스트림의 특징
1. Iterorator과 비슷한 역할을 하는 반복자이다.
2. 대부분 메서드는 함수적 인터페이스 타입이다.
3. 속도면에서 빠르다.
- Collection에서 Stream을 사용하는 간단한 예제
- Stream은 중간처리와 최종처리가 함수형으로 표현 가능하다.
- 중간 처리 메서드
- 최종 처리 메서드
package api.ramda.basic2;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
public class MainClass01 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("홍길동");
list.add("피카츄");
list.add("라이츄");
list.add("꼬북이");
for(String s : list) {
System.out.println(s);
}
System.out.println("-------------------------------------------");
//Stream<String> stream = list.stream();
//stream.forEach( a -> System.out.println(a) );
// list.stream().forEach( new Consumer<String>() {
// @Override
// public void accept(String a) {
// System.out.println(a);
// }
//
// });
list.stream().forEach( a -> System.out.println(a) );
}
}
package api.ramda.basic2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class MainClass02 {
public static void main(String[] args) {
/*
* 펑셔널인터페이스
* Consumer - 매개변수가 1개 이상이고, 반환은 void
* Predicate - 매개변수가 1개 이상이고, 반환이 boolean
* Function - 매개변수가 1개 이상이고, 반환은 임의의 타입
*/
//100개의 랜덤한 값을 가지고 있는 리스트
List<Integer> list = new ArrayList<>();
for(int i = 0; i < 100; i++ ) {
list.add( new Random().nextInt(100) + 1 );
}
System.out.println(list.toString());
System.out.println("-----------------------------------");
//중복제거
list.stream().distinct().forEach( a -> System.out.print(a + " ") );
System.out.println("\n-----------------------------------");
//return에 true인 값들만 필터링해서 저장
list.stream().filter( a -> a > 50 ).forEach(a -> System.out.print(a + " ") );
System.out.println("\n-----------------------------------");
//정렬
list.stream().sorted().forEach(a -> System.out.print(a + " "));
System.out.println("\n-----------------------------------");
//map -> 메서드 안에 정의된 내용을 기준으로 새로운 리스트를 만듬
//a는 리스트의 요소, 반환은 임의의 새로운값
list.stream().map( a -> a % 2 == 0 ? true : false).forEach(a -> System.out.print(a + " ") );
System.out.println("\n-----------------------------------");
list.stream()
.distinct()
.map( a -> a > 50 ? a : 0 )
.filter( a -> a != 0 )
.sorted()
.forEach( a -> System.out.print(a + " ") );
System.out.println("\n-----------------------------------");
//collect = 최종수집함수(새로운 list, set, map) 반환을 받을 수 있음
List<Integer> newList = list.stream()
.map( a -> a < 0 ? -a : a)
.sorted()
.collect( Collectors.toList() );
System.out.println(newList);
System.out.println("--------------------------------------");
List<String> list2 = Arrays.asList("hong", "LEE", "Park", "Choi");
//각 이름의 최초 0번째 글자를 얻어서, 전부 대문자로 치환하고, 알파벳순으로 정렬한 결과를 리스트로 반환받는다
List<String> newList2 = list2.stream()
.map( a -> a.toUpperCase().charAt(0) + "" )
.sorted()
.collect(Collectors.toList());
System.out.println(newList2);
Map<String, Integer> map = list2.stream().collect(Collectors.toMap(a -> a, a -> a.length() ));
System.out.println(map.toString());
}
}
package api.ramda.basic2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.function.BinaryOperator;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class MainClass03 {
public static void main(String[] args) {
/*
* Stream의 타입
*
* Stream - 오리지널스트림
* IntStream - 정수저장스트림
* DoubleStream - 실수저장스트림
* LongStream - 롱타입 저장스트림
* Optional - 이외의 것들을 저장스트림
*
*/
List<Integer> list = new ArrayList<>();
for(int i = 1; i <= 20; i++) {
list.add( new Random().nextInt(100) + 1 );
}
System.out.println(list.toString());
//평균, 합계, 개수 등 집계기능을 사용하려면 정수형스트림으로 변경
//mapToXXX()
long cnt = list.stream().mapToInt( a -> a).count(); //count -최종함수
System.out.println("데이터개수:" + cnt);
int sum = list.stream().mapToInt(a -> a).sum(); //sum - 최종함수
System.out.println("데이터의합계:" + sum);
//optionalXX은 특정한 값을 저장하고 있는 객체, 값을 얻을때는 get메서드를 사용함
double avg = list.stream().mapToInt(a -> a).average().getAsDouble();
System.out.println("데이터의평균:" + avg);
int min = list.stream().mapToInt(a -> a).min().getAsInt();
System.out.println("최소값:" + min);
//boxed() -> 정수스트림을 오리지널스트림으로 형변환
Stream<Integer> s = list.stream().mapToInt(a -> a).boxed();
//Reduce() - 사용자가 정의한 합계를 구할 수 있는 최종메서드
List<String> list2 = Arrays.asList("a", "b", "c", "d", "e");
//a가 초기값, b가 요소
String result = list2.stream().reduce((a, b) -> a+b).get();
System.out.println(result);
System.out.println("---------------------------------------------------");
//정수스트림을 빠르게 만드는법
//0~10미만 값을 인트스트림으로 생성
IntStream.range(0, 10).forEach( a -> System.out.print(a + " ") );
System.out.println();
//0~10까지 값을 인트스트림으로 생성
IntStream.rangeClosed(0, 10).forEach( a -> System.out.print(a + " "));
System.out.println();
//1~100까지 값을 저장하는 리스트
List<Integer> list3 = IntStream.rangeClosed(1, 100).boxed().collect( Collectors.toList() );
System.out.println(list3);
}
}
728x90
'Programming > Java' 카테고리의 다른 글
[JAVA] 멀티 스레드 (0) | 2024.02.26 |
---|---|
[JAVA] 정규표현식 (0) | 2024.02.26 |
[JAVA] API - java.util 패키지 (Collection FrameWork) (0) | 2023.12.07 |
[JAVA] API-IO (Input 스트림과 Output 스트림) (1) | 2023.12.06 |
[JAVA] API - java.util Package (0) | 2023.12.05 |