๐ŸšฐJava Stream

Java 8

2 minute read

ํŠน์ง•

  • ์—ฐ์†๋œ ์ •๋ณด๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•œ๋‹ค.
  • Sequence of elements supporting sequential and parallel aggregate operations
  • ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ์ €์žฅ์†Œ(์ปฌ๋ ‰์…˜)์ด ์•„๋‹ˆ๋‹ค.

  • Functional in nature : stream์€ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค.
List<String> names = new ArrayList<>();  
names.add("test");  
  
names.stream().map(String::toUpperCase).forEach(System.out::println);  
names.forEach(System.out::println);  
  
> TEST  
> test  
  • ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์˜ค์ง ํ•œ๋ฒˆ๋งŒ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  • ๋„คํŠธ์›Œํฌ ๋“ฑ ๋ฌด์ œํ•œ stream์ด ์žˆ์„ ์ˆ˜๋„ ์žˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ Short Circuit ๋ฉ”์†Œ๋“œ๋กœ ์ œํ•œํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ค‘๊ฐœ ์—ฐ์‚ฐ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ lazyํ•˜๋‹ค.
List<String> names = new ArrayList<>();  
names.add("test");  
  
names.stream().map(s -> {  
	System.out.println(s);		// ์ข…๋‹จ ์—ฐ์‚ฐ ์ „๊นŒ์ง€๋Š” ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.  
	return s.toUpperCase();  
});  
names.forEach(System.out::println);  
  
> test  
  • parallelStream์„ ์ด์šฉํ•˜์—ฌ ์†์‰ฝ๊ฒŒ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
List<String> names = new ArrayList<>();  
names.add("test1");  
names.add("test2");  
  
List<String> collect = names.parallelStream().map(s -> s.toUpperCase()).collect(Collectors.toList());  
  
collect.forEach(System.out::println);  

์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ

์ค‘๊ฐœ ์—ฐ์‚ฐ

  • stream์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • stateless์™€ stateful ๋ฐฉ์‹์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค. ๋Œ€๋ถ€๋ถ„ stateless์ด์ง€๋งŒ distinct๋‚˜ sorted ๊ฐ™์€ ๊ฒฝ์šฐ stateful์ด๋‹ค.
  • filter, map, limit, skip, sorted, โ€ฆ

์ข…๋‹จ ์—ฐ์‚ฐ

  • stream์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • collect, allMatch, count, forEach, min, max, โ€ฆ

์ŠคํŠธ๋ฆผ API

๊ฑธ๋Ÿฌ๋‚ด๊ธฐ

  • filter(predicate)
  • ํŠน์ • ์กฐ๊ฑด(predicate)๋ฅผ ๋งŒ์กฑํ•˜๋Š” element๋งŒ ์ƒˆ๋กœ์šด stream์œผ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • filter(Predicate.not(OnlineClass::isClosed)) -> !์™€ ๊ฐ™์€ ์—ฐ์‚ฐ์ž๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

๋ณ€๊ฒฝํ•˜๊ธฐ

  • map(function), flatMap(function)
  • ๊ฐ๊ฐ์˜ ์š”์†Œ์—์„œ ํŠน์ •์š”์†Œ๋งŒ ๊บผ๋‚ด๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•˜์—ฌ ์ƒˆ๋กœ์šด stream์œผ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • (ex) List<Stream> -> String์˜ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜

์ƒ์„ฑํ•˜๊ธฐ

  • generate(Supplier) ๋˜๋Š” iterate(T seed, UnaryOperator)
  • seed๋กœ ๋ถ€ํ„ฐ UnaryOperator๋ฅผ ๋ฌด์ œํ•œ์œผ๋กœ ๋ฐ˜๋ณตํ•˜๋Š” stream์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • Random integer ๋ฌด์ œํ•œ ์ŠคํŠธ๋ฆผ ๋“ฑ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์ œํ•œํ•˜๊ธฐ

  • limit(long), skip(long)
  • (ex) ์•ž์—์„œ 3๊ฐœ๋ฅผ ๋บ€ ๋‚˜๋จธ์ง€ stream์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

Stream์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š”์ง€ ํ™•์ธ

  • anyMatch(), allMatch(), nonMatch()
  • stream์˜ element ๋“ค์„ ๋Œ๋ฉด์„œ ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
  • (ex) ์ œ๋ชฉ ์ค‘ test๊ฐ€ ๋“ค์–ด๊ฐ€๋Š”์ง€

๊ฐœ์ˆ˜ ์„ธ๊ธฐ

  • count()

Stream์„ ๋ฐ์ดํ„ฐ ํ•˜๋‚˜๋กœ ๋ญ‰์น˜๊ธฐ

  • reduce(identity, BiFunction), collect(), sum(), max()

ํ†ตํ•ฉ ์˜ˆ์ œ

// ๋ฐ์ดํ„ฐ ์ค€๋น„  
List<OnlineClass> springClasses = new ArrayList<>();  
springClasses.add(new OnlineClass(1, "spring boot", true));  
springClasses.add(new OnlineClass(2, "spring data jpa", true));  
springClasses.add(new OnlineClass(3, "spring mvc", false));  
springClasses.add(new OnlineClass(4, "spring core", false));  
springClasses.add(new OnlineClass(5, "rest api development", false));  
  
List<OnlineClass> javaClasses = new ArrayList<>();  
javaClasses.add(new OnlineClass(6, "The Java, Test", true));  
javaClasses.add(new OnlineClass(7, "The Java, Code mainpulation", true));  
javaClasses.add(new OnlineClass(8, "The Java 8 to 11", false));  
  
List<List<OnlineClass>> events = new ArrayList<>();  
events.add(springClasses);  
events.add(javaClasses);  
  
// spring์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ์ˆ˜์—…  
springClasses.stream()  
	.filter(oc -> oc.getTitle().startsWith("spring")  
	.forEach(System.out::println);  
  
// closed๋˜์ง€ ์•Š๋Š” ์ˆ˜์—…  
springClasses.stream()  
	.filter(Predicate.not(OnlineClass::isClosed))  
	.forEach(System.out::println);  
  
// ์ˆ˜์—… ์ด๋ฆ„๋งŒ ๋ชจ์•„์„œ stream๋งŒ๋“ค๊ธฐ  
Stream<String> springTitleStream = springClasses.stream()  
	.map(OnlineClass::getTitle);  
  
// ๋‘ ์ˆ˜์—… ๋ชฉ๋ก์— ๋“ค์–ด์žˆ๋Š” ๋ชจ๋“  ์ˆ˜์—… ์•„์ด๋”” ์ถœ๋ ฅ  
events.stream()  
	.flatMap(Collection::stream)	// 2์ฐจ์› ๋ฆฌ์ŠคํŠธ๋ฅผ 1์ฐจ์›์œผ๋กœ ํ‰ํƒ„ํ™”  
	.forEach(oc -> System.out.println(oc.getId());  
  
// 10๋ถ€ํ„ฐ 1์”ฉ ์ฆ๊ฐ€ํ•˜๋Š” ๋ฌด์ œํ•œ ์ŠคํŠธ๋ฆผ ์ค‘์—์„œ ์•ž์— 10๊ฐœ ๋นผ๊ณ  ์ตœ๋Œ€ 10๊ฐœ๊นŒ์ง€๋งŒ  
Stream.iterate(10, i -> i + 1)  
	.skip(10)  
	.limit(10)  
	.forEach(System.out::println);  
  
// ์ž๋ฐ” ์ˆ˜์—… ์ค‘์— Test๊ฐ€ ๋“ค์–ด์žˆ๋Š” ์ˆ˜์—…์ด "์žˆ๋Š”์ง€" ํ™•์ธ  
boolean test = jaaClasses.stream()  
	.anyMatch(oc -> oc.getTitle().contains("Test"));  
  
// ์Šคํ”„๋ง ์ˆ˜์—… ์ค‘์— ์ œ๋ชฉ์ด spring์ด ๋“ค์–ด๊ฐ„ ์ œ๋ชฉ๋งŒ ๋ชจ์•„์„œ List๋กœ ๋งŒ๋“ค๊ธฐ  
List<String> spring = springClasses.stream()  
	.filter(oc -> oc.getTitle().contains("spring")  
	.map(OnlineClass::getTitle)  
	.collect(Collector.toList());  

[1] ๋ฐฑ๊ธฐ์„ , ๋” ์ž๋ฐ” Java 8, Optional