사용자로부터 총 5개의 정수를 입력받아 하나의 쓰레드에게 전달하고, 총합을 계산해서 그 결과를 출력하는프로그램을 작성하자
package com.test.memo;
import java.util.Scanner;
class IntegerCom {
int num = 0;
boolean isNewNum = false;
void setNum(int n) {
synchronized (this) {
if (isNewNum) { // true라면
try {
wait(); // 특정조건을 충족시키기를 기다림
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num = n;
isNewNum = true;
notify();
}
}
int getNum() { // 저장된 정수 반환
int reNum;
synchronized (this) {
if (!isNewNum) { // false라면
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
reNum = num;
isNewNum = false;
return reNum;
}
}
}
class IntegerSum extends Thread {
IntegerCom com;
int sum;
IntegerSum(IntegerCom com) {
this.com = com;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
sum += com.getNum();
}
System.out.println("입력된 정수의 합 : " + sum);
}
}
public class Practice {
public static void main(String[] args) {
IntegerCom com = nm();
IntegerSum sum = new IntegerSum(com);
sum.start();
Scanner sc = new Scanner(System.in);
System.out.println("5개의 정수 입력 ...");
for (int i = 0; i < 5; i++) {
com.setNum(sc.nextInt());
}
try {
sum.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.test.memo;
import java.util.concurrent.locks.ReentrantLock;
class IHaveTwoNum {
int num1 = 0;
int num2 = 0;
// Object key1 = new Object();
// Object key2 = new Object();
private final ReentrantLock key1 = new ReentrantLock();
private final ReentrantLock key2 = new ReentrantLock();
public void addOneNum1() {
key1.lock();
try {
num1 += 1;
} finally {
key1.unlock();
}
}
public void addTwoNum1() {
key1.lock();
try {
num1 += 2;
} finally {
key1.unlock();
}
}
public void addOneNum2() {
key2.lock();
try {
num2 += 1;
} finally {
key2.unlock();
}
}
public void addTwoNum2() {
key2.lock();
try {
num2 += 2;
} finally {
key2.unlock();
}
}
public void showAllNums() {
System.out.println("num1: " + num1);
System.out.println("num2: " + num2);
}
}
class AccessThread extends Thread {
IHaveTwoNum twoNumInst;
public AccessThread(IHaveTwoNum inst) {
twoNumInst = inst;
}
public void run() {
twoNumInst.addOneNum1();
twoNumInst.addTwoNum1();
twoNumInst.addOneNum2();
twoNumInst.addTwoNum2();
}
}
public class Practice1 {
public static void main(String[] args) throws Exception {
IHaveTwoNum numInst = new IHaveTwoNum();
AccessThread at1 = new AccessThread(numInst);
AccessThread at2 = new AccessThread(numInst);
at1.start();
at2.start();
try {
at1.join();
at2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
numInst.showAllNums();
}
}
//num1: 6
//num2: 6
package com.test.memo;
import java.util.Scanner;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
class InputCom {
String newInput;
boolean isNewString = false;
private final ReentrantLock lock = new ReentrantLock();
private final Condition read = lock.newCondition();
private final Condition write = lock.newCondition();
void setNewString(String str) {
lock.lock();
try {
if (isNewString) {
write.await();
}
newInput = str;
isNewString = true;
read.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
String getString() {
String str = null;
lock.lock();
try {
if (!isNewString) {
read.await();
}
str = newInput;
isNewString = false;
write.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return str;
}
}
class StringWriter extends Thread {
InputCom com;
StringWriter(InputCom com) {
this.com = com;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("readString " + com.getString());
}
}
}
class StringReader extends Thread {
InputCom com;
StringReader(InputCom com) {
this.com = com;
}
@Override
public void run() {
Scanner sc = new Scanner(System.in);
String in;
for (int i = 0; i < 5; i++) {
in = sc.next();
com.setNewString(in);
}
}
}
public class Practice1 {
public static void main(String[] args) throws Exception {
InputCom com = new InputCom();
StringReader sr = new StringReader(com); // 스레드 2
StringWriter sw = new StringWriter(com); // 스레드 3
System.out.println("입출력된 쓰레드 실행...");
sr.start();
sw.start();
}
}

1.Thread문제
package com.test.memo;
public class Practice1 {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
}
}// main
//실행 결과
0 2 4 6 8 10 12 14 16 18
package com.test.memo;
public class Practice1 {
public static void main(String[] args) {
Runnable task1 = () -> {
for (int i = 0; i < 20; i++) {
if (i % 2 == 0) {
System.out.print(i + " ");
}
}
};
Thread t1 = new Thread(task1);
t1.start();
}
}// 0 2 4 6 8 10 12 14 16 18
package com.test.memo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Practice1 {
public static void main(String[] args) {
Runnable task = () -> {
int n1 = 10;
int n2 = 20;
String name = Thread.currentThread().getName();
System.out.println(name + ": " + (n1 + n2));
};
ExecutorService exr = Executors.newSingleThreadExecutor();
exr.submit(task);
System.out.println("End" + Thread.currentThread().getName());
exr.shutdown();
}
}//Endmain
//pool-1-thread-1: 30
package com.test.memo;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Practice1 {
public static void main(String[] args) {
// 쓰레드 풀 생성
ExecutorService exr = Executors.newSingleThreadExecutor();
// Callable 객체 생성 및 submit
Callable<Integer> c = () -> {
int sum = 0;
for (int i = 1; i <= 10; i++) {
sum += i;
}
return sum;
};
// Future 객체를 통해 Callable의 결과값을 받음
Future<Integer> f = exr.submit(c);
try {
int result = f.get();// 블록킹되어 결과값을 기다림
System.out.println("1~10까지의 합 : " + result);
} catch (Exception e) {
e.printStackTrace();
}
// 쓰레드 풀 종료
exr.shutdown();
}
}// 1~10까지의 합 : 55
package com.test.memo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Practice1 {
public static List<Integer> lst = Collections.synchronizedList(new ArrayList<Integer>());
public static void main(String[] args) {
for (int i = 0; i < 16; i++)
lst.add(i);
System.out.println(lst);
Runnable task = () -> { // 이 코드로 해야 Iterator()까지 동기화 처리된것
synchronized (lst) { // 동기화 블록의 내부를 실행할 때 lst에 다른 쓰레드의 접근을 허용하지 않는다.
ListIterator<Integer> itr = lst.listIterator();
while (itr.hasNext())
itr.set(itr.next() + 1);
}
};
ExecutorService exr = Executors.newFixedThreadPool(3); // 3개짜리 풀 생성
exr.submit(task);
exr.submit(task);
exr.submit(task); // 쓰레드 3개 실행
exr.shutdown();
try {
exr.awaitTermination(100, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(lst);
}
}// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
//[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
예제 1
interface Printable {
void print(String s); // 매개변수 하나, 반환형 void
}
class OneParamNoReturn {
public static void main(String[] args) {
Printable p;
p = (String s) -> {System.out.println(s);}; // 줄임 없는 표현
p.print("Lambda exp one.");
p = (String s) -> System.out.println(s); // 중괄호 생략
p.print("Lambda exp two.");
p = (s) -> System.out.println(s); // 매개변수 형 생략
p.print("Lambda exp three.");
p = s -> System.out.println(s); // 매개변수 소괄호 생략
p.print("Lambda exp four.");
}
}
/*
Lambda exp one.
Lambda exp two.
Lambda exp three.
Lambda exp four.
*/
예제 2
interface Calculate {
void cal(int a, int b); // 매개변수 둘, 반환형 void
}
class TwoParamNoReturn {
public static void main(String[] args) {
Calculate c;
c = (a, b) -> System.out.println(a + b);
c.cal(4, 3);
c = (a, b) -> System.out.println(a - b);
c.cal(4, 3);
c = (a, b) -> System.out.println(a * b);
c.cal(4, 3);
}
}
/*
7
1
12
*/
interface HowLong {
int len(String s); // 값을 반환하는 메소드
}
class OneParamAndReturn {
public static void main(String[] args) {
HowLong hl = s -> s.length();
System.out.println(hl.len("I am so happy"));
}
}
/*
13
*/
예제 3
@FunctionalInterface
interface Calculate <T> {
T cal(T a, T b);
}
class LambdaGeneric {
public static void main(String[] args) {
Calculate<Integer> ci = (a, b) -> a + b;
System.out.println(ci.cal(4, 3));
Calculate<Double> cd = (a, b) -> a + b;
System.out.println(cd.cal(4.32, 3.45));
}
}
/*
7
7.7700000000000005
*/
Predicate
import java.util.List;
import java.util.Arrays;
import java.util.function.Predicate;
//@FunctionalInterface
//public interface Predicate<T> { > 미리 정의되어 있는 함수형 인터페이스
// boolean test(T t); > test메소드 하나 정의되어 있음, 메인메소드에서 이 test를 만들어서 같이 보내야한다.
//}
class PredicateDemo {
public static int sum(Predicate<Integer> p, List<Integer> lst) {
int s = 0;
for(int n : lst) {
if(p.test(n))
s += n;
}
return s;
}
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 5, 7, 9, 11, 12);
int s; //test()
s = sum(n -> n%2 == 0, list);
System.out.println("짝수 합: " + s);
s = sum(n -> n%2 != 0, list);
System.out.println("홀수 합: " + s);
}
}
/*
짝수 합: 12
홀수 합: 33
*/
표준으로 정의된 대표적인 함수형 인터페이스 네 개와 그 안에 위치한 추상 메소드는 아래와 같다.(암기)
이들은 java.util.function 패키지로 묶여있다.
Predicate boolean test(T t) : 매개변수 하나, 반환 타입 boolean
Supplier T get() : 매개변수 x, 반환값 O
Consumer void accept(T t) : 매개변수O, 반환값 X
Function<T, R> R apply(T t) : 하나의 매개변수를 받아서 결과를 반환
Predicate removeIf()
default boolean removeIf(Predicate<? super E> filter) > Collection\<E> 인터페이스에 디폴트 메소드로 정의되어 있다.
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.function.Predicate;
class RemoveIfDemo {
public static void main(String[] args) {
List<Integer> ls1 = Arrays.asList(1, -2, 3, -4, 5);
ls1 = new ArrayList<>(ls1);
List<Double> ls2 = Arrays.asList(-1.1, 2.2, 3.3, -4.4, 5.5);
ls2 = new ArrayList<>(ls2);
Predicate<Number> p = n -> n.doubleValue() < 0.0; //조건을 만족하는 애는 삭제 > 0보다 작으면 삭제
ls1.removeIf(p);
ls2.removeIf(p);
System.out.println(ls1); //1 3 5
System.out.println(ls2); //2.2 3.3 5.5
}
}
ArrayList의 제네릭을 Integer로 인스턴스를 생성하면, 그 안에 존재하는 removeIf메소드의 E는 아래와 같이 Integer로 결정된다.
public boolean removeIf(Predicate<? super Integer> filter) {...}제네릭을 Number로 놓은 이유는 실수 정수 모두 다룰 수 있게 하기 위함
Supplier
단순히 무언가를 반환해야 할 때 유용하게 사용할 수 있다.
package com.test.memo;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
public class Practice1 {
public static List<Integer> makeIntList(Supplier<Integer> s, int n) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < n; i++)
list.add(s.get());
return list;
}
public static void main(String[] args) {
// Supplier<Integer> spr = new Supplier<Integer>() {
//
// @Override
// public Integer get() {
// Random rand = new Random();
// return rand.nextInt(50);
// }
// };
// 아래의 코드가 위 주석처리 된 부분을 람다로 표현
Supplier<Integer> spr = () -> {
Random rand = new Random();
return rand.nextInt(50);
};
List<Integer> list = makeIntList(spr, 5);
System.out.println(list);
list = makeIntList(spr, 10);
System.out.println(list);
}
}
//[30, 5, 26, 47, 37]
//[19, 31, 4, 47, 43, 13, 22, 37, 24, 4]
Consumer
import java.util.function.Consumer;
class ConsumerDemo {
public static void main(String[] args) {
Consumer<String> c = s -> System.out.println(s);
c.accept("Pineapple"); // 출력이라는 결과를 보임
c.accept("Strawberry");
}
}
/*
Pineapple
Strawberry
*/
Function
package com.test.memo;
import java.util.function.Function;
public class Practice1 {
public static void main(String[] args) {
Function<String, Integer> f = s -> s.length();
// 위의 람다식이 아래의 익명 클래스를 내포한것
// Function<String, Integer> f = new Function<String, Integer>() {
//
// @Override
// public Integer apply(String t) {
// return t.length()
// }
// };
System.out.println(f.apply("Robot"));
System.out.println(f.apply("System"));
}
}
//5 6
import java.util.function.Function;
class FunctionDemo2 {
public static void main(String[] args) {
Function<Double, Double> cti = d -> d * 0.393701;
Function<Double, Double> itc = d -> d * 2.54;
System.out.println("1cm = " + cti.apply(1.0) + "inch"); // cm를 inch로
System.out.println("1inch = " + itc.apply(1.0) + "cm"); // inch를 cm로
}
}
/*
1cm = 0.393701inch
1inch = 2.54cm
*/
Predicate
import java.util.List;
import java.util.Arrays;
import java.util.function.IntPredicate;
class IntPredicateDemo {
public static int sum(IntPredicate ip, List<Integer> lst) {
int s = 0;
for(int n : lst) {
if(ip.test(n))
s += n;
}
return s;
}
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 5, 7, 9, 11, 12);
int s;
s = sum(n -> n%2 == 0, list);
System.out.println("짝수 합: " + s);
s = sum(n -> n%2 != 0, list);
System.out.println("홀수 합: " + s);
}
}
/*
짝수 합: 12
홀수 합: 33
*/
Supplier
import java.util.Random;
import java.util.List;
import java.util.ArrayList;
import java.util.function.IntSupplier;
class IntSupplierDemo {
public static List<Integer> makeIntList(IntSupplier is, int n) {
List<Integer> list = new ArrayList<>();
for(int i = 0; i < n; i++)
list.add(is.getAsInt());
return list;
}
public static void main(String[] args) {
IntSupplier ispr = () -> {
Random rand = new Random();
return rand.nextInt(50);
};
List<Integer> list = makeIntList(ispr, 5);
System.out.println(list);
list = makeIntList(ispr, 10);
System.out.println(list);
}
}
/*
[37, 47, 3, 20, 15]
[33, 8, 33, 43, 44, 49, 2, 47, 6, 38]
*/
IntSupplier int getAsInt()
LongSupplier long getAsLong()
DoubleSupplier double getAsDouble()
Boolean Supplier boolean getAsBoolean()
제네릭이 아닌 위와 같이 구체화한 인터페이스들이 더 성능이 좋다. > 사용법은 같다.
Consumer
import java.util.function.ObjIntConsumer;
class ObjIntConsumerDemo {
public static void main(String[] args) {
ObjIntConsumer<String> c = (s, i) -> System.out.println(i + ". " + s);
int n = 1;
c.accept("Toy", n++);
c.accept("Book", n++);
c.accept("Candy", n);
}
}
/*
1. Toy
2. Book
3. Candy
*/
IntConsumer void accept(int value)
LongConsumer void accept(long value)
DoubleConsumer void accept(double value)
BiConsumer<T, U> void accept(T t, U u)
Function
import java.util.function.ToIntFunction;
class ToIntFunctionDemo {
public static void main(String[] args) {
ToIntFunction<String> f = s -> s.length();
System.out.println(f.applyAsInt("Robot"));
System.out.println(f.applyAsInt("System"));
}
}
/*
5
6
*/
IntToDoubleFunction double applyAsDouble(int value)
DoubleUnaryOperator double applyAsDouble(double operand)
Function<T, R>에서 T와 R을 모두 기본 자료형으로 결정하여 정의한
인터페이스들
BiFunction\<T, U, R> R apply(T t, U u)
IntFunction\ R apply(int value)
DoubleFunction\ R apply(double value)
ToIntFunction\ int applyAsInt(T value)
ToDoubleFunction\ double applyAsDouble(T value)
ToIntBiFunction\<T, U> int applyAsInt(T t, U u)
ToDoubleBiFunction\<T, U> double applyAsDouble(T t, U u)
Function<T, R>에 위치한 추상 메소드의 매개변수 선언과 반환형을 다양화 한 것들
import java.util.function.DoubleUnaryOperator;
class DoubleUnaryOperatorDemo {
public static void main(String[] args) {
DoubleUnaryOperator cti = d -> d * 0.393701;
DoubleUnaryOperator itc = d -> d * 2.54;
System.out.println("1cm = " + cti.applyAsDouble(1.0) + "inch");
System.out.println("1inch = " + itc.applyAsDouble(1.0) + "cm");
}
}
/*
1cm = 0.393701inch
1inch = 2.54cm
*/
interface Calculate{
T cal(T a, T b);
}
public class CalculatorDemo {
public static void calAndShow(Calculate op, T n1, T n2) {
T r = op.cal(n1, n2);
System.out.println(r);
}
public static void main(String[] args) {
// 3 + 4
// 2.5 + 7.1
// 4 - 2
// 4.9 - 3.2
}
}
package com.test.memo;
interface Calculate<T> {
T cal(T a, T b);
}
public class Practice1 {
public static <T> void calAndShow(Calculate<T> op, T n1, T n2) {
T r = op.cal(n1, n2);
System.out.println(r);
}
public static void main(String[] args) {
// Calculate<Integer> c1 = (a, b) -> a + b;
// calAndShow(c1, a, null);
calAndShow((a, b) -> a + b, 3, 4);
calAndShow((a, b) -> a + b, 2.5, 7.1);
calAndShow((a, b) -> a - b, 4, 2);
calAndShow((a, b) -> a - b, 4.9, 3.2);
}
}
package com.test.memo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
//class SLenComp implements Comparator<String> {
// @Override
// public int compare(String s1, String s2) {
// return s1.length() - s2.length();
// }
//}
public class Practice1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Robot");
list.add("Lambda");
list.add("Box");
// Collections.sort(list, new SLenComp()); // 정렬
Collections.sort(list, (s1, s2) -> s1.length() - s2.length());
for (String s : list)
System.out.println(s);
}
}
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class PredicateShow {
public static void show(Predicate p, List lst) {
// 채워 넣을 부분
}
public static void main(String[] args) {
List lst1 = Arrays.asList(1, 3, 8, 10, 11);
show(n->n%2!= 0, lst1); // 홀수만 출력
List lst2 = Arrays.asList(-1.2, 3.5, -2.4, 9.5);
show(n->n>0.0, lst2); // 0.0 보다 큰 수 출력
}
}
package com.test.memo;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Practice1 {
public static <T> void show(Predicate<T> p, List<T> lst) {
// for(T n : lst) {
// if((int)n % 2 != 0) {
// System.out.println(n);
// }
// } 내가 풀다 만것
for (T n : lst) {
if (p.test(n)) //각 객체의 test()메소드를 호출해 안에있는 값 반환받아서
System.out.println(n);
}
}
public static void main(String[] args) {
List<Integer> lst1 = Arrays.asList(1, 3, 8, 10, 11);
show(n -> n % 2 != 0, lst1); // 홀수만 출력
//위 Predicate<T> p 에 아래 메서드가 들어가는것이다. > 람다로 그렇제 정의해놨으니까
//Predicate<Integer> p = new Predicate<Integer>() {
//@Override
// public boolean test(Integer t) { //홀수인지 아닌지
// return t % 2 != 0;
//}
//};
List<Double> lst2 = Arrays.asList(-1.2, 3.5, -2.4, 9.5);
show(n -> n > 0.0, lst2); // 0.0 보다 큰 수 출력
//마찬가지로 위 show 인자의 p를 람다로 정의했기에 아래 코드의 형태로 작성되어 p에 들어간것이다.
//Predicate<Double> p2 = new Predicate<Double>() {
//@Override
//public boolean test(Double t) {
//return t > 0;
//}
//};
}
}
//1
//3
//11
//3.5
//9.5
아래 코드가 정상적으로 동작하도록 '완성되지 않은 문장'을 완성해보자. 어떠한 내용을 담아야 할지는 주석의 내용을 참조하여 판단하자
[BiPredicate\<T, U>]
람다로
package com.test.memo;
import java.util.function.BiPredicate;
public class Practice1 {
public static void main(String[] args) {
BiPredicate<String, Integer> conv = (s, i) -> {
if (s.length() > i) {
return true;
}
return false;
};
// test 호출 결과 문자열 "Robot"의 길이가 3을 넘으면 true 반환
if (conv.test("Robot", 3))
System.out.println("문자열 길이 3 초과");
else
System.out.println("문자열 길이 3 이하");
// test 호출 결과 문자열 "Box"의 길이가 5를 넘으면 true 반환
if (conv.test("Box", 5))
System.out.println("문자열 길이 5 초과");
else
System.out.println("문자열 길이 5 이하");
}
}
//문자열 길이 3 초과
//문자열 길이 5 이하
익명 클래스로
package com.test.memo;
import java.util.function.BiPredicate;
public class Practice1 {
public static void main(String[] args) {
BiPredicate<String, Integer> conv = new BiPredicate<String, Integer>() {
@Override
public boolean test(String t, Integer u) {
if (t.length() > u)
return true;
return false;
}
};
// test 호출 결과 문자열 "Robot"의 길이가 3을 넘으면 true 반환
if (conv.test("Robot", 3))
System.out.println("문자열 길이 3 초과");
else
System.out.println("문자열 길이 3 이하");
// test 호출 결과 문자열 "Box"의 길이가 5를 넘으면 true 반환
if (conv.test("Box", 5))
System.out.println("문자열 길이 5 초과");
else
System.out.println("문자열 길이 5 이하");
}
}
package com.test.memo;
import java.util.function.BiConsumer;
import java.util.function.ObjIntConsumer;
class Box<T> {
private T ob;
public void set(T o) {
ob = o;
}
public T get() {
return ob;
}
}
public class Practice1 {
public static void main(String[] args) {
// Box<Integer> box = new Box<>();
// ObjIntConsumer<Integer> o = (s, i) -> box.set(i);
BiConsumer<Box<Integer>, Integer> c1 = (b, i) -> b.set(i);
BiConsumer<Box<Double>, Double> c2 = (b, i) -> b.set(i);
Box<Integer> bi = new Box<>();
Box<Double> bd = new Box<>();
c1.accept(bi, 10);
c2.accept(bd, 10.45);
System.out.println(bi.get());
System.out.println(bd.get());
}
}

package com.test.memo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Practice1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Robot");
list.add("Lambda");
list.add("Box");
Collections.sort(list, (str1, str2) -> Integer.compare(str1.length(), str2.length())); // 정렬
//
for (String s : list)
System.out.println(s);
}
}
//Box
//Robot
//Lambda

package com.test.memo;
interface Printable {
void print(String s); // 매개변수 하나, 반환형 void
}
public class Practice1 {
public static void main(String[] args) {
Printable p = s -> System.out.println(s);
p.print("Lambda exp one.");
}
}
//Lambda exp one.

package com.test.memo;
interface Calculate {
void cal(int a, int b); // 매개변수 둘, 반환형 void
}
public class Practice1 {
public static void main(String[] args) {
Calculate c;
c = (a, b) -> System.out.println(a + b);
c.cal(4, 3);
c = (a, b) -> System.out.println(a - b);
c.cal(4, 3);
c = (a, b) -> System.out.println(a * b);
c.cal(4, 3);
}
}
//7 1 12

package com.test.memo;
interface Calculate {
int cal(int a, int b); // 매개변수 둘, 반환형 void
}
public class Practice1 {
public static void main(String[] args) {
Calculate c;
c = (a, b) -> {
return a + b;
};
System.out.println(c.cal(4, 3));
}
}
//7

package com.test.memo;
interface HowLong {
int len(String s); // 값을 반환하는 메소드
}
public class Practice1 {
public static void main(String[] args) {
HowLong hl = s -> {
return s.length();
};
System.out.println(hl.len("I am so happy"));
}
}
//13
함수형 인터페이스에 대해 설명하고 그 예시를 드시오.
함수형 인터페이스란 단, 하나의 추상 메서드만을 가지는 인터페이스다.
@Functionallnterface 애노테이션을 명시할 수 있고, 람다식으로 구현할 수 있다.
6-1 . 0 부터 49사이의 난수를 발생시키는 람다식을 작성하시오.
package com.test.memo;
interface Random {
int ran(); // 매개변수 없는 메서드
}
public class Practice1 {
public static void main(String[] args) {
Random ran = () -> {
return (int) (Math.random() * 50);
};
System.out.println(ran.ran());
}
}
//0~49사이 난수 하나 출력
다음 소스코드와 출력결과를 참고하여 함수형 인터페이스를 작성하시오.
7
7.7700000000000005

package com.test.memo;
interface Calculate<T> {// int와 double이 모두 올 수 있도록 제네릭 타입 형태로
T cal(T a, T b);
}
public class Practi//ce1 {
public static void main(String[] args) {
Calculate<Integer> ci = (a, b) -> a + b;
System.out.println(ci.cal(4, 3));
Calculate<Double> cd = (a, b) -> a + b;
System.out.println(cd.cal(4.32, 3.45));
}
}
//7
//7.7700000000000005
7-1 .
문제 1. 아래 코드에서 주석에 명시된 연산의 결과를 출력하기 위한 calAndShow 메소드의 호출문을 람다식을 기반으로 작성해보자.

package com.test.memo;
interface Calculate<T> {// int와 double이 모두 올 수 있도록 제네릭 타입 형태로
T cal(T a, T b);
}
public class Practice1 {
public static <T> void calAndShow(Calculate<T> op, T n1, T n2) {
T r = op.cal(n1, n2);
System.out.println(r);
}
public static void main(String[] args) {
calAndShow((a, b) -> a + b, 3, 4);
calAndShow((a, b) -> a + b, 2.5, 7.1);
calAndShow((a, b) -> a - b, 4, 2);
calAndShow((a, b) -> a - b, 4.9, 3.2);
}
}
//7
//9.6
//2
//1.7000000000000002
문제 2. SLenComparator.java를 람다식 기반으로 수정해보자. 수정 결과에서는 클래스 SLenComp의 정의가 지워져야 한다.

package com.test.memo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
//class SLenComp implements Comparator<String> {
// @Override
// public int compare(String s1, String s2) {
// return s1.length() - s2.length();
// }
//}
public class Practice1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Robot");
list.add("Lambda");
list.add("Box");
Collections.sort(list, (s1, s2) -> s1.length() - s2.length()); // 정렬
for (String s : list)
System.out.println(s);
}
}
//Box
//Robot
//Lambda
java.util.function 패키지로 묶여있다.
| 함수형 인터페이스 | 추상 메소드 |
|---|---|
| Predicate\ | boolean test(T t) |
| Supplier\ | T get() |
| Consumer\ | void accept(T t) |
| Function\<T, R> | R apply(T t) |
매개 변수가 두 개인 함수형 인터페이스
매개변수의 타입으로 보통 'T'를 사용하므로, 알파벳에서 'T'의 다음 문자인 'U', 'V', 'W'를 매개변수의 타입으로 사용하는 것일 뿐 별다른 의미X
| 함수형 인터페이스 | 추상 메소드 |
|---|---|
| BiPredicate\<T, U> | boolean test(T t, U u) |
| BiConsumer\<T, U> | void accept(T t, U u) |
| BiFunction\<T, U, R> | R apply(T t, U u) |
Supplier는 매개변수는 없고 반환값만 존재하는데, 메서드는 두 개의 값을 반환할 수 없으므로 BiSupplier가 없는 것이다.
두 개 이상의 매개변수를 갖는 함수형 인터페이스
2개 이상이 필요하다면, 직접 만들어서 써야한다.
ex) 만일 3개의 매개변수를 갖는 함수형 인터페이스를 선언한다면 아래와 같다.
@FunctionalINterface
interface TriFunction<T, U, V, R> {
R apply(T t, U u, V v);
}
UnaryOperator / BinaryOperator Function
UnaryOperator와 BinaryOperator의 조상은 각각 Function과BiFunction이다.
메소드 - apply()
8-1 . 다음 출력결과를 참고하여 람다식과 sum 메소드를 완성하시오.
짝수 합: 12
홀수 합: 33

package com.test.memo;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Practice1 {
public static int sum(Predicate<Integer> p, List<Integer> lst) {
int s = 0;
for (int n : lst) {
if (p.test(n)) {
s += n;
}
}
return s;
}
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 5, 7, 9, 11, 12);
int s;
s = sum(n -> n % 2 == 0, list);
System.out.println("짝수 합: " + s);
s = sum(i -> i % 2 != 0, list);
System.out.println("홀수 합: " + s);
}
}
//짝수 합: 12
//홀수 합: 33
8-2. 아래의 코드에서 주석으로 표시된 내용의 출력을 보이도록 show 메소드의 몸체를 채워 보자.

package com.test.memo;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Practice1 {
public static <T> void show(Predicate<T> p, List<T> lst) {
for (T t : lst) {
if (p.test(t)) { // 해당 람다 결과값 boolean으로 반환
System.out.print(t + " ");
}
}
System.out.println();
}
public static void main(String[] args) {
List<Integer> lst1 = Arrays.asList(1, 3, 8, 10, 11);
show(n -> n % 2 != 0, lst1); // 홀수만 출력
List<Double> lst2 = Arrays.asList(-1.2, 3.5, -2.4, 9.5);
show(n -> n > 0.0, lst2); // 0.0 보다 큰 수 출력
}
}
8-1을 IntPredicate로 구현해보자. 보충설명하자면 sum 메소드의 원형을 다음 형태로 해라.
package com.test.memo;
import java.util.Arrays;
import java.util.List;
import java.util.function.IntPredicate;
public class Practice1 {
public static int sum(IntPredicate ip, List<Integer> lst) {
int s = 0;
for (int n : lst) {
if (ip.test(n)) {
s += n;
}
}
return s;
}
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 5, 7, 9, 11, 12);
int s;
s = sum(n -> n % 2 == 0, list);
System.out.println("짝수 합: " + s);
s = sum(i -> i % 2 != 0, list);
System.out.println("홀수 합: " + s);
}
}
9-1. [BiPredicate\<T, U>]
아래 코드가 정상적으로 동작하도록 '완성되지 않은 문장'을 완성해보자. 어떠한 내용을 담아야 할지는 주석의 내용을 참조하여 판단하자.

package com.test.memo;
import java.util.function.BiPredicate;
public class Practice1 {
public static void main(String[] args) {
BiPredicate<String, Integer> conv = (s, i) -> s.length() > i;
// test 호출 결과 문자열 "Robot"의 길이가 3을 넘으면 true 반환
if (conv.test("Robot", 3))
System.out.println("문자열 길이 3 초과");
else
System.out.println("문자열 길이 3 이하");
// test 호출 결과 문자열 "Box"의 길이가 5를 넘으면 true 반환
if (conv.test("Box", 5))
System.out.println("문자열 길이 5 초과");
else
System.out.println("문자열 길이 5 이하");
}
}
//문자열 길이 3 초과
//문자열 길이 5 이하
[25, 42, 43, 23, 18][49, 44, 32, 5, 2, 0, 44, 36, 20, 41]

package com.test.memo;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
public class Practice1 {
public static List<Integer> makeIntList(Supplier<Integer> s, int n) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < n; i++)
list.add(s.get());
return list;
}
public static void main(String[] args) {
Supplier<Integer> spr = () -> {
return (int) (Math.random() * 50);
};
List<Integer> list = makeIntList(spr, 5);
System.out.println(list);
list = makeIntList(spr, 10);
System.out.println(list);
}
}
//[5, 37, 40, 47, 15]
//[45, 31, 10, 22, 46, 12, 48, 22, 13, 39]
10번의 makeIntList의 메소드 원형을 다음과 같이 바꿔서 구현하자.
public static List\ makeIntList(IntSupplier is, int n) {}
메서드 : int getAsInt()
package com.test.memo;
import java.util.ArrayList;
import java.util.List;
import java.util.function.IntSupplier;
public class Practice1 {
public static List<Integer> makeIntList(IntSupplier is, int n) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < n; i++)
list.add(is.getAsInt());
return list;
}
public static void main(String[] args) {
IntSupplier spr = () -> {
return (int) (Math.random() * 50);
};
List<Integer> list = makeIntList(spr, 5);
System.out.println(list);
list = makeIntList(spr, 10);
System.out.println(list);
}
}
//[5, 37, 40, 47, 15] 계속 다르게 난수 발생
//[45, 31, 10, 22, 46, 12, 48, 22, 13, 39]
다음 출력결과를 보고 다음 람다식을 완성하시오.
Pineapple
Strawberry
package com.test.memo;
import java.util.function.Consumer;
public class Practice1 {
public static void main(String[] args) {
Consumer<String> c = s -> System.out.println(s);
c.accept("Pineapple");
c.accept("Strawberry");
}
}
//Pineapple
//Strawberry
출력결과가 다음과 같이 나오도록 람다식을 작성하시오.
Toy
Book
Candy
package com.test.memo;
import java.util.function.ObjIntConsumer;
public class Practice1 {
public static void main(String[] args) {
ObjIntConsumer<String> c = (s, i) -> System.out.println(i + ". " + s);
int n = 1;
c.accept("Toy", n++);
c.accept("Book", n++);
c.accept("Candy", n++);
}
}
//1. Toy
//2. Book
//3. Candy
13-1. [BiConsumer\<T, U>]
인터페이스 BiConsumer\<T, U>를 기반으로 아래 클래스의 인스턴스에 int형, double형 데이터를 저장하는 기능의 람다식을 각각 작성하고, 이를 확인하기 위한 예제를 작성해보자.
class Box{
private T ob;
public void set(T o) { ob = o; }
public T get() { return ob;}
}
package com.test.memo;
import java.util.function.BiConsumer;
class Box<T> {
private T ob;
public void set(T o) {
ob = o;
}
public T get() {
return ob;
}
}
public class Practice1 {
public static void main(String[] args) {
BiConsumer<Box<Integer>, Integer> bc1 = (b, i) -> b.set(i);
BiConsumer<Box<Double>, Double> bc2 = (b, i) -> b.set(i);
Box<Integer> bi = new Box<>();
Box<Double> bd = new Box<>();
bc1.accept(bi, 10);
bc2.accept(bd, 10.55);
System.out.println(bi.get());
System.out.println(bd.get());
}
}
//10
//10.55

package com.test.memo;
import java.util.function.Function;
public class Practice1 {
public static void main(String[] args) {
Function<String, Integer> f = s -> s.length();
System.out.println(f.apply("Robot"));
System.out.println(f.apply("System"));
}
}
//5
//6

package com.test.memo;
import java.util.function.Function;
public class Practice1 {
public static void main(String[] args) {
Function<Double, Double> cti = d -> d * 0.393701;
Function<Double, Double> itc = d -> d * 2.54;
System.out.println("1cm = " + cti.apply(1.0) + "inch"); // cm를 inch로
System.out.println("1inch = " + itc.apply(1.0) + "cm"); // inch를 cm로
}
}
//1cm = 0.393701inch
//1inch = 2.54cm

package com.test.memo;
import java.util.function.ToIntFunction;
public class Practice1 {
public static void main(String[] args) {
ToIntFunction<String> f = s -> s.length();
System.out.println(f.applyAsInt("Robot"));
System.out.println(f.applyAsInt("System"));
}
}
//5
//6

package com.test.memo;
import java.util.function.DoubleUnaryOperator;
public class Practice1 {
public static void main(String[] args) {
DoubleUnaryOperator cti = i -> i * 0.393701;
DoubleUnaryOperator itc = i -> i * 2.54;
System.out.println("1cm = " + cti.applyAsDouble(1.0) + "inch");
System.out.println("1inch = " + itc.applyAsDouble(1.0) + "cm");
}
}
//1cm = 0.393701inch
//1inch = 2.54cm

package com.test.memo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Practice1 {
public static void main(String[] args) {
List<Integer> ls1 = Arrays.asList(1, -2, 3, -4, 5);
ls1 = new ArrayList<>(ls1);
List<Double> ls2 = Arrays.asList(-1.1, 2.2, 3.3, -4.4, 5.5);
ls2 = new ArrayList<>(ls2);
Predicate<Number> p = n -> n.doubleValue() < 0.0; // 0보다 작으면 삭제
// 람다식
ls1.removeIf(p);
ls2.removeIf(p);
System.out.println(ls1);
System.out.println(ls2);
}
}
//[1, 3, 5]
//[2.2, 3.3, 5.5]
람다식으로 줄어든 코드의 양을 조금 더 줄일 수 있게 한다
메소드 참조의 4가지 유형과 메소드 참조의 장점
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
class ArrangeList {
public static void main(String[] args) {
List<Integer> ls = Arrays.asList(1, 3, 5, 7, 9);
ls = new ArrayList<>(ls);
Consumer<List<Integer>> c = l -> Collections.reverse(l); // 람다식
Consumer<List<Integer>> c = new Consumer<List<Integer>>(){ //위 람다식을 익명클래스로 해놓은거
@Override
public void accept(List<Integer> l){
Collections.reverse(1); //순서를 뒤집기
}
};
c.accept(ls); // 순서 뒤집기 기능을 accept안에 넣어 실행
System.out.println(ls); // 출력
}
}
// Consumer<T> void accept(T t)
// static 메소드의 참조
//[9, 7, 5, 3, 1]
Consumer<List<Integer>> c = Collections::reverse;
ClassName::staticMethodName > static 메서드의 참조 방법으로 :: 은 메소드 참조를 의미하는 연산자다.
메소드 참조를 기반으로 람다식으로 가능하다.
Consumer<List<integer>> c = l -> Collections.reverse(l);
Consumer<List<Integer>> c = Collections::reverse;
accept 메소드 호출 시 전달되는 인자를 reverse 메소드를 호출하면서 그대로 전달한다.
예제 2
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
class JustSort {
public void sort(List<?> lst) { // 인스턴스 메소드
Collections.reverse(lst);
}
}
class ArrangeList3 {
public static void main(String[] args) {
List<Integer> ls = Arrays.asList(1, 3, 5, 7, 9);
ls = new ArrayList<>(ls);
JustSort js = new JustSort();
//람다식에서 같은 지역내에서 선언된 참조변수 js 에 접근하고 있다.
Consumer<List<Integer>> c = e -> js.sort(e);
// Consumer<List<Integer>> c = js::sort; 이렇게 메소드 참조고 대신할 수 있다.
c.accept(ls);
System.out.println(ls);
}
}
//[9, 7, 5, 3, 1]
/*
람다식에서 같은 지역 내에 선언된 참조변수 js에 접근하고 있다. > 람다식은 본래 인스턴스의 생성으로 이어진다는 사실을 고려하면 다소 특이
람다식에서 같은 지역에 선언된 참조변수에 접근하는 것은 가능하다.
effectively final : 사실상 final 선언이 된 것과 같음 > 값 변경 불가능
public static void main(String[] args) { ... JustSort js = new JustSort(); js = new JustSort(); // 다른 인스턴스를 참조하게 했다. Consumer<List<Integer>> c = l -> js.sort(l); ... js = null;
위 코드처럼 작성한다면 컴파일 오류가 일어난다. > js가 effectively final이 아니기 때문이다. > 주소값이 변경되면 안된다.
ReferenceName::instanceMethodName : 인스턴스 메소드는 :: 을 이용해 참조 가능하다.
예제 2-1
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
class JustSort {
public void sort(List<?> lst) { // 인스턴스 메소드
Collections.reverse(lst);
}
}
class ArrangeList4 {
public static void main(String[] args) {
List<Integer> ls = Arrays.asList(1, 3, 5, 7, 9);
ls = new ArrayList<>(ls);
JustSort js = new JustSort();
Consumer<List<Integer>> c = js::sort; // 메소드 참조 기반
c.accept(ls);
System.out.println(ls);
}
}
예제 3
import java.util.List;
import java.util.Arrays;
class ForEachDemo {
public static void main(String[] args) {
List<String> ls = Arrays.asList("Box", "Robot");
// 람다식 기반
ls.forEach(s -> System.out.println(s));
// 메소드 참조 기반
ls.forEach(System.out::println);
}
}
Collection인터페이스는 Iterable를 상속해, 컬렉션 클래스들은 대부분 Iterable을 구현하게 되는데, 이 인터페이스에는 디폴트 메소드가 정의되어 있다.
default void forEach(Consumer<? super T> action) {
for(T t: this) // this는 이 메소드가 속한 컬렉션 인스턴스를 의미함
action.accept(t); // 모든 저장된 데이터들에 대해 이 문장 반복
}즉, 위의 메소드가 호출되면 컬렉션 인스턴스에 저장되어 있는 모든 인스턴스들을 대상으로
action.accept(t);가 실행되게 된다. > t는 저장되어있는 인스턴스 각각을 의미
forEach 문의 호출은, 람다식 또는 메소드 참조를 토앻 진행할 수 있다.
예제 4
ToIntBiFunction <> applyAsInt(); 메서드 존재
import java.util.function.ToIntBiFunction;
class IBox {
private int n;
public IBox(int i) { n = i; }
public int larger(IBox b) {
if(n > b.n)
return n;
else
return b.n;
}
}
class NoObjectMethodRef {
public static void main(String[] args) {
IBox ib1 = new IBox(5);
IBox ib2 = new IBox(7);
//첫 번째 인자로 전달된 인스턴스의 메소드
// 두 상자에 저장된 값 비교하여 더 큰 값 반환
ToIntBiFunction<IBox, IBox> bf = (b1, b2) -> b1.larger(b2); //applyAsInt()메서드의 정의를 람다로
// > ToIntBiFunction<IBox, IBox> bf = IBox::larger; 메소드 참조 방식으로 한다면 이렇게
int bigNum = bf.applyAsInt(ib1, ib2);
System.out.println(bigNum);}
}
// 7
ClassName::instanceMethodName > 메소드 참조 방식 예제 4-1
import java.util.function.ToIntBiFunction;
class IBox {
private int n;
public IBox(int i) { n = i; }
public int larger(IBox b) {
if(n > b.n)
return n;
else
return b.n;
}
}
class NoObjectMethodRef2 {
public static void main(String[] args) {
IBox ib1 = new IBox(5);
IBox ib2 = new IBox(7);
// 두 상자에 저장된 값 비교하여 더 큰 값 반환
ToIntBiFunction<IBox, IBox> bf = IBox::larger;
int bigNum = bf.applyAsInt(ib1, ib2);
System.out.println(bigNum);}
}
// 7
// ToIntBiFunction<T, U> int applyAsInt(T t, U u)
예제 5
interface SMaker {
String make(char[] ar);
}
class StringMaker {
public static String chsToString(char[] a, SMaker m) {
return m.make(a);
}
public static void main(String[] args) {
//Function<char[], String> f = ar -> new String(ar); String생성자를 이용해 반환
//Function<char[], String> f = String::new; // 생성자 참조 방식
SMaker sm = (ar) -> {
return new String(ar);
};
char[] src = {'R', 'o', 'b', 'o', 't'};
String str = chsToString(src, sm);
System.out.println(str);
}
}
//Robot
// Function<T, R> R apply(T t)
public static void main(String[] args){
Function<char[], String> f = String::new;
...
String str = f.apply(src);
...
}
f의 참조 대상이 String::new이므로, f는 String의 생성자를 참조하게 되는데, 참조변수 f의 자료형이 Function<char[], String>이므로 매개변수 형이 char[]인 아래의 생성자를 참조하게 된다.
public String(char[] value)
String str = f.apply(src);apply(src) {
new String(src);
}//메소드 정의가 아닌 apply()가 호출될 때 실행되는 내용
예제 5-1
import java.util.function.Function;
class StringMaker2 {
public static void main(String[] args) {
Function<char[], String> f = String::new;
char[] src = {'R', 'o', 'b', 'o', 't'};
String str = f.apply(src);
System.out.println(str);
}
}
// Function<T, R> R apply(T t)

package com.test.memo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Practice1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("robot");
list.add("Lambda");
list.add("box");
// Comparator<String> c = (s1, s2) -> s1.compareToIgnoreCase(s2);
Collections.sort(list, String::compareToIgnoreCase);
System.out.println(list);
}
}
//[box, Lambda, robot]

package com.test.memo;
import java.util.function.BiFunction;
class Box<T, U> {
private T id;
private U con;
public Box(T i, U c) {
id = i;
con = c;
}
public void showIt() {
System.out.println("ID: " + id + ", " + "Contents: " + con);
}
}
public class Practice1 {
public static void main(String[] args) {
// 채워 넣어야 할 문장, 참조변수 bf의 선언
// 익명클래스
// BiFunction<Integer, String, Box<Integer, String>> bf = new BiFunction<Integer, String, Box<Integer,String>>() {
// //들어가는 부분
// @Override
// public Box<Integer, String> apply(Integer t, String u) {
// return new Box<Integer, String>(t, u);
// }
// };
// 람다식으로
// BiFunction<Integer, String, Box<Integer, String>> bf = (t, u) -> new Box<Integer, String >(t, u);
// 생성자 참조로
BiFunction<Integer, String, Box<Integer, String>> bf = Box::new;
Box<Integer, String> b1 = bf.apply(1, "Toy"); // 1과 "Toy" 저장된 상자 반환
Box<Integer, String> b2 = bf.apply(2, "Robot"); // 2와 "Robot" 저장된 상자 반환
b1.showIt();
b2.showIt();
}
}
//ID: 1, Contents: Toy
//ID: 2, Contents: Robot
암기
| 함수형 인터페이스 | 추상 메소드 |
|---|---|
| Predicate\ | boolean test(T t) |
| Supplier\ | T get() |
| Consumer\ | void accept(T t) |
| Function\<T, R> | R apply(T t) |
[매개변수가 두개]
| 함수형 인터페이스 | 추상 메소드 |
|---|---|
| BiPredicate\<T, U> | boolean test(T t, U u) |
| BiConsumer\<T, U> | void accept(T t, U u) |
| BiFunction\<T, U, R> | R apply(T t, U u) |