인터페이스<타입> 객체명 = 매개변수 -> { 코드작성 };
함수형 인터페이스 작성 예시
// 람다식을 쓰려면 functional interface (자바의 람다식은 함수형 인터페이스로만 사용한다)
@FunctionalInterface
public interface Test {
void run(); // 추상 메서드 run을 생성 => 생성해주면 함수형 인터페이스 조건을 만족함
// void run2(); // 함수형 인터페이스는 '하나'의 추상메서드만 가진 인터페이스임
}
메서드를 사용해 작성한 코드를 람다식으로 바꾼 예시
public class App {
public static void main(String[] args) {
// 문자열 array list 생성
List<String> list = new ArrayList<>();
list.add("하나");
list.add("둘");
list.add("셋");
list.forEach(new Consumer<String>() {
// Consumer 인터페이스(추상 메서드)를 익명 클래스에서 구현해야 함
@Override
public void accept(String t) {
// 익명 클래스에서 구현
System.out.print(t + "\t");
}
});
System.out.println();
// 익명 클래스를 람다식으로 변경
list.forEach(t -> System.out.print(t + "\t"));
}
}
매개변수 자리에 () 만 써줌. ()는 생략불가.
interface Runner {
void execute(); // 추상메서드 1개 => 람다식 사용가능
}
public class App2 {
public static void main(String[] args) {
// Runner run = () -> {}; 기본형태. 코드가 한줄이면 코드블럭{} 생략가능
Runner run = () -> {
System.out.println("헬로우!");
System.out.println("람다식");
};
run.execute();
System.out.println(run instanceof Runner); // run은 Runner의 객체인가? 맞으면 true
System.out.println(run.getClass()); // run의 클래스는 람다식
}
}
()생략가능.
interface Runner {
void execute(String t); // 추상 메서드에 매개변수가 있는 경우
}
public class App {
public static void main(String[] args) {
// 매개변수가 있는 경우
Runner run1 = (s) -> System.out.println(s);
run1.execute("펭수");
Runner run2 = x -> System.out.println(x); // 매개변수가 1개일때 ()생략가능. 없을땐 생략불가이므로 주의
run2.execute("길동");
}
}
매개변수 자리에 2개 이상을 차례로 작성하면 됨.
아래 예시의 (n, t) 가 매개변수임.
interface Runner {
void execute(String name, String text); // 추상 메서드에 매개변수가 있는 경우
}
public class App {
public static void main(String[] args) {
// 매개변수가 있는 경우
Runner run1 = (n, t) -> System.out.printf("%s님 %s\n", n, t);
run1.execute("펭수", "안녕하세요");
greet(run1); // 메소드로 사용
}
private static void greet(Runner run1) {
run1.execute("길동", "건강하세요");
}
}
코드가 한 줄일때 return생략가능.
interface Joiner {
String join(String text1, String text2); // 추상 메서드에 리턴, 매개변수가 있는 경우
}
public class App {
public static void main(String[] args) {
// 리턴값이 있는 경우
Joiner joiner = (t1, t2) -> {
String text = t1 + " - " + t2;
return text;
};
System.out.println(joiner.join("치킨", "맥주"));
System.out.println(joiner.join("학원", "공부"));
Joiner joiner2 = (s1, s2) -> s1 + " + " + s2; // 코드가 한 줄일 때 return도 생략가능
System.out.println(joiner2.join("학원", "공부"));
System.out.println(joiner2.join("치킨", "맥주"));
}
}
public class RemoveIf {
public static void main(String[] args) {
// 특정 타입(제네릭)을 검사해서 참, 거짓을 리턴
List<Integer> numbers = new ArrayList<>();
numbers.add(3);
numbers.add(5);
numbers.add(7);
numbers.add(2);
numbers.add(9);
numbers.add(10);
numbers.add(4);
numbers.forEach(t -> System.out.print(t + "\t")); // numbers의 원소를 차례로 모두 출력
System.out.printf("\n\n");
// 리스트 numbers 안에 있는 정수들 중 6보다 작으면 모두 제거
// removeIf(매개변수 -> 조건) : predicate로 검사(test)해서 참이면 다 제거
// numbers.removeIf(new Predicate<Integer>() {
// public boolean test(Integer i) {
// return i < 6; // 정수가 6보다 작으면 참
// }
// });
// 23~27행을 이렇게 간단히 표현가능
numbers.removeIf(i -> i < 6);
numbers.forEach(x -> System.out.println(x)); // numbers의 원소를 차례로 모두 출력
System.out.println();
List<String> sList = new ArrayList<>();
sList.add("하나둘");
sList.add("둘셋넷");
sList.add("셋둘하나");
sList.add("여섯일곱여덟");
sList.add("다섯넷셋");
sList.add("하나둘셋");
// 문자열의 길이가 4보다 작으면 모두 제거
sList.removeIf(s -> s.length() < 4); // 문자열의 길이가 4보다 작으면 참. 참이면 제거
sList.forEach(s -> System.out.println(s)); // sList 원소 모두 출력
}
}
public class ReplaceAll {
public static void main(String[] args) {
// ReplaceAll : 각각의 값을 리턴된 값으로 바꿔줌
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(3);
numbers.add(4);
numbers.add(7);
numbers.add(2);
numbers.forEach(n -> System.out.print(n + "\t"));
System.out.printf("\n\n");
// numbers.replaceAll(new UnaryOperator<Integer> (){
// public Integer apply(Integer n) {
// return n * n;
// }
// });
// 20~24행을 람다식으로 바꿔 줄임
numbers.replaceAll(n -> n * n);
numbers.forEach(n -> System.out.printf(n + "\t"));
System.out.println();
// 문자열의 경우
List<String> friends = new ArrayList<>();
friends.add("길동");
friends.add("메리");
friends.add("철수");
friends.add("영식");
friends.forEach(s -> System.out.println(s));
friends.replaceAll(s -> "안녕~ " + s);
friends.forEach(s -> System.out.println(s));
public class App {
public static void main(String[] args) {
// 연습문제
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(5);
list.add(9);
list.add(1000);
list.add(3);
list.add(6);
list.add(-20);
list.add(4);
// 1) 0 ~ 10이 아닌 값들은 모두 제거
System.out.printf("\n\n");
// 2) 각 아이템들에 + 100
// 3) 출력하여 확인
}
}
풀어본것
public class App {
public static void main(String[] args) {
/* 연습문제
* 0 ~ 10이 아닌 값들은 모두 제거
* 그 다음, 각 아이템들에 +100을 한다
* 그 결과를 콘솔에 표시
*/
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(5);
list.add(9);
list.add(1000);
list.add(3);
list.add(6);
list.add(-20);
list.add(4);
// 1) 0 ~ 10이 아닌 값들은 모두 제거
list.removeIf(i -> (i <= 0 || i >= 10)); // true를 반환한 아이템을 삭제하므로 주의
list.forEach(i -> System.out.print(i + "\t"));
System.out.printf("\n\n");
// 2) 각 아이템들에 + 100
list.replaceAll(e -> e + 100);
list.forEach(e -> System.out.print(e + "\t"));
}
}
예제 1
public class App {
public static void main(String[] args) {
// 멀티 쓰레드
Runnable runnable = () -> {
for (int i = 0; i < 100; i++) {
System.out.println("i : " + i);
try {
Thread.sleep(500); // 0.5초 대기
} catch (Exception e) {
e.printStackTrace();
}
}
};
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
t1.start();
t2.start();
// t1과 t2가 동시에 한번씩 출력됨
}
}
0.5초에 한 번씩 t1과 t2가 출력됨
예제 2
public class App {
private int value = 0;
public void run() throws InterruptedException {
Runnable runnable = () -> {
for (int i = 0; i < 200; i++) {
value++;
}
};
Thread t1 = new Thread(runnable); // 새 스레드 t1 생성
Thread t2 = new Thread(runnable); // 새 스레드 t2 생성
t1.start(); // t1을 실행
t2.start(); // t2를 실행
System.out.println("Value: " + value);
// t1, t2 스레드의 실행보다 메인스레드의 실행이 빠르면 value의 값이 0 혹은 400보다 적게나옴
// 고로 컴퓨터의 성능이 느릴 경우 메인스레드의 실행이 t1, t2가 실행된 후에 실행되면 0보다 큰 값이 나온다
t1.join(); // 메인 스레드가 t1을 실행할때까지 대기
t2.join(); // 메인 스레드가 t2을 실행할때까지 대기
System.out.println("Value: " + value); // t1, t2가 끝난 후 출력
}
public static void main(String[] args) throws InterruptedException {
// 멀티 스레드2
new App().run(); // 앱 객체를 만들고 run() 메소드 실행
}
}
예제 3
public class App {
private int value = 0;
private synchronized void increment() {
// synchronized : 해당 메소드에는 한번에 하나의 스레드만 접근할 수 있음.
value++;
}
public void run() throws InterruptedException {
Runnable runnable = () -> {
for (int i = 0; i < 10000; i++) {
increment();
}
};
Thread t1 = new Thread(runnable); // 새 스레드 t1 생성
Thread t2 = new Thread(runnable); // 새 스레드 t2 생성
Thread t3 = new Thread(runnable); // 새 스레드 t3 생성
t1.start(); // t1을 실행
t2.start(); // t2를 실행
t3.start(); // t3를 실행
System.out.println("Value: " + value);
t1.join(); // 메인 스레드가 t1을 실행할때까지 대기
t2.join(); // 메인 스레드가 t2을 실행할때까지 대기
t3.join(); // 메인 스레드가 t2을 실행할때까지 대기
System.out.println("Value: " + value); // t1, t2가 끝난 후 출력
}
public static void main(String[] args) throws InterruptedException {
// 멀티 스레드3
new App().run(); // 앱 객체를 만들고 run() 메소드 실행
}
}
static 메소드를 만들어 사용해야 함
(static메소드는 객체생성없이 사용가능)
람다식과 서로 대체가능.
예제 1
public class App {
public static void greet() { // static메소드는 객체 생성없이 사용가능
System.out.println("헬로우!");
}
public static void main(String[] args) {
// 메소드 레퍼런스 : static메소드를 만들어 사용
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
// 1초에 한번씩 헬로우! 출력
service.scheduleAtFixedRate(()->System.out.println("헬로우!!"), 0, 1000, TimeUnit.MICROSECONDS);
// service.scheduleAtFixedRate(App::greet, 0, 1000, TimeUnit.MICROSECONDS);
// 클래스명::메소드명 => 메소드 레퍼런스
// 람다식과 메소드 레퍼런스 모두 사용가능. 둘중 택1.
}
}
1초에 한번씩 "헬로우!" 출력
예제 2
@FunctionalInterface
interface Greeter {
void greet();
}
public class App2 {
public static void main(String[] args) {
Greeter g = () -> System.out.println("헬로우!");
g.greet();
Greeter g2 = App2::sayHello;
g2.greet();
}
private static void sayHello() {
System.out.println("헬로우!!");
}
}
예제 3
public class App3 {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(6);
numbers.add(4);
numbers.add(7);
numbers.add(3);
numbers.add(6);
numbers.add(3);
// numbers.removeIf(n -> n<5);
numbers.removeIf(App3::filter); // 위의 람다식을 메소드 레퍼런스로 변경
numbers.forEach(System.out::println);
System.out.println();
// numbers.replaceAll(n -> n *2);
numbers.replaceAll(App3::map); // 위의 람다식을 메소드 레퍼런스로 변경
numbers.forEach(System.out::println);
}
private static boolean filter(int n) {
return n < 5;
}
private static int map(int n) {
return n * 2;
}
}