@FunctionalInterface
public interface Runnable{
public abstract void run();
}
@FUnctionalInterface
interface MyFunction{
void run(); //public abstract void run();
}
Runnalbe r = () -> {System.out.println("funmctional interface");}
Comparator<Apple> weight = new Comparator<Apple>(){
@Override
public int compare(Apple o1, Apple o2){
return o1.getWeight().compareTo(o2.getWeight());
}
}
Comparator<Apple> weight =
(Apple o1, Apple o2) -> o1.getWeight().compareTo(o2.getWeight());
public class LambdaCreateThreadEx1{
public static void main(String[] args) {
// 람다 없이 Thread 생성
Runnable r1=new Runnable(){
public void run(){
System.out.println("Thread1 is running...");
}
};
Thread t1=new Thread(r1); t1.start();
// 람다를 사용한 Thread 생성
Runnable r2=()->{
System.out.println("Thread2 is running...");
};
Thread t2=new Thread(r2);
t2.start();
}
}
public class LambdaProduct{
int id;
String name;
int price;
public LambdaProduct(int id, String name, int price) {
this.id = id;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getPrice() {
return price;
}
public class LambdaCollectionComparator {
public static void main(String[] args) {
List<LambdaProduct> list=new ArrayList<>();
list.add(new LambdaProduct(1,"노트북",25000));
list.add(new LambdaProduct(3,"키보드",300));
list.add(new LambdaProduct(2,"마우스",150));
System.out.println("이름 기준 정렬");
// lambda expression 구현
Collections.sort(list,(p1, p2)->{
return p1.name.compareTo(p2.name);
});
for(LambdaProduct p:list){
System.out.println(
p.id+" "+p.name+" "+p.price);
}
}
}
[결과]
이름 기준 정렬
1 노트북 25000
2 마우스 150
3 키보드 300
종류 | 형식 |
---|---|
정적 메서드 참조 | 클래스명::정적메서드명 |
객체 메서드 참조 | 객체변수::메서드명 |
람다인자 객체 메서드 참조 | 클래스명::메서드명 |
생성자 참조 | 클래스명::New |
(apple) -> apple.getWeight();
Apple::getWeight;
정적 메서드 참조(Static method reference)
인스턴스 메서드 참조(Instance method reference)
생성자 참조(Constructor reference)
정적 메서드 참조 예제: 미리 정의된 Runnable 인터페이스를 사용하여 정적 메서드 참조를 한다.
public class StaticMethodReferenceEx2 {
public static void ThreadStatus(){
System.out.println("Thread is running");
}
public static void main(String[] args) {
Thread t2=new Thread(StaticMethodReferenceEx2::ThreadStatus);
t2.start();
}
}
[결과]
Thread is running
interface SayableEx{
void say();
}
public class InstanceMethodReferenceEx1 {
public void saySomething(){
System.out.println("안녕, 인스턴스 메서드");
}
public static void main(String[] args) {
InstanceMethodReferenceEx1 methodReference = new InstanceMethodReferenceEx1();
// 참조를 사용한 인스턴스 메서드 참조
SayableEx sayable = methodReference::saySomething;
// 인터페이스 메서드 호출
sayable.say();
// 익명 객체를 이용한 인스턴스 메서드 참조
Sayable sayable2 = new InstanceMethodReferenceEx1()::saySomething; // 익명 객체를 사용할 수 있다
sayable.say();
}
}
[결과]
안녕, 인스턴스 메서드
안녕, 인스턴스 메서드
interface Messageable{
Message getMessage(String msg);
}
class Message{
Message(String msg){
System.out.print(msg);
}
}
public class ConstructorReferenceEx1 {
public static void main(String[] args) {
Messageable hello = Message::new;
hello.getMessage("안녕");
}
}
[결과]
안녕
종류 | 추상 메서드 특징 |
---|---|
Function | 인자 있고, 리턴값 있음, 주로 인자값을 연산하고 결과를 리턴 |
Consumer | 인자 있고, 리턴값 없음 |
Supplier | 인자 없고, 리턴값 있음 |
Operator | 인자 있고, 리턴값 있음. 주로 인자값을 연산하고 결과를 리턴 |
Predicate | 인자 있고, 리턴값은 boolean, 인자값을 조사하고 true/false를 리턴 |
//T R
Function<BufferedReader, String> f = (BufferedReader b) -> {
//구현부
};
//T U R
BiFunction<String, String, String> func1 = (s1, s2) -> {
String s3 = s1 + s2;
return s3;
};
String result = func1.apply("Hello", "World");
Function<BufferedReader, String> f = (BufferedReader b) -> {
try{
return b.readLine();
}catch(IOException e){
throw new RuntimeException(e);
}
}
인터페이스 명 | 추상 메서드 | 설명 |
---|---|---|
Predicate<T> | boolean test(T t) | 객체 T를 조사 |
BiPredicate<T, U> | boolean test(T t, U u) | 객체 T와 U를 비교 조사 |
DoublePredicate | boolean test(double value) | double 값을 조사 |
IntPredicate | boolean test(int value) | int 값을 조사 |
LongPredicate | boolean test(long value) | long 값을 조사 |
@FunctionalInterface
public interface Predicate<T>{
boolean test(T t);
...
}
public <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> results = new ArrayList<>();
for(T t: list){
if(p.test(t)) {
results.add(t);
}
}
return results;
}
Predicate<String> predicate = (String s) -> !s.isEmpty();
List<String> nonEmpty = filter(lists, predicate);
인터페이스 명 | 추상 메서드 | 설명 |
---|---|---|
Consumer<T> | void accept(T t) | 객체 T를 받아 소비 |
BiConsumer<T,U> | void accept(T t, U u) | 객체 T와 U를 받아 소비 |
DoubleConsumer | void accept(double value) | double 값을 받아 소비 |
IntConsumer | void accept(int value) | int 값을 받아 소비 |
LongConsumer | void accept(long value) | long 값을 받아 소비 |
ObjDoubleConsumer<T> | void accept(T t, double value) | 객체 T와 double 값을 받아 소비 |
ObjIntConsumer<T> | void accept(T t, int value) | 객체 T와 int 값을 받아 소비 |
ObjLongConsumer<T> | void accept(T t, long value) | 객체 T와 long 값을 받아 소비 |
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
...
}
public <T> void forEach(List<T> list, Consumer<T> c){
for(T t:list){
c.accept(t);
}
}
forEach(
Arrays.asList(1,2,3,4,5),
(Integer i) -> System.out.println(i)
);
[결과]
1
2
3
4
5
@FunctionalInterface
public interface Function<T, R>{
R apply(T t);
...
}
인터페이스명 | 추상메서드 | 설명 |
---|---|---|
Function<T,R> | R apply(T t) | 객체 T를 객체 R로 매핑 |
BiFunction<T,R> | R apply(T t, U u) | 객체 T와 U를 객체 R로 매핑 |
DoubleFunction<R> | R apply(double value) | double을 객체 R로 매핑 |
IntFunction<R> | R apply(int value) | int를 객체 R로 매핑 |
IntToDoubleFunction | double applyAsDouble(int value) | int를 double로 매핑 |
IntToLongFunction | long applyAsLong(int value) | int를 long으로 매핑 |
LongToDoubleFunction | double applyAsDouble(long value) | long을 double로 매핑 |
LongToIntFunction | int applyAsInt(long value) | long을 int로 매핑 |
ToDoubleBiFunction<T,U> | double applyAsDouble(T t, U u) | 객체 T와 U를 double로 매핑 |
ToDoubleFunction<T> | double applyAsDouble(T value) | 객체 T를 double로 매핑 |
ToIntBiFunction<T,U> | int applyAsInt(T t, U u) | 객체 T와 U를 int로 매핑 |
ToIntFunction<T> | Int applyAsInt(T value) | 객체 T를 int로 매핑 |
ToLongBiFunction<T,U> | long applyAsLong(T t, U u) | 객체 T와 U를 long으로 매핑 |
ToLongFunction<T> | long applyAsLong(T value) | 객체 T를 long으로 매핑 |
public <T, R> List<R> map(List<T> list, Function<T, R> f){
List<R> result = new ArrayList<>();
for(T t: list){
result.add(f.apply(t));
}
return result;
}
List<Integer> resultlist = f.map(
Arrays.asList("람다", "홍길동", "함수형 인터페이스"),
(String s) -> s.length()
);
[결과]
[2, 3, 9]
Argument 값 → Operator → 리턴 값
UnaryOperator<String> u = str -> str + " operator";
String result = u.apply("test"); // test operator
인터페이스명 | 추상메서드 | 설명 |
---|---|---|
BinaryOperator<T> | BiFunction<T,U,R>의 하위 인터페이스 | T와 U를 연산한 후 R 리턴 |
UnaryOperator<T> | Function<T,R>의 하위 인터페이스 | T를 연산한 후 R 리턴 |
DoubleBinaryOperator | double applyAsDouble(double, double) | 두 개의 double 연산 |
DoubleUnaryOperator | double applyAsDouble(double) | 한 개의 double 연산 |
IntBinaryOperator | int applyAsInt(int, int) | 두 개의 int 연산 |
IntUnaryOperator | int applyAsInt(int) | 한 개의 int 연산 |
LongBinaryOperator | long applyAsLong(long, long) | 두 개의 long 연산 |
LongUnaryOperator | long applyAsLong(long) | 한 개의 long 연산 |
@FunctionalInterface
public interface Supplier<T>{
T get();
}
Supplier<String> s = () -> "supplier";
String result = s.get(); //supplier
인터페이스명 | 추상메서드 | 설명 |
---|---|---|
Supplier<T> | T get() | 객체를 리턴 |
BooleanSupplier | boolean getAsBoolean() | boolean 값을 리턴 |
DoubleSupplier | double getAsDouble() | double 값을 리턴 |
IntSupplier | int getAsInt() | int 값을 리턴 |
LongSupplier | long getAsLong() | long 값을 리턴 |
static <T> List<T> doSomething(Function<T, T> f, List<T> list) {
System.out.print("Function : ");
List<T> newList = new ArrayList<T>(list.size());
for(T i : list) {
newList.add(f.apply(i));
}
return newList;
}
static <T, R> List<R> doSomething2(Function<T, R> f, List<T> list) {
System.out.print("Function : ");
List<R> newList = new ArrayList<R>(list.size());
for(T i : list) {
newList.add(f.apply(i)); // i/10
}
return newList;
}
static <T> void printEvenNum(Predicate<T> p, Consumer<T> c, List<T> list) {
System.out.print("Predicate, Consumer : [");
for(T i : list) {
// i%2==0
if(p.test(i)) // boolean return (짝수 여부)
c.accept(i); // T 객체 소비 System.out.print(i+", ")
}
System.out.println("]");
}
static <T> void makeRandomList(Supplier<T> s, List<T> list) {
for(int i=0;i<10;i++) {
list.add(s.get()); // T 객체 리턴
}
}
public static void main(String[] args) {
// Supplier<T> -> T get()
Supplier<Integer> s = ()-> (int)(Math.random()*100)+1; // 랜덤 값
// Consumer<T> -> void accept(T t)
Consumer<Integer> c = i -> System.out.print(i+", ");
// Predicate<T> -> boolean test(T t)
Predicate<Integer> p = i -> i%2==0; // 짝수 구하기
// Function<T, R> -> R apply(T t)
Function<Integer, Integer> f = i -> i/10;
// 문자열 표시
Function<Integer, String> f2 = i -> "\"" + Integer.toString(i/10) + "\"";
List<Integer> list = new ArrayList<>();
makeRandomList(s, list); // Supplier
System.out.println("Supplier : " + list);
printEvenNum(p, c, list); // Predicate, Consumer
List<Integer> newList = doSomething(f, list); // function
System.out.println(newList);
List<String> newList2 = doSomething2(f2, list);
System.out.println(newList2);
}
[결과]
Supplier : [86, 10, 92, 60, 32, 29, 3, 44, 29, 94]
Predicate, Consumer : [86, 10, 92, 60, 32, 44, 94, ]
Function:[8,1,9,6,3,2,0,4,2,9]
Function : ["8", "1", "9", "6", "3", "2", "0", "4", "2", "9"]
//기존의 for문을 이용한 방식
int count = 0;
for(String w : words){
if(w.length() > 12) count++;
}
//Stream을 이용한 방식
long count = words.stream()
.filter(w -> w.length()>12)
.count();
//병렬처리를 수행하는 Stream을 이용한 방식
long count = words.parallelStram()
.filter(w -> w.length()>12)
.count();
List<Dish> lowCaloricDishes = new ArrayList<>();
for(Dish d: dishes){
if(d.getCalories() > 400){
lowCaloricDishes.add(d);
}
}
List<String> lowCaloricDishesName = new ArrayList<>();
Collections.sort(lowCaloricDishes, new Comparator<Dish>() { //익명클래스compare로정렬
public int compare(Dish d1, Dish d2){
return Integer.compare(d1.getCalories(), d2.getCalories());
}
});
for(Dish d: lowCaloricDishes){
lowCaloricDishesName.add(d.getName());
}
List<String> lowCaloricDishesName =
dishes.stream()
.filter(d -> d.getCalories() > 400)
.sorted(comparing(Dish::getCalories))
.map(Dish::getName)
.collect(toList());
public class StreamFilterCollectEx1 {
public static void main(String[] args) {
List<LambdaProduct> list = new ArrayList<LambdaProduct>();
list.add(new LambdaProduct(1,"삼성",17000));
list.add(new LambdaProduct(3,"아이폰",65000));
list.add(new LambdaProduct(2,"소니",25000));
list.add(new LambdaProduct(4,"노키아",15000));
list.add(new LambdaProduct(6,"레노바",19000));;
List<Integer> productPriceList = list.stream()
.filter(p -> p.price > 20000) // 데이터 필터링
.map(p -> p.price) // 가격 얻어오기
.collect(Collectors.toList());// collecting list
System.out.println(productPriceList);
}
}
[결과]
[65000, 25000]
public class StreamReduceEx01 {
public static void main(String[] args) {
List<LambdaProduct> productsList = new ArrayList<>();
productsList.add(new LambdaProduct(1,"삼성",17000));
productsList.add(new LambdaProduct(3,"아이폰",65000));
productsList.add(new LambdaProduct(2,"소니",25000));
productsList.add(new LambdaProduct(4,"노키아",15000));
productsList.add(new LambdaProduct(6,"레노바",19000));
// 데이터 필터링의 간결한 접근 방식
int totalPrice = productsList.stream()
.map(product->product.price)
.reduce(0,(sum, price)-> sum + price); // 누적 가격
System.out.println(totalPrice);
}
}
[결과]
141000
public class StreamConverListToMapEx01{
public static void main(String[] args) {
List<LambdaProduct> productsList = new ArrayList<>();
productsList.add(new LambdaProduct(1,"삼성",17000));
productsList.add(new LambdaProduct(3,"아이폰",65000));
productsList.add(new LambdaProduct(2,"소니",25000));
productsList.add(new LambdaProduct(4,"노키아",15000));
productsList.add(new LambdaProduct(6,"레노바",19000));
// Product List를 Map으로 변환
Map<Integer,String> productPriceMap =
productsList.stream()
.collect(Collectors.toMap(p->p.id, p->p.name));
System.out.println(productPriceMap);
}
}
[결과]
{1=삼성, 2=소니, 3=아이폰, 4=노키아, 6=레노바}
//순차 필터링
long count = values.stream().filter().count();
//병렬 필터링
long count1 = values.parallelStream().filter().count();
1612104
순차 필터링 소요 시간: 168 ms
1612104
병렬 필터링 소요 시간: 36 ms
연산 | 형식 | 반환 형식 |
---|---|---|
filter | 중간 연산 | Stream<T> |
map | 중간 연산 | Stream<R> |
limit | 중간 연산 | Stream<T> |
sorted | 중간 연산 | Stream<T> |
distinct | 중간 연산 | Stream<T> |
연산 | 형식 | 반환 형식 | 목적 |
---|---|---|---|
forEach | 최종 연산 | void | 스트림의 각 요소를 소비하면서 람다를 적용한다. |
count | 최종 연산 | long (generic) | 스트림의 요소 개수를 반환한다. |
collect | 최종 연산 | 스트림을 리듀스에서 리스트, 맵, 합수 형식의 컬렉션을 만든다. |
리턴 타입 | 메서드(매개 변수) | 소스 |
---|---|---|
Stream<T> | java.util.Collection.stream( java.util.Collection.parallelStream() | |
Stream<T> IntStream LongStream DoubleStream | Arrays.stream(T[ ]), Stream.of(T[ ]) Arrays.stream(int[ ]), IntStream.of(int[ ]) Arrays.stream(long[ ]), LongStream.of(long[ ]) Arrays.stream(double[ ]), DoubleStream.of(double[ ]) | 배열 |
IntStream | IntStream.range(int, int) | |
IntStream.rangeClosed(int, int) | int 범위 | |
LongStream | LongStream.range(long, long) LongStream.rangeClosed(long, long) | long 범위 |
Stream<Path> | Files.find(Path, int, BiPredicate, FileVisitOption) Files.list(Path) | 디렉토리 |
Stream<String> | Files.lines(Path, Charset) BufferedReader.lines() | 파일 |
DoubleStream IntStream LongStream | Random.doubles(…) Random.ints() Random.longs() | 랜덤 수 |
List<String> highCaloricDish = new ArrayList<>();
Iterator<String> iterator = menu.iterator();
while(iterator.hasNext()){
Dish dish = iterator.next();
if(dish.getCalories() > 300){
highCaloricDish.add(dish.getName());
}
}
List<String> highCaloricDish =
menu.stream()
.flter(d -> d.getCalories() > 300)
.collect(toList());
List<String> names =
menu.stream() //객체 리스트에서 스트림 얻기
.filter(dish -> dish.getCalories() > 300)
.map(Dish::getName) //중간 연산
.limit(3) //중간 연산
.collect(toList()); //스트림을 리스트로 변환
Stream<T> filter(Predicate<? super T> predicate);
List<Dish> vegetarianMenu =
menu.stream()
.filter(Dish::isVegetarian)
.collect(toList());
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 2, 4);
numbers.stream()
.filter(i -> i%2 == 0)
.distinct()
.forEach(System.out::println);
List<Dish> dishes =
specialMenu.stream()
.filter(dish -> dish.getCalories() > 300)
.limit(3)
.collect(toList());
List<String> dishNames = menu.stream()
.map(Dish::getName)
.collect(toList());
List<Integer> dishNames = menu.stream()
.map(Dish::getName)
.map(String::length)
.collect(toList());
// [[a], [b]]
List<List<String>> list = Arrays.asList(Arrays.asList("a"), Arrays.asList("b"));
// [a, b]
List<String> flatList = list.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
List<String> words = Arrays.asList("Hello", "World");
List<String> uniqueCharacters =
words.stream()
.map(word -> word.split("")) //단어를 개별 문자 배열로 반환
.flatMap(Arrays::stream) //생성된 스트림을 하나의 스트림으로 평면화
.distinct()
.collect(toList());
[결과]
[H, e, l, o, W, r, d]
if(menu.stream().anyMatch(Dish:isVegetarian)){
System.out.println("Vegetarian menu");
}
boolean isHealthy = menu.stream()
.allMatch(dish -> dish.getCalories() < 1000);
boolean isHealthy = menu.stream()
.noneMatch(dish -> dish.getCalories() >= 1000);
Optional<Integer> max = numbers.stream().reduce(Integer::max);
Optional<Integer> min = numbers.stream().reduce(Integer::min);