1~4. ๋žŒ๋‹ค์‹์ด๋ž€? ๋žŒ๋‹ค์‹ ์ž‘์„ฑํ•˜๊ธฐ


๋žŒ๋‹ค์‹(Lambda Expression)

  • ํ•จ์ˆ˜๋ฅผ ๊ฐ„๋‹จํ•œ ์‹์œผ๋กœ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•
int max(int a, int b) {
	return a > b ? a : b;
}
(a, b) -> a > b ? a : b
  • ์ต๋ช… ํ•จ์ˆ˜(์ด๋ฆ„์ด ์—†๋Š” ํ•จ์ˆ˜, annonymous function)
    • ๋ฐ˜ํ™˜ ํƒ€์ž…, ํ•จ์ˆ˜ ์ด๋ฆ„ ์ œ๊ฑฐ
    • ํ™”์‚ดํ‘œ ์‚ฝ์ž…
  • ํ•จ์ˆ˜์™€ ๋ฉ”์„œ๋“œ์˜ ์ฐจ์ด
    • ํ•จ์ˆ˜๋Š” ์ผ๋ฐ˜์  ์šฉ์–ด, ๋ฉ”์„œ๋“œ๋Š” ๊ฐ์ฒด์ง€ํ–ฅ๊ฐœ๋… ์šฉ์–ด
    • ํ•จ์ˆ˜๋Š” ํด๋ž˜์Šค์— ๋…๋ฆฝ์ , ๋ฉ”์„œ๋“œ๋Š” ํด๋ž˜์Šค์— ์ข…์†์ 

๋žŒ๋‹ค์‹ ์ž‘์„ฑํ•˜๊ธฐ

  1. ๋ฉ”์„œ๋“œ์˜ ์ด๋ฆ„๊ณผ ๋ฐ˜ํ™˜ํƒ€์ž…์„ ์ œ๊ฑฐํ•˜๊ณ  โ€˜โ†’โ€™ ๋ฅผ ๋ธ”๋ก ์•ž์— ์ถ”๊ฐ€
  2. ๋ฐ˜ํ™˜๊ฐ’์ด ์žˆ๋Š” ๊ฒฝ์šฐ, ์‹์ด๋‚˜ ๊ฐ’๋งŒ ์ ๊ณ  return๋ฌธ ์ƒ๋žต ๊ฐ€๋Šฅ
  3. ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ํƒ€์ž…์ด ์ถ”๋ก  ๊ฐ€๋Šฅํ•˜๋ฉด ์ƒ๋žต ๊ฐ€๋Šฅ

์ฃผ์˜์‚ฌํ•ญ

  1. ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ํ•˜๋‚˜์ธ ๊ฒฝ์šฐ, ๊ด„ํ˜ธ() ์ƒ๋žต ๊ฐ€๋Šฅ
  2. ๋ธ”๋ก ์•ˆ์˜ ๋ฌธ์žฅ์ด ํ•˜๋‚˜์ผ ๊ฒฝ์šฐ, ๊ด„ํ˜ธ{} ์ƒ๋žต ๊ฐ€๋Šฅ

๋žŒ๋‹ค์‹์˜ ์˜ˆ

(a, b) -> a > b ? a : b
(name, i) -> System.out.println(name + "=" + i)
x -> x * x
() -> (int)(Math.random() * 6)

๋žŒ๋‹ค์‹์€ ์ต๋ช… ๊ฐ์ฒด

  • ๋žŒ๋‹ค์‹(์ต๋ช… ๊ฐ์ฒด)์„ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ ์ฐธ์กฐ๋ณ€์ˆ˜ ํ•„์š”

5~6. ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค


ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค

  • ๋‹จ ํ•˜๋‚˜์˜ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋งŒ ์„ ์–ธ๋œ ์ธํ„ฐํŽ˜์ด์Šค
interface MyFuction {
	public abstract int max(int a, int b);
}
MyFunction f = new MyFunction() {
	public int max(int a, int b) {
		return a > b ? a : b;
	}
};
  • ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค ํƒ€์ž…์˜ ์ฐธ์กฐ๋ณ€์ˆ˜๋กœ ๋žŒ๋‹ค์‹์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Œ
    • ๋‹จ, ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฉ”์„œ๋“œ์™€ ๋žŒ๋‹ค์‹์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐœ์ˆ˜์™€ ๋ฐ˜ํ™˜ํƒ€์ž…์ด ์ผ์น˜ํ•ด์•ผ ํ•จ
MyFuction f = (a, b) -> a > b ? a : b;
int value = f.max(3, 5); // ์‹ค์ œ๋กœ๋Š” ๋žŒ๋‹ค์‹์ด ํ˜ธ์ถœ๋จ

ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค - ์˜ˆ์‹œ

  • ์ต๋ช… ๊ฐ์ฒด๋ฅผ ๋žŒ๋‹ค์‹์œผ๋กœ ๋Œ€์ฒด
List<String> list = Arrays.asList("abc", "aaa", "bbb", "ddd", "aaa");
@FunctionalInterface
interface Comparator<T> {
	int compare(T o1, T o2);
}
Collections.sort(list, new Comparator<String>() {
	public int compare(String s1, String s2) {
		return s2.compareTo(s1);
	}
});
Collections.sort(list, (s1, s2) -> s2.compareTo(s1));

ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค ํƒ€์ž…์˜ ๋งค๊ฐœ๋ณ€์ˆ˜, ๋ฐ˜ํ™˜ํƒ€์ž…

@FunctionalInterface
interface MyFunction {
	void myMethod();
}
// ๋žŒ๋‹ค์‹์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ํ™œ์šฉ
void aMethod(MyFunction f) {
	f.myMethod(); // MyFunction์— ์ •์˜๋œ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
}
MyFunction f = () -> System.out.println("myMethod()");
aMethod(f);
// ์ค„์—ฌ์„œ
aMethod(() -> System.out.println("myMethod()"));
  • ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค ํƒ€์ž…์˜ ๋งค๊ฐœ๋ณ€์ˆ˜
// ๋žŒ๋‹ค์‹์„ ๋ฐ˜ํ™˜
MyFunction myMethod() {
	MyFunction f = () -> {};
	return f;
}
// ์ค„์—ฌ์„œ
MyFunction myMethod() {
	return () -> {};
}
  • ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค ํƒ€์ž…์˜ ๋ฐ˜ํ™˜ํƒ€์ž…

7~8. java.util.function ํŒจํ‚ค์ง€


java.util.function ํŒจํ‚ค์ง€

  • ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๋‹ค์–‘ํ•œ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค ์ œ๊ณต
ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฉ”์„œ๋“œ์„ค๋ช…
java.lang.Runnablevoid run()๋งค๊ฐœ๋ณ€์ˆ˜ ์—†๊ณ  ๋ฐ˜ํ™˜๊ฐ’๋„ ์—†์Œ
SupplierT get()๋งค๊ฐœ๋ณ€์ˆ˜ ์—†๊ณ  ๋ฐ˜ํ™˜๊ฐ’์€ ์žˆ์Œ
Consumervoid accept(T t)๋งค๊ฐœ๋ณ€์ˆ˜๋งŒ ์žˆ๊ณ  ๋ฐ˜ํ™˜๊ฐ’ ์—†์Œ
Function<T, R>R apply(T t)ํ•˜๋‚˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์•„์„œ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
Predicateboolean test(T t)ํ•˜๋‚˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์•„์„œ boolean์„ ๋ฐ˜ํ™˜
Supplier<Integer> f = () -> (int)(Math.random() * 100) + 1;
Consumer<Integer> f = i -> System.out.print(i + ", ");
Predicate<Integer> f  = i -> i%2==0;
Function<Integer, Integer> f = i -> i/10*10;

๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ 2๊ฐœ์ธ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค

ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฉ”์„œ๋“œ์„ค๋ช…
BiConsumer<T, U>void accept(T t, U u)๋‘ ๊ฐœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋งŒ ์žˆ๊ณ  ๋ฐ˜ํ™˜๊ฐ’ ์—†์Œ
BiPredicate<T, U>boolean test(T t, U u)๋‘ ๊ฐœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์•„์„œ boolean์„ ๋ฐ˜ํ™˜
BiFunction<T, U, R>R apply(T t, U u)๋‘ ๊ฐœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์•„์„œ ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
// ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ 3๊ฐœ ์ด์ƒ์ธ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ•„์š”ํ•˜๋ฉด ์ง์ ‘ ์ž‘์„ฑํ•˜์—ฌ ์‚ฌ์šฉ
@FunctionalInterface
interface TriFunction<T, U, V, R> {
	R apply(T t, U u, V v);
}

๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž…๊ณผ ๋ฐ˜ํ™˜ ํƒ€์ž…์ด ์ผ์น˜ํ•˜๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค

ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฉ”์„œ๋“œ์„ค๋ช…
UnaryOperatorT apply(T t)Function์˜ ์ž์†. ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ๊ฒฐ๊ณผ์˜ ํƒ€์ž…์ด ๊ฐ™์Œ
BinaryOperatorT apply(T t, T t)BiFunction์˜ ์ž์†. ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ๊ฒฐ๊ณผ์˜ ํƒ€์ž…์ด ๊ฐ™์Œ

9~12. Predicate์˜ ๊ฒฐํ•ฉ, CF


Predicate์˜ ๊ฒฐํ•ฉ

Predicate<Integer> p = i -> i < 100;
Predicate<Integer> q = i -> i < 200;
Predicate<Integer> r = i -> i%2 == 0;
Predicate<Integer> notP = p.negate();        // i >= 100
Predicate<Integer> all  = notP.and(q.or(r)); // 100 <= i && i < 200 || i%2 == 0
Predicate<Integer> all2 = notP.and(q.or(r)); // 100 <= i && (i < 200 || i%2 == 0)
System.out.println(all.test(2));  // true
System.out.println(all2.test(2)); // false
  • and() or() negate() ๋กœ ๋‘ Predicate๋ฅผ ํ•˜๋‚˜๋กœ ๊ฒฐํ•ฉ
Predicate<String> p2 = Predicate.isEqual(str1);
boolean result = p2.test(str2); // str1๊ณผ str2๊ฐ€ ๊ฐ™์€์ง€ ๋น„๊ตํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜
  • ๋“ฑ๊ฐ€๋น„๊ต๋ฅผ ์œ„ํ•œ Predicate์˜ ์ž‘์„ฑ์—๋Š” isEqual()๋ฅผ ์‚ฌ์šฉ(static ๋ฉ”์„œ๋“œ)

์ปฌ๋ ‰์…˜ ํ”„๋ ˆ์ž„์›๊ณผ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค

list.forEach(i -> System.out.print(i + ", "));
list.removeIf(x -> x%2 == 0 || x%3 == 0);
list.replaceAll(i -> i*10);
// map์˜ ๋ชจ๋“  ์š”์†Œ๋ฅผ {k,v} ํ˜•์‹์œผ๋กœ ์ถœ๋ ฅ
map.forEach((k,v) -> System.out.print("{" + k + "," + v + "},"));
  • ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ปฌ๋ ‰์…˜ ํ”„๋ ˆ์ž„์›์˜ ๋ฉ”์„œ๋“œ

13~14. ๋ฉ”์„œ๋“œ, ์ƒ์„ฑ์ž์˜ ๋ฉ”์„œ๋“œ ์ฐธ์กฐ


๋ฉ”์„œ๋“œ ์ฐธ์กฐ

  • ํ•˜๋‚˜์˜ ๋ฉ”์„œ๋“œ๋งŒ ํ˜ธ์ถœํ•˜๋Š” ๋žŒ๋‹ค์‹์€ โ€˜๋ฉ”์„œ๋“œ ์ฐธ์กฐโ€™๋กœ ๋” ๊ฐ„๋‹จํžˆ ํ•  ์ˆ˜ ์žˆ์Œ
์ข…๋ฅ˜๋žŒ๋‹ค๋ฉ”์„œ๋“œ ์ฐธ์กฐ
static ๋ฉ”์„œ๋“œ ์ฐธ์กฐ(x) โ†’ ClassName.method(x)ClassName::method
์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ ์ฐธ์กฐ(obj, x) โ†’ obj.method(x)ClassName::method
ํŠน์ • ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ ์ฐธ์กฐ(x) โ†’ obj.method(x)obj::method
Integer method(String s) {
	return Integer.parseInt(s);
}
Function<String, Integer> f = (String s) -> Integer.parseInt(s);
Function<String, Integer> f = Integer::parseInt;
  • static ๋ฉ”์„œ๋“œ ์ฐธ์กฐ

์ƒ์„ฑ์ž์˜ ๋ฉ”์„œ๋“œ ์ฐธ์กฐ

Supplier<MyClass> s = () -> new MyClass();
Supplier<MyCalss> s = MyClass::new;
Function<Integer, MyClass> s = (i) -> new MyClass(i);
Function<Integer, MyClass> s = MyClass::new;
  • ์ƒ์„ฑ์ž์˜ ๋ฉ”์„œ๋“œ ์ฐธ์กฐ
Function<Integer, int[]> f = x -> new int[x];
Function<Integer, int[]> f2 = int[]::new;
  • ๋ฐฐ์—ด๊ณผ ๋ฉ”์„œ๋“œ ์ฐธ์กฐ

15~16. ์ŠคํŠธ๋ฆผ, ์ŠคํŠธ๋ฆผ์˜ ํŠน์ง•


์ŠคํŠธ๋ฆผ

stream.distinct().limit(5).sorted().forEach(System.out::println)
//     ----------์ค‘๊ฐ„ ์—ฐ์‚ฐ---------- ---------์ตœ์ข… ์—ฐ์‚ฐ----------
  • ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ํ‘œ์ค€ํ™”๋œ ๋ฐฉ๋ฒ•์œผ๋กœ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ ๊ฒƒ
  • ์ŠคํŠธ๋ฆผ์ด ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ
    • ์ค‘๊ฐ„ ์—ฐ์‚ฐ - ์—ฐ์‚ฐ ๊ฒฐ๊ณผ๊ฐ€ ์ŠคํŠธ๋ฆผ์ธ ์—ฐ์‚ฐ. ๋ฐ˜๋ณต์ ์œผ๋กœ ์ ์šฉ ๊ฐ€๋Šฅ
    • ์ตœ์ข… ์—ฐ์‚ฐ - ์—ฐ์‚ฐ ๊ฒฐ๊ณผ๊ฐ€ ์ŠคํŠธ๋ฆผ์ด ์•„๋‹Œ ์—ฐ์‚ฐ. ๋‹จ ํ•œ ๋ฒˆ๋งŒ ์ ์šฉ ๊ฐ€๋Šฅ (์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ๋ฅผ ์†Œ๋ชจ)

์ŠคํŠธ๋ฆผ์˜ ํŠน์ง•

List<Integer> list = Arrays.asList(3,1,5,4,2);
List<Integer> sortedList = list.stream().sorted().collect(Collectors.toList());
System.outprintln(list);       // [3, 1, 5, 4, 2]
System.outprintln(sortedList); // [1, 2, 3, 4, 5]
  • ์ŠคํŠธ๋ฆผ์€ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ธฐ๋งŒ ํ•  ๋ฟ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Œ
strStream.forEach(System.out::println); // ๋ชจ๋“  ์š”์†Œ๋ฅผ ํ™”๋ฉด์— ์ถœ๋ ฅ(์ตœ์ข… ์—ฐ์‚ฐ)
int numOfStr = strStream.count();       // ์—๋Ÿฌ. ์ŠคํŠธ๋ฆผ์ด ์ด๋ฏธ ๋‹ซํ˜”์Œ
  • ์ŠคํŠธ๋ฆผ์€ Iterator ์ฒ˜๋Ÿผ ์ผํšŒ์šฉ (ํ•„์š” ์‹œ ๋‹ค์‹œ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•ด์•ผ ํ•จ)
IntStream intStream = new Random().int(1, 46);        // 1~45 ๋ฒ”์œ„์˜ ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ
intStream.distinct().limit(6).sorted()                // ์ค‘๊ฐ„ ์—ฐ์‚ฐ
						.forEach(i -> System.out.print(i + ",")); // ์ตœ์ข… ์—ฐ์‚ฐ
  • ์ตœ์ข… ์—ฐ์‚ฐ ์ „๊นŒ์ง€ ์ค‘๊ฐ„์—ฐ์‚ฐ์ด ์ˆ˜ํ–‰๋˜์ง€ ์•Š์Œ - ์ง€์—ฐ๋œ ์—ฐ์‚ฐ
stream.forEach(System.out::println); // forEach ๋ฉ”์„œ๋“œ ์•ˆ์— for๋ฌธ์ด ์žˆ์Œ
  • ์ŠคํŠธ๋ฆผ์€ ์ž‘์—…์„ ๋‚ด๋ถ€ ๋ฐ˜๋ณต์œผ๋กœ ์ฒ˜๋ฆฌํ•จ
Stream<String> strStream = Stream.of("dd", "aaa", "CC", "cc", "b");
int sum = strStream.parallel()                // ๋ณ‘๋ ฌ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ „ํ™˜(์†์„ฑ๋งŒ ๋ณ€๊ฒฝ)
						.mapToInt(s -> s.length()).sum(); // ๋ชจ๋“  ๋ฌธ์ž์—ด์˜ ๊ธธ์ด์˜ ํ•ฉ
  • ์ŠคํŠธํŒ€์˜ ์ž‘์—…์„ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌ - ๋ณ‘๋ ฌ์ŠคํŠธ๋ฆผ

  • ๊ธฐ๋ณธํ˜• ์ŠคํŠธ๋ฆผ - IntStream, LongStream, DoubleStream

    • ์˜คํ† ๋ฐ•์‹ฑ & ์–ธ๋ฐ•์‹ฑ์˜ ๋น„ํšจ์œจ์ด ์ œ๊ฑฐ๋จ(Stream<Integer> ๋Œ€์‹  intStream ์‚ฌ์šฉ)
    • ์ˆซ์ž์™€ ๊ด€๋ จ๋œ ์œ ์šฉํ•œ ๋ฉ”์„œ๋“œ๋ฅผ Stream<T>๋ณด๋‹ค ๋” ๋งŽ์ด ์ œ๊ณต

17~22. ์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ


์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ - ์ปฌ๋ ‰์…˜

List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> intStream = list.stream(); // list๋ฅผ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜
// ์ŠคํŠธ๋ฆผ์˜ ๋ชจ๋“  ์š”์†Œ๋ฅผ ์ถœ๋ ฅ
intStream.forEach(System.out::print); // 12345
intStream.forEach(System.out::print); // ์—๋Ÿฌ. ์ŠคํŠธ๋ฆผ์ด ์ด๋ฏธ ๋‹ซํž˜
  • Collection ์ธํ„ฐํŽ˜์ด์Šค์˜ stream()์œผ๋กœ ์ปฌ๋ ‰์…˜์„ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜

์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ - ๋ฐฐ์—ด

Stream<String> strStream = Stream.of("a", "b", "c"); // ๊ฐ€๋ณ€ ์ธ์ž
Stream<String> strStream = Stream.of(new String[]{"a", "b", "c"});
Stream<String> strStream = Arrays.stream(new String[]{"a", "b", "c"});
Stream<String> strStream = Arrays.stream(new String[]{"a", "b", "c"}, 0, 3);
  • ๊ฐ์ฒด ๋ฐฐ์—ด๋กœ๋ถ€ํ„ฐ ์ŠคํŠธ๋ฆผ ์ƒ์„ฑํ•˜๊ธฐ
IntStream IntStream.of(int... values) // Stream์ด ์•„๋‹ˆ๋ผ IntStream
IntStream IntStream.of(int[])
IntStream Arrays.stream(int[])
IntStream Arrays.stream(int[] array, int startInclusive, int endExclusive)
  • ๊ธฐ๋ณธํ˜• ๋ฐฐ์—ด๋กœ๋ถ€ํ„ฐ ์ŠคํŠธ๋ฆผ ์ƒ์„ฑํ•˜๊ธฐ

์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ - ์ž„์˜์˜ ์ˆ˜

IntStream intStream = new Random().ints();       // ๋ฌดํ•œ ๋‚œ์ˆ˜ ์ŠคํŠธ๋ฆผ ์ƒ์„ฑ
intStream.limit(5).forEach(System.out::println); // 5๊ฐœ์˜ ์š”์†Œ๋งŒ ์ถœ๋ ฅ
IntStream intStream = new Random().ints(5);        // 5๊ฐœ์งœ๋ฆฌ ์œ ํ•œ ๋‚œ์ˆ˜ ์ŠคํŠธ๋ฆผ ์ƒ์„ฑ
IntStream intStream = new Random().ints(5, 1, 11); // (1, 10)์‚ฌ์ด 5 ์š”์†Œ ์œ ํ•œ ๋‚œ์ˆ˜ ์ŠคํŠธ๋ฆผ
  • ๋‚œ์ˆ˜๋ฅผ ์š”์†Œ๋กœ ๊ฐ–๋Š” ์ŠคํŠธ๋ฆผ ์ƒ์„ฑํ•˜๊ธฐ

์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ - ํŠน์ • ๋ฒ”์œ„์˜ ์ •์ˆ˜

IntStream intStream = IntStream.range(1, 5);       // 1,2,3,4
IntStream intStream = IntStream.rangeClosed(1, 5); // 1,2,3,4,5
  • ํŠน์ • ๋ฒ”์œ„์˜ ์ •์ˆ˜๋ฅผ ์š”์†Œ๋กœ ๊ฐ–๋Š” ์ŠคํŠธ๋ฆผ ์ƒ์„ฑํ•˜๊ธฐ (IntStream, LongStream)

์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ - ๋žŒ๋‹ค์‹ iterate(), generate()

// iterate()๋Š” ์ด์ „ ์š”์†Œ๋ฅผ seed๋กœ ํ•ด์„œ ๋‹ค์Œ ์š”์†Œ๋ฅผ ๊ณ„์‚ฐ (์ด์ „ ์š”์†Œ์— ์ข…์†์ )
Stream<Integer> evenStream = Stream.iterate(0, n -> n+2);
// generate๋Š” seed๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ (์ด์ „ ์š”์†Œ์— ๋…๋ฆฝ์ )
Stream<Double> randomStream = Stream.generate(Math::random);
Stream<Integer> oneStream = Stream.generate(() -> 1);
  • ๋žŒ๋‹ค์‹์„ ์†Œ์Šค๋กœ ํ•˜๋Š” ์ŠคํŠธ๋ฆผ ์ƒ์„ฑํ•˜๊ธฐ

์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ - ํŒŒ์ผ๊ณผ ๋นˆ ์ŠคํŠธ๋ฆผ

Stream<Path> Files.list(Path dir); // Path๋Š” ํŒŒ์ผ ๋˜๋Š” ๋””๋ ‰ํ† ๋ฆฌ
Stream<String> Files.lines(Path dir);
Stream<String> Files.lines(Path dir, Charset cs);
Stream<String> lines(); // BufferedReader ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ
  • ํŒŒ์ผ์„ ์†Œ์Šค๋กœ ํ•˜๋Š” ์ŠคํŠธ๋ฆผ ์ƒ์„ฑํ•˜๊ธฐ
Stream emptyStream = Stream.empty(); // empty()๋Š” ๋นˆ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜
long count = emptyStream.count();    // count ๊ฐ’์€ 0
  • ๋น„์–ด์žˆ๋Š” ์ŠคํŠธ๋ฆผ ์ƒ์„ฑํ•˜๊ธฐ

23~25. ์ŠคํŠธ๋ฆผ์˜ ์—ฐ์‚ฐ


์ŠคํŠธ๋ฆผ์˜ ์—ฐ์‚ฐ - ์ค‘๊ฐ„ ์—ฐ์‚ฐ

// ์ค‘๋ณต ์ œ๊ฑฐ
Stream<T> distinct()
// ์กฐ๊ฑด์— ์•ˆ ๋งž๋Š” ์š”์†Œ ์ œ์™ธ
Stream<T> filter(Predicate<T> predicate)
// ์ŠคํŠธ๋ฆผ์˜ ์ผ๋ถ€๋ฅผ ์ž˜๋ผ๋ƒ„
Stream<T> limit(long maxSize)
// ์ŠคํŠธ๋ฆผ์˜ ์ผ๋ถ€๋ฅผ ๊ฑด๋„ˆ๋œ€
Stream<T> skip(long n)
// ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ์— ์ž‘์—… ์ˆ˜ํ–‰
Stream<T> peek(Consumer<T> action)
// ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ๋ฅผ ์ •๋ ฌ
Stream<T> sorted()
Stream<T> sorted(Comparator<T> comparator)
// ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ ๋ณ€ํ™˜
Stream<R>    map(Function<T,R> mapper)
DoubleStream mapToDouble(ToDoubleFunction<T> mapper)
IntStream    mapToInt(ToIntFunction<T> mapper)
LongStream   mapToLong(ToLongFunction<T> mapper)
Stream<R>    flatMap(Function<T,Stream<R>> mapper)
DoubleStream flatMapToDouble(Function<T, DoubleStream> m)
IntStream    flatMapToInt(Function<T, IntStream> m)
LongStream   flatMapToLong(Function<T, LongStream> m)

์ŠคํŠธ๋ฆผ์˜ ์—ฐ์‚ฐ - ์ตœ์ข… ์—ฐ์‚ฐ

// ๊ฐ ์š”์†Œ์— ์ง€์ •๋œ ์ž‘์—… ์ˆ˜ํ–‰
void forEach(Consumer<? super T> action)
void forEachOrdered(Consumer<? super T> action)
// ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ์˜ ๊ฐœ์ˆ˜ ๋ฐ˜ํ™˜
long count()
// ์ŠคํŠธ๋ฆผ์˜ ์ตœ๋Œ€/์ตœ์†Œ๊ฐ’ ๋ฐ˜ํ™˜
Optional<T> max(Comparator<? super T> comparator)
Optional<T> min(Comparator<? super T> comparator)
// ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ ํ•˜๋‚˜ ๋ฐ˜ํ™˜
Optional<T> findAny()   // ์•„๋ฌด๊ฑฐ๋‚˜ ํ•˜๋‚˜
Optional<T> findFirst() // ์ฒซ๋ฒˆ์งธ ์š”์†Œ
// ์ฃผ์–ด์ง„ ์กฐ๊ฑด์„ ๋ชจ๋“  ์š”์†Œ๊ฐ€ ๋งŒ์กฑ์‹œํ‚ค๋Š”์ง€ ํ™•์ธ
boolean allMatch(Predicate<T> p)  // ๋ชจ๋‘ ๋งŒ์กฑํ•˜๋Š”์ง€
boolean anyMatch(Predicate<T> p)  // ํ•˜๋‚˜๋ผ๋„ ๋งŒ์กฑํ•˜๋Š”์ง€
boolean noneMatch(Predicate<T> p) // ๋ชจ๋‘ ๋งŒ์กฑํ•˜์ง€ ์•Š๋Š”์ง€
// ์ŠคํŠธ๋ฆผ์˜ ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜
Object[] toArray()
A[] toArray(IntFunction<A[]> generator)
// ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ๋ฅผ ํ•˜๋‚˜์”ฉ ์ค„์—ฌ๊ฐ€๋ฉด์„œ ๊ณ„์‚ฐ
Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
U reduce(U identity, BiFunction<U,T,U> accumulator BinaryOperator<T> combiner)
// ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ๋ฅผ ์ˆ˜์ง‘. ์ฃผ๋กœ ์š”์†Œ๋ฅผ ๊ทธ๋ฃนํ™”ํ•˜๊ฑฐ๋‚˜ ๋ถ„ํ• ํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ปฌ๋ ‰์…˜์— ๋‹ด์•„ ๋ฐ˜ํ™˜
R collect(Collector<T,A,R> collector)
R collect(Supplier<R> supplier, BiConsumer<R,T> accumulator, BiConsumer<R,R> combiner)

26~34. ์ŠคํŠธ๋ฆผ์˜ ์ค‘๊ฐ„ ์—ฐ์‚ฐ


์ŠคํŠธ๋ฆผ์˜ ์ค‘๊ฐ„ ์—ฐ์‚ฐ

IntStream intStream = IntStream.rangeClosed(1, 10);    // 12345678910
intStream.skip(3).limit(5).forEach(System.out::print); // 45678
  • ์ŠคํŠธ๋ฆผ ์ž๋ฅด๊ธฐ - skip(), limit()
Int intStream = IntStream.of(1,2,2,3,3,3,4,5,5,6);
intStream.distinct().forEach(System.out::print); // 123456
Int intStream = IntStream.rangeClosed(1, 10);               // 12345678910
intStream.filter(i -> i%2 == 0).forEach(System.out::print); // 246810
intStream.filter(i -> i%2 != 0 && i%3 != 0).forEach(System.out::print);
intStream.filter(i -> i%2 != 0).filter(i -> i%3 != 0).forEach(System.out::print);
  • ์ŠคํŠธ๋ฆผ ์š”์†Œ ๊ฑธ๋Ÿฌ๋‚ด๊ธฐ - filter(), distinct()
Stream<T> sorted()                // ์ŠคํŠธ๋ฆผ ์š”์†Œ์˜ ๊ธฐ๋ณธ ์ •๋ ฌ(Comparable)๋กœ ์ •๋ ฌ
Stream<T> sorted(Comparator<? super T> comparator) // ์ง€์ •๋œ Comparator๋กœ ์ •๋ ฌ
  • ์ŠคํŠธ๋ฆผ ์ •๋ ฌํ•˜๊ธฐ - sorted()
// e.g. ํŒŒ์ผ ์ŠคํŠธ๋ฆผ์—์„œ ํŒŒ์ผ ํ™•์žฅ์ž(๋Œ€๋ฌธ์ž)๋ฅผ ์ค‘๋ณต์—†์ด ๋ฝ‘์•„๋‚ด๊ธฐ
fileStream.map(File::getName)                // Stream<File> -> Stream<String>
	.filter(s -> s.indexOf('.') != -1)         // ํ™•์žฅ์ž๊ฐ€ ์—†๋Š” ๊ฒƒ์€ ์ œ์™ธ
	.map(s -> s.substring(s.indexOf('.') + 1)) // Stream<String> -> Stream<String>
	.map(String::toUpperCase)                  // Stream<String> -> Stream<String>
	.distinct()                                // ์ค‘๋ณต ์ œ๊ฑฐ
	.forEach(System.out::print);               // JAVABAKTXT
  • ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ ๋ฐ˜ํ™˜ํ•˜๊ธฐ - map()
fileStream.map(File::getName)                // Stream<File> -> Stream<String>
	.filter(s -> s.indexOf('.') != -1)         // ํ™•์žฅ์ž๊ฐ€ ์—†๋Š” ๊ฒƒ์€ ์ œ์™ธ
	.peek(s -> System.out.printf("filename=%s%n", s)) // ํŒŒ์ผ๋ช… ์ถœ๋ ฅ
	.map(s -> s.substring(s.indexOf('.') + 1)) // Stream<String> -> Stream<String>
	.peek(s -> System.out.printf("extension=%s%n", s)) // ํ™•์žฅ์ž ์ถœ๋ ฅ
	.forEach(System.out::print);               // JAVABAKTXT
  • ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ๋ฅผ ์†Œ๋น„ํ•˜์ง€ ์•Š๊ณ  ์—ฟ๋ณด๊ธฐ - peek()
Stream<String[]> strArrStream = Stream.of(
	new String[]{"abc", "def", "jkl"},
	new String[]{"ABC", "GHI", "JKL"}
);
// ์ŠคํŠธ๋ฆผ์˜ ์ŠคํŠธ๋ฆผ
Stream<Stream<String>> strStreamStream = strArrStream.map(Arrays::stream);
// ์ŠคํŠธ๋ฆผ์˜ ์ŠคํŠธ๋ฆผ -> ์ŠคํŠธ๋ง ์ŠคํŠธ๋ฆผ
Stream<String> strStream = strArrStream.flatMap(Arrays::stream);
  • ์ŠคํŠธ๋ฆผ์˜ ์ŠคํŠธ๋ฆผ์„ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜ - flatMap()

35~39. Optional<T>


Optional<T>

  • T ํƒ€์ž… ๊ฐ์ฒด์˜ ๋ž˜ํผํด๋ž˜์Šค (๊ฐ„์ ‘์ ์œผ๋กœ null ๋‹ค๋ฃจ๊ธฐ)
    • null์„ ์ง์ ‘ ๋‹ค๋ฃจ๋Š” ๊ฒƒ์€ ์œ„ํ—˜
    • null ์ฒดํฌ ์‹œ if๋ฌธ ํ•„์ˆ˜. ์ฝ”๋“œ๊ฐ€ ์ง€์ €๋ถ„
public final class Optional<T> {
	private final T value; // T ํƒ€์ž…์˜ ์ฐธ์กฐ๋ณ€์ˆ˜ (๋ชจ๋“  ์ข…๋ฅ˜์˜ ๊ฐ์ฒด ์ €์žฅ ๊ฐ€๋Šฅ)
		...
}

Optional<T> ๊ฐ์ฒด ์ƒ์„ฑํ•˜๊ธฐ

String str = "abc";
Optional<String> optVal = Optional.of(str);
Optional<String> optVal = Optional.of("abc");
Optional<String> optVal = Optional.of(null);         // NullPointerException ๋ฐœ์ƒ
Optional<String> optVal = Optional.ofNullable(null); // OK.
  • null ๋Œ€์‹  ๋นˆ Optional<T> ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์ž
Optional<String> optVal = null;                     // ๋„๋กœ ์ดˆ๊ธฐํ™”. ๋ฐ”๋žŒ์ง X
Optional<String> optVal = Optional.<String>empty(); // ๋นˆ ๊ฐ์ฒด๋กœ ์ดˆ๊ธฐํ™”

Optional<T> ๊ฐ์ฒด ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ

  • Optional ๊ฐ์ฒด์˜ ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ - get(), orElse(), orElseGet(), orElseThrow()
Optional<String> optVal = Optional.of("abc");
String str1 = optVal.get();                  // optVal์— ์ €์žฅ๋œ ๊ฐ’์„ ๋ฐ˜ํ™˜. null์ด๋ฉด ์˜ˆ์™ธ
String str2 = optVal.orElse("");             // optVal์— ์ €์žฅ๋œ ๊ฐ’์ด null์ด๋ฉด "" ๋ฐ˜ํ™˜
String str3 = optVal.orElseGet(String::new); // ๋žŒ๋‹ค์‹ ์‚ฌ์šฉ๊ฐ€๋Šฅ
String str4 = optVal.orElseThrow(NullPointerException::new); // null์ด๋ฉด ์˜ˆ์™ธ ๋ฐœ์ƒ
  • isPresent() - Optional ๊ฐ์ฑ„์˜ ๊ฐ’์ด null์ด๋ฉด false, ์•„๋‹ˆ๋ฉด true ๋ฐ˜ํ™˜

OptionalInt, OptionalLong, OptionalDouble

  • ๊ธฐ๋ณธํ˜• ๊ฐ’์„ ๊ฐ์‹ธ๋Š” ๋ž˜ํผํด๋ž˜์Šค
  • ๋นˆ Optional ๊ฐ์ฒด์™€์˜ ๋น„๊ต
OptionalInt opt  = OptionalInt.of(0);
OptionalInt opt2 = OptionalInt.empty();
System.out.println(opt.isPresent());  // true
System.out.println(opt2.isPresent()); // false
System.out.println(opt.equals(opt2)); // false