π λλ€ (Lambda)
ν¨μ(λ©μλ)λ₯Ό μ’ λ κ°λ¨νκ³ νΈλ¦¬νκ² νννκΈ° μν΄ κ³ μλ λ¬Έλ² μμ
// sum λ©μλ λλ€μ
(num1, num2) -> num1 + num2
// λλ€μμ κ°μ²΄λ‘ νν
new Object() { // μ΅λͺ
ν΄λμ€
int sum(int num1, int num2) {
return num1 + num2;
}
}
λλ€μμ μ¬μ€ μμ κ°μ΄ μ΅λͺ ν΄λμ€λ€.
μ΅λͺ ν΄λμ€: κ°μ²΄μ μ μΈκ³Ό μμ±μ λμμ νμ¬ μ€μ§ νλμ κ°μ²΄λ₯Ό μμ±νκ³ λ¨ ν λ²λ§ μ¬μ©λλ μΌνμ© ν΄λμ€
π ν¨μν μΈν°νμ΄μ€
public class LamdaExample1 {
public static void main(String[] args) {
Func func = (num1, num2) -> num1 + num2
System.out.println(func.sum(10, 15))
}
@FunctionalInterface // μ»΄νμΌλ¬κ° μΈν°νμ΄μ€κ° λ°λ₯΄κ² μ μλμλ μ§ νμΈν μ μλλ‘
interface Func {
public abstract int sum(int num1, int num2);
}
// μΆλ ₯κ°
25
ν¨μν μΈν°νμ΄μ€λ₯Ό νμ©ν΄ λλ€μμ λ€λ£° μ μλ€.
μΈν°νμ΄μ€ λ¬Έλ²μΌλ‘ λλ€μμ λ€λ£¨λ κ²μ΄ κ°λ₯ν μ΄μ
- λλ€μλ κ²°κ΅ κ°μ²΄μ΄κΈ° λλ¬Έμ μΈν°νμ΄μ€μ μ μλ μΆμ λ©μλλ₯Ό ꡬνν μ μλ€.
ν¨μν μΈν°νμ΄μ€κ° λ¨ νλμ μΆμ λ©μλλ§ κ°μ§ μ μλ μ΄μ
- λλ€μκ³Ό μΈν°νμ΄μ€μ λ©μλκ° 1:1λ‘ λ§€μΉ λμ΄μΌ νλ€.
@FunctionalInterface
public interface Func {
public int accept(int x, int y);
}
public class MyFunctionalInterfaceExample {
public static void main(String[] args) throws Exception {
Func example;
example = (x, y) -> { // 1
int result = x + y;
return result;
};
example = (x, y) -> { return x + y; }; // 2
example = (x, y) -> x + y; // 3
example = (x, y) -> sum(x, y); // 4
example = (x, y) -> sum;
example = Integer::sum; // 5, λ©μλ λ νΌλ°μ€
// 1, 2, 3, 4, 5 λͺ¨λ κ°μ λμμ νλ€.
}
public static int sum(int x, int y){
return x + y;
}
}
π Javaμμ κΈ°λ³Έμ μΌλ‘ μ 곡νλ ν¨μν μΈν°νμ΄μ€
Functional Interface | Descripter | Method |
Runnable | () -> void | void run() |
Callable<V> | () -> V | V call() |
Supplier<T> | () -> T | T get() |
Consumer<T> | T -> void | void accept(T t) |
Function<T, R> | T -> R | R apply(T t) |
Predicate<T> | T -> boolean | boolean test(T t) |
Comparator<T> | (T, T) -> int | int compare(T o1, T o2) |
ν¨μν μΈν°νμ΄μ€ API DOC
π λ©μλ λ νΌλ°μ€
ν΄λμ€::λ©μλ // μ μ λ©μλ μ°Έμ‘°
μ°Έμ‘° λ³μ::λ©μλ // μΈμ€ν΄μ€ λ©μλ μ°Έμ‘°
(left, right) -> Math.max(left, right);
(left, right) -> Math::max; // μ μ λ©μλ μ°Έμ‘°
(a, b) -> { return new ν΄λμ€(a, b); };
(a, b) -> ν΄λμ€::new; // μμ±μ μ°Έμ‘° λ¬Έλ²
π μ€νΈλ¦Ό
- λ°°μ΄, 컬λ μ μ μ μ₯ μμλ₯Ό νλμ© μ°Έμ‘°ν΄μ λλ€μμΌλ‘ μ²λ¦¬ν μ μλλ‘ ν΄μ£Όλ λ°λ³΅μ
- λ°μ΄ν°λ₯Ό μ°μμ μΌλ‘ μ λ¬νλ ν΅λ‘
π νΉμ§
π μ μΈνμΌλ‘ λ°μ΄ν° μμ€λ₯Ό μ²λ¦¬νλ€.
μ μΈν νλ‘κ·Έλλ°: "μ΄λ»κ²" μννλμ§ λ³΄λ€ "무μμ" μννλμ§μ κ΄μ¬μ λλ νλ‘κ·Έλλ° ν¨λ¬λ€μ
public class Example {
public static void main(String[] args){
// Listμ μλ μ«μλ€ μ€μμ 4λ³΄λ€ ν° μ§μμ ν©κ³ ꡬνκΈ°
List<Integer> numbers = List.of(1, 3, 6, 7, 8, 11);
int sum = 0;
// λͺ
λ Ήν (Imperative) νλ‘κ·Έλλ°
for(int number : numbers){
if(number > 4 && (number % 2 == 0)){
sum += number;
}
}
// μ μΈν (Declarative) νλ‘κ·Έλλ°
int sum = numbers.stream()
.filter(number -> number > 4 && (number % 2 == 0))
.mapToInt(number -> number)
.sum();
}
}
π λλ€μμΌλ‘ μμ μ²λ¦¬ μ½λλ₯Ό μ 곡νλ€.
stream.forEach(s -> {
String name = s.getName();
int score = s.getScore();
System.out.println(name + " - " + score);
});
π λ΄λΆ λ°λ³΅μλ₯Ό μ¬μ©νλ―λ‘ λ³λ ¬ μ²λ¦¬κ° μ½λ€.
μΈλΆ λ°λ³΅μ(external iterator)
- κ°λ°μκ° μ§μ 컬λ μ μ μμλ₯Ό λ°λ³΅ν΄μ κ°μ Έμ€λ μ½λ ν¨ν΄
- μ) indexλ₯Ό μ¬μ©νλ forλ¬Έ, iteratorλ₯Ό μ¬μ©νλ whileλ¬Έ
λ΄λΆ λ°λ³΅μ(internal iterator)
- 컬λ μ λ΄λΆμμ μμλ€μ λ°λ³΅μν€κ³ κ°λ°μλ μμλΉ μ²λ¦¬ν΄μΌ ν μ½λλ§ μ 곡νλ μ½λ ν¨ν΄
λ΄λΆ λ°λ³΅μμ μ΄μ
- μ΄λ»κ² μμλ₯Ό λ°λ³΅μν¬ κ²μΈκ°λ 컬λ μ μ 맑겨λκ³ , κ°λ°μλ μμ μ²λ¦¬ μ½λμλ§ μ§μ€ν μ μλ€
- μμλ€μ λ°λ³΅ μμλ₯Ό λ³κ²½νκ±°λ λ©ν° μ½μ΄ CPUλ₯Ό μ΅λν νμ©νκΈ° μν΄ μμλ€μ λΆλ°°μμΌ λ³λ ¬ μμ μ ν μ μκ² λμμ£ΌκΈ° λλ¬Έμ νλμ© μ²λ¦¬νλ μμ°¨μ μΈλΆ λ°λ³΅μλ³΄λ€ ν¨μ¨μ μΌλ‘ μμλ₯Ό λ°λ³΅μν¬ μ μλ€.
λ³λ ¬ μ€νΈλ¦Όμ μ¬μ©νκΈ° μν΄μλ parallel λ©μλλ₯Ό μ¬μ©νλ©΄ λλ€.
π μ€κ° μ°μ°κ³Ό μ΅μ’ μ°μ°μ ν μ μλ€.
μ€κ° μ°μ°: 맀ν, νν°λ§, μ λ ¬ λ±μ μνν μ μλ€.
μ΅μ’ μ°μ°: λ°λ³΅, μΉ΄μ΄ν , νκ· , μ΄ν© λ±μ μ§κ³λ₯Ό μνν μ μλ€.
π νμ΄νλΌμΈ ꡬμ±
컬λ μ μ μμλ₯Ό 리λμ μ κ²°κ³Όλ¬Όλ‘ λ°λ‘ μ§κ³ν μ μμ λ νν°, 맀ν, μ λ ¬, κ·Έλ£Ήν λ±μ μ€κ° μ°μ°μ΄ νμνλ€.
리λμ (Reduction): λλμ λ°μ΄ν°λ₯Ό κ°κ³΅ν΄μ μΆμνλ κ²
리λμ μ κ²°κ³Όλ¬Ό: λ°μ΄ν°μ ν©κ³, νκ· κ°, μΉ΄μ΄ν , μ΅λκ°, μ΅μκ° λ±
π νμ΄νλΌμΈ
- μ¬λ¬κ°μ μ€νΈλ¦Όμ΄ μ°κ²°λμ΄ μλ ꡬ쑰
- νμ΄νλΌμΈμμ μ΅μ’ μ°μ°μ μ μΈνκ³ λ λͺ¨λ μ€κ° μ°μ° μ€νΈλ¦Όμ΄λ€.
μ€κ° μ€νΈλ¦Όμ΄ μμ±λ λ μμλ€μ΄ λ°λ‘ μ€κ° μ°μ°λλ κ²μ΄ μλλΌ μ΅μ’ μ°μ°μ΄ μμλκΈ° μ κΉμ§λ μ§μ°λλ€. μ΅μ’ μ°μ°μ΄ μμλλ©΄ λΉλ‘μ 컬λ μ μ μμκ° νλμ© μ€κ° μ€νΈλ¦Όμμ μ°μ°λκ³ μ΅μ’ μ°μ°κΉμ§ μ€κ² λλ€.
π μ€νΈλ¦Ό μμ±
// Listλ‘λΆν° μ€νΈλ¦Όμ μμ±
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> listStream = list.stream();
// λ°°μ΄λ‘λΆν° μ€νΈλ¦Όμ μμ±
Stream<String> stream = Stream.of("a", "b", "c"); //κ°λ³μΈμ
Stream<String> stream = Stream.of(new String[] {"a", "b", "c"});
Stream<String> stream = Arrays.stream(new String[] {"a", "b", "c"});
Stream<String> stream = Arrays.stream(new String[] {"a", "b", "c"}, 0, 3); //end λ²μ λ―Έν¬ν¨
// 4μ΄μ 10λ―Έλ§μ μ«μλ₯Ό κ°λ IntStream
IntStream stream = IntStream.range(4, 10);
λ¦¬ν΄ νμ | λ©μλ(λ§€κ° λ³μ) | μμ€ |
Stream | java.util.Collection.Stream(), java.util.Collection.parallelStream( ) | 컬λ μ |
Stream, IntStream, LongStream, DoubleStream | Arrays.stream(T[]), Arrays.stream(int[]), Arrays.stream(long[]), Arrays.stream(double[]), Stream.of(T[]), IntStream.of(int[]) LongStream.of(long[]), DoubleStream.of(double[]) | λ°°μ΄ |
IntStream | IntStream.range(int, int), IntStream.rangeClosed(int, int) | int λ²μ |
LongStream | LongStream.range(long, long), LongStream.rangeClosed(long, long) | long λ²μ |
μ£Όμν μ
- μ€νΈλ¦Όμ λ°μ΄ν° μμ€λ‘λΆν° μ½κΈ°λ§ ν λΏ λ³κ²½νμ§ μλλ€. (Read-only)
- μ€νΈλ¦Όμ μΌνμ©μ΄λ€.
π μ€κ° μ°μ°
π νν°λ§ (filter(), distinct())
filter(): 쑰건μ λ§λ λ°μ΄ν°λ§μ μ μ νλ€.
distinct(): μ€λ³΅μ μ κ±°νλ€.
π 맀ν (map())
map(): κΈ°μ‘΄μ Stream μμλ€μ λ체νλ μμλ‘ κ΅¬μ±λ μλ‘μ΄ Streamμ νμ±νλ€.
flatMap(): μμλ₯Ό λ체νλ 볡μ κ°μ μμλ€λ‘ ꡬμ±λ μλ‘μ΄ Streamμ νμ±νλ€.
map λ©μλμ flatMap λ©μλμ μ°¨μ΄
mapToInt, mapToLong, mapToDouble, mapToObject
π μ λ ¬ (sorted())
list.stream()
.sorted() // μ€λ¦μ°¨μ μ λ ¬
.forEach(n -> System.out.println(n));
list.stream()
.sorted(Comparator.reverseOrder()) // λ΄λ¦Όμ°¨μ μ λ ¬
.forEach(n -> System.out.println(n));
workersStream
.sorted(Comparator.comparing(Employee::getId))
.forEach(System.out::println);
π μ°μ° κ²°κ³Ό νμΈ (peek())
μ£Όλ‘ μ°μ° κ²°κ³Όλ₯Ό νμΈνμ¬ λλ²κΉ νκ³ μ ν λ μ¬μ©νλ€.
intStream
.filter(a -> a % 2 == 0)
.peek(n -> System.out.println(n))
.sum();
π μ΅μ’ μ°μ°
π μ°μ° κ²°κ³Ό νμΈ (foreach())
μμλ₯Ό νλμ© μ°μ°νλ€.
intStream
.filter(a -> a % 2 == 0)
.forEach(n -> System.out.println(n));
π λ§€μΉ (match())
νΉμ ν 쑰건μ μΆ©μ‘±νλμ§ κ²μ¬νλ€.
allMatch(): λͺ¨λ μμλ€μ΄ 맀κ°κ°μΌλ‘ μ£Όμ΄μ§ Predicateμ 쑰건μ λ§μ‘±νλμ§ μ‘°μ¬
anyMatch(): μ΅μν ν κ°μ μμκ° λ§€κ°κ°μΌλ‘ μ£Όμ΄μ§ Predicateμ 쑰건μ λ§μ‘±νλμ§ μ‘°μ¬
noneMatch(): λͺ¨λ μμλ€μ΄ 맀κ°κ°μΌλ‘ μ£Όμ΄μ§ Predicateμ 쑰건μ λ§μ‘±νμ§ μλμ§ μ‘°μ¬
int[] intArr = {2, 4, 6};
boolean result = Arrays.stream(intArr).allMatch(a -> a % 2 == 0);
System.out.println("λͺ¨λ 2μ λ°°μμΈκ°? " + result);
result = Arrays.stream(intArr).anyMatch(a -> a % 3 == 0);
System.out.println("νλλΌλ 3μ λ°°μκ° μλκ°? " + result);
result = Arrays.stream(intArr).noneMatch(a -> a % 3 == 0);
System.out.println("3μ λ°°μκ° μλκ°? " + result);
μΆλ ₯κ°
λͺ¨λ 2μ λ°°μμΈκ°? true
νλλΌλ 3μ λ°°μκ° μλκ°? true
3μ λ°°μκ° μλκ°? false
π κΈ°λ³Έ μ§κ³ (sum(), count(), average(), max(), min())
sum(): μ΄ν©, count(): κ°μ, average(): νκ· , max(): μ΅λκ°, min(): μ΅μκ°
π reduce()
reduceλ λμ νμ¬ νλλ‘ μμΆ(reduce)νλ λ°©μμΌλ‘ λμνλ€.
int[] intArr = {1, 2, 3, 4, 5};
long sum = Arrays.stream(intArr).sum();
System.out.println("intArrμ μ 체 μμ ν© " + sum);
int sum1 = Arrays.stream(intArr)
.map(el -> el * 2)
.reduce((a, b) -> a + b)
.getAsInt();
System.out.println("μ΄κΈ°κ° μλ reduce " + sum1);
int sum2= Arrays.stream(intArr)
.map(el -> el * 2)
.reduce(0, (a, b) -> a + b);
System.out.println("μ΄κΈ°κ° μ‘΄μ¬νλ reduce " + sum2)
μΆλ ₯κ°
intArrμ μ 체 μμ ν© 15
μ΄κΈ°κ° μλ reduce 30
μ΄κΈ°κ° μ‘΄μ¬νλ reduce 30
π collect()
Streamμ μμλ€μ List, Set, Map λ± λ€λ₯Έ μ’ λ₯μ κ²°κ³Όλ‘ μμ§νκ³ μΆμ κ²½μ° μ¬μ©νλ€.
List<Student> maleList = totalList.stream()
.filter(s -> s.getGender() == Student.Gender.Male)
.collect(Collectors.toList());
Set<Student> femaleSet = totalList.stream()
.filter(s -> s.getGender() == Student.Gender.Female)
.collect(Collectors.toCollection(HashSet::new));
π Optional
NullPointerException(NPE), μ¦ null κ°μΌλ‘ μΈν΄ μλ¬κ° λ°μνλ νμμ κ°μ²΄ μ°¨μμμ ν¨μ¨μ μΌλ‘ λ°©μ§νκ³ μ λμ λμλ€.
Optional ν΄λμ€λ λͺ¨λ νμ μ κ°μ²΄λ₯Ό λ΄μ μ μλ λνΌ(Wrapper) ν΄λμ€λ€.
κ°μ²΄ μμ± of() λλ ofNullable()μ μ¬μ©νλ€. μ°Έμ‘° λ³μκ° nullμΌ κ°λ₯μ±μ΄ μμΌλ©΄ ofNullable()μ μ¬μ©νλ€.
Optional<String> opt1 = Optional.of("123");
Optional<String> opt2 = Optional.ofNullable(null);
Optional<String> opt3 = Optional.<String>empty(); // κΈ°λ³Έκ°μΌλ‘ μ΄κΈ°ν
Optional<String> opt4 = Optional.empty(); // κΈ°λ³Έκ°μΌλ‘ μ΄κΈ°ν
System.out.println(opt1.orElse("else")); // "123"
System.out.println(opt2.orElse("else")); // "else"
List<String> languages = Arrays.asList(
"Ruby", "Python", "Java", "Go", "Kotlin");
Optional<List<String>> listOptional = Optional.of(languages);
int size = listOptional
.map(List::size)
.orElse(0); // 5
μ€νΈλ¦Όκ³Ό μ μ¬νκ² λ©μλ 체μ΄λμ΄ κ°λ₯νλ€.