์คํธ๋ฆผ์ด ๋์ ๋๊ธฐ ์ด์ ์ ์์ ์ํ์ค, ์ฆ ์ผ๋ จ์ ์์๋ฅผ ๋ฐํํ๋ ๋ฉ์๋์ ๋ฐํ ํ์ ์ผ๋ก Collection, Set, List๊ณผ ๊ฐ์ ์ปฌ๋ ์ ์ธํฐํ์ด์ค๋ Iterable ๋๋ ๋ฐฐ์ด์ ์ฌ์ฉํ๋ค.
Collection
,Set
,List
:- ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋๋ ๊ธฐ๋ณธ ์ธํฐํ์ด์ค.
- ๋ฐ๋ณต(iteration)๊ณผ ๋ค์ํ ์ ํธ๋ฆฌํฐ ๋ฉ์๋(
size
,contains
,add
,remove
๋ฑ)๋ฅผ ์ ๊ณต.
Iterable
:- ๋จ์ ๋ฐ๋ณต์ ์ํ ์ธํฐํ์ด์ค.
- ์ปฌ๋ ์ ๋ณด๋ค ๊ฐ๋จํ ์ธํฐํ์ด์ค๋ก, for-each ๋ฃจํ์์ ์ฌ์ฉ ๊ฐ๋ฅ.
- ๋ฐฐ์ด(Array):
- ๊ธฐ๋ณธ ํ์ ์ ๋ค๋ฃจ๊ฑฐ๋ ์ฑ๋ฅ์ด ์ค์ํ ๊ฒฝ์ฐ ์ฌ์ฉ.
- ํฌ๊ธฐ๊ฐ ๊ณ ์ ๋๊ณ , ์ปฌ๋ ์ ์ธํฐํ์ด์ค์ ์ ์ฐ์ฑ์ ์ ๊ณตํ์ง ์์.
- ๋ฐ๋ณต๊ณผ ์ปฌ๋ ์
๋ฉ์๋ ์ ๊ณต ์ฌ๋ถ:
- ์ปฌ๋ ์ ์ธํฐํ์ด์ค๊ฐ ์ ํฉ: ๋๋ถ๋ถ์ ๊ฒฝ์ฐ, ์ปฌ๋ ์ ์ ์ฌ์ฉ.
- ๋จ์ ๋ฐ๋ณต๋ง ํ์ํ ๊ฒฝ์ฐ:
Iterable
์ฌ์ฉ.
- ์ฑ๋ฅ ๋ฏผ๊ฐ๋:
- ๋ฐฐ์ด์ ์ฌ์ฉํ์ฌ ์ค๋ฒํค๋๋ฅผ ์ค์.
Java 8์์๋ ์คํธ๋ฆผ(Stream)์ด ๋ฑ์ฅํ๋ฉฐ, ์์ ์ํ์ค๋ฅผ ๋ฐํํ ๋ ์ ํ์ง๊ฐ ๋ณต์กํด์ก๋ค.
์คํธ๋ฆผ์ ๋ฐ๋ณต(iteration)์ ์ง์ํ์ง ์๋๋ค. ๋ฐ๋ผ์ ์์ ์ํ์ค๋ฅผ ๋ฐํํ ๋ ์คํธ๋ฆผ์ ์ฌ์ฉํ๋ฉด ์๋์ ๊ฐ์ด for-each
๋ก ๋ฐ๋ณต์ ์ํํ ์ ์๋ค.
for (ProcessHandle ph : ProcessHandle.allProcesses()::iterator) {
// ํ๋ก์ธ์ค๋ฅผ ์ฒ๋ฆฌํ๋ค.
}
}
for-each
์ ๊ฐ์ด ํฅ์๋ for ๋ฌธ์ด ๊ฐ๋ฅํ ์ปฌ๋ ์
์ Iterable
์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๊ณ ์์ด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค. Stream
์ธํฐํ์ด์ค๋ Iterable
์ธํฐํ์ด์ค๊ฐ ์ ์ํ ์ถ์ ๋ฉ์๋๋ฅผ ํฌํจํ๊ณ ์ ์ํ ๋ฐฉ์๋๋ก ๋์ํ์ง๋ง, ํ์ฅ(extend) ํ์ง ์์๊ธฐ ๋๋ฌธ์ ๋ฐ๋ณต์ด ๋ถ๊ฐ๋ฅํ๋ค.
ํ์ง๋ง ProcessHandle.allProcesses()
๋ ์คํธ๋ฆผ(Stream<ProcessHandle>
)์ ๋ฐํํ๋ฏ๋ก, ์ด๋ฅผ for-each
์์ ๋ฐ๋ก ์ฌ์ฉํ ์ ์๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ:
::iterator
๋ฅผ ์ฌ์ฉ: ์คํธ๋ฆผ์Iterable
๋ก ๋ณํํ์ฌfor-each
์ฌ์ฉ.collect()
๋ก ์ปฌ๋ ์ ์ผ๋ก ๋ณํ:Stream
์ ๋ช ์์ ์ผ๋กList
๋๋Set
์ผ๋ก ๋ณํํ์ฌ ์ฒ๋ฆฌ.
๊ธฐ์กด ๋ฐฉ๋ฒ: ::iterator
๋ก Iterable ๋ณํ
@Test
public void processHandleTestUsingIterator() {
// Stream์ Iterable๋ก ๋ณํ
Iterable<ProcessHandle> processHandles = ProcessHandle.allProcesses()::iterator;
// for-each ์ฌ์ฉ
for (ProcessHandle processHandle : processHandles) {
System.out.println("Process Info: " + processHandle.info());
}
}
- ํ์
์ถ๋ก ์ด ๋ถํธ:
- IDE๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ ์ ์ ํํ ์ถ๋ก ํ์ง ๋ชปํ๋ฉฐ, ์๋ ์บ์คํ ์ด ํ์ํ ์ ์์.
Runnable
,Executable
๋ฑ ๋ค๋ฅธ ํ์ ์ ์ถ์ฒํ๋ ๊ฒฝ์ฐ๋ ๋ฐ์.
- ๊ฐ๋
์ฑ ์ ํ:
::iterator
๋ฐฉ์์ ์ง๊ด์ ์ด์ง ์์ผ๋ฉฐ, ์ฝ๋๋ฅผ ์ฝ๋ ์ฌ๋์๊ฒ ํผ๋์ ์ค ์ ์์.
public interface Stream<T> extends BaseStream<T, Stream<T>> {
}
๊ทธ๋ ๋ค๋ฉด ์คํธ๋ฆผ์ ๋ฐ๋ณตํ ์ ์๊ฒ ํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น?
Java์์ ์คํธ๋ฆผ๊ณผ Iterable ํ์ ์ ํ์์ ๋ฐ๋ผ ๋ณํํ ์ ์๋๋ก ์ด๋ํฐ ๋ฉ์๋๋ฅผ ์ ๊ณตํ์ฌ ์ ์ฐํ๊ฒ ์ฌ์ฉํ ์ ์๋ค. ์ด๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ฑฐ๋ ๋ฐ๋ณตํ๋ ค๋ ์ํฉ์์ ์ฝ๋์ ํ์ฉ์ฑ์ ๋์ฌ์ค๋ค.
// Stream -> Iterable ๋ณํ ๋ฉ์๋
public static <E> Iterable<E> iterableOf(Stream<E> stream) {
// ์คํธ๋ฆผ์ iterator() ๋ฉ์๋๋ฅผ ์ด์ฉํด Iterable ๋ฐํ
return stream::iterator;
}
// Iterable -> Stream ๋ณํ ๋ฉ์๋
public static <E> Stream<E> streamOf(Iterable<E> iterable) {
// Iterable์ Stream์ผ๋ก ๋ณํ (Spliterator ์ฌ์ฉ)
return StreamSupport.stream(iterable.spliterator(), false);
}
iterableOf()
์streamOf()
๋ผ๋ ๋๊ฐ์ง ์ด๋ํฐ ๋ฉ์๋๋ก ์๋ก์ ํ์ ์ ์ฝ๊ฒ ์ค๊ฐ ์ ์๊ฒ ๋ง๋ค์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์๋ ์๋ค.- Collection ์ธํฐํ์ด์ค๋ stream() ๊ณผ Iterable ๊ตฌํ ๋ชจ๋ ํ๊ธฐ ๋๋ฌธ์ ๊ธฐ์์ด๋ฉด Collection ์ด๋ ๊ทธ ํ์ ํ์ ์ ๋ฐํ ํน์ ํ๋ผ๋ฏธํฐ ํ์ ์ ์ฌ์ฉํ๋ ๊ฒ ์ต์ ์ด๋ค.
- ๋จ์ง ์ปฌ๋ ์ ์ ๋ฐํํ๋ค๋ ์ด์ ๋ก ๋ฉ์น ํฐ ์ํ์ค1๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ ค์๋ ์๋๋ค.
์ํ์ค๊ฐ ํฌ์ง๋ง, ํํ ๋ฐฉ์์ด ๊ฐ๋จํด์ง ์ ์๋ค๋ฉด, ์ ์ฉ ์ปฌ๋ ์ ์ ๊ตฌํํด๋ณด์.
์ด๋ํฐ ๋ฉ์๋ ํ์ฉ ์์ : ์ด๋ํฐ ๋ฉ์๋๋ฅผ ํตํ Stream -> Iterable -> Stream ๋ณํ ์์
@Test
void streamIterableTest() {
// ProcessHandle ์คํธ๋ฆผ ์์ฑ
Stream<ProcessHandle> handleStream = ProcessHandle.allProcesses();
// ์คํธ๋ฆผ์ ์ด์ฉํ ํ๋ก์ธ์ค ์ ๋ณด ์ถ๋ ฅ
handleStream.forEach(p -> System.out.println(p.info()));
// Stream -> Iterable ๋ณํ ํ for-each ๋ฌธ ์ฌ์ฉ
Iterable<ProcessHandle> handles = iterableOf(handleStream);
for (ProcessHandle handle : handles) {
System.out.println(handle.info());
}
// Iterable -> Stream ๋ณํ ํ ๋ค์ ์คํธ๋ฆผ ์ฒ๋ฆฌ
Stream<ProcessHandle> stream = streamOf(handles);
stream.forEach(p -> System.out.println(p.info()));
}
- ์คํธ๋ฆผ ํ์ฉ์ด ๊ฐ๋จํ ๊ฒฝ์ฐ: ์คํธ๋ฆผ์ ์ฌ์ฉํ๊ณ ์ง์
forEach()
๋ฅผ ์ด์ฉํด ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ์. - Iterable ํ์
์ ๋ฐ๋์ ์ฌ์ฉํด์ผ ํ๋ ๊ฒฝ์ฐ: ์ด๋ํฐ ๋ฉ์๋๋ฅผ ์ด์ฉํ์ฌ ์คํธ๋ฆผ์ Iterable๋ก ๋ณํํ๊ฑฐ๋ ์ปฌ๋ ์
์ผ๋ก ์์ง(
collect()
)ํ๋ ๋ฐฉ๋ฒ์ ๊ณ ๋ คํ์.
๋ฉฑ์งํฉ(Power Set)
์ ๋ชจ๋ ๋ถ๋ถ ์งํฉ์ ์์๋ก ๊ฐ์ง๋ ์งํฉ์ ๋งํ๋ค. ์ด ๊ฒฝ์ฐ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ฆฌ๊ธฐ๋ณด๋ค๋ ํ์ํ ์์ ์ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด ๋ ํจ์จ์ ์ด๋ค.
์ ๋ ฅ ์งํฉ์ ์์ ์๊ฐ 30์ ๋์ผ๋ฉด PowerSet.of๊ฐ ์์ธ๋ฅผ ๋์ง๋ค. ์ด๋ Stream์ด๋ Iterable์ด ์๋ Collection์ ๋ฐํ ํ์ ์ผ๋ก ์ธ ๋์ ๋จ์ ์ ์ ๋ณด์ฌ์ค๋ค. ๋ค์ ๋งํด, Collection์ size ๋ฉ์๋๊ฐ int ๊ฐ์ ๋ฐํํ๋ฏ๋ก PowerSet.of๊ฐ ๋ฐํ๋๋ ์ํ์ค์ ์ต๋ ๊ธธ์ด๋ Integer.MAX_VALUE ํน์ 2^n-1๋ก ์ ํ๋๋ค. Collection ๋ช ์ธ์ ๋ฐ๋ฅด๋ฉด ์ปฌ๋ ์ ์ด ๋ ํฌ๊ฑฐ๋ ์ฌ์ง์ด ๋ฌดํ๋์ผ ๋ size๊ฐ 2^n-1์ ๋ฐํํด๋ ๋์ง๋ง ์์ ํ ๋ง์กฑ ์ค๋ฌ์ด ํด๋ฒ์ ์๋๋ค.
static class PowerSet {
public static final <E> Collection<Set<E>> of(Set<E> s) {
List<E> src = new ArrayList<>(s);
int numberOfMaximumElements = 30; // ์์ ๊ฐ์ ์ ํ (์ต๋ 30)
if (src.size() > numberOfMaximumElements) {
throw new IllegalArgumentException("์งํฉ์ ์์๊ฐ ๋๋ฌด ๋ง์ต๋๋ค. (์ต๋ " + numberOfMaximumElements + " ๊ฐ)");
}
// AbstractList๋ฅผ ์ด์ฉํด ํ์ํ ๋ถ๋ถ์งํฉ์ ๋์ ์ผ๋ก ์์ฑ
return new AbstractList<>() {
@Override
public Set<E> get(int index) {
Set<E> result = new HashSet<>();
for (int i = 0; index != 0; i++, index >>= 1) {
if ((index & 1) == 1) {
result.add(src.get(i));
}
}
return result;
}
@Override
public int size() {
// ๋ฉฑ์งํฉ์ ํฌ๊ธฐ = 2^์์์ ์
return 1 << src.size();
}
@Override
public boolean contains(Object o) {
return o instanceof Set && src.containsAll((Set<?>) o);
}
};
- ๋ฉฑ์งํฉ์ ๊ตฌํด์ผ ํ๋ ๊ฒฝ์ฐ์ ๊ตณ์ด ํญ์ ๋ชจ๋ ์ปฌ๋ ์ ์์๋ฅผ ๋ฉ๋ชจ๋ฆฌ์์ ์ฌ๋ฆฌ๊ณ ์์ ํ์๋ ์๋ค.
get() ๋ฉ์๋
๋ฅผ ํตํด ํ์ํ ์์ ์ ํ์ํ ์๋ฆฌ๋จผํธ๋ฅผ ์ป์ผ๋ฉด ๋๋ค.- ๋ชจ๋ ์์๋ฅผ ๊ฐ์ง๊ณ ์๊ธฐ์ 2^length๋งํผ์ ๊ณต๊ฐ์ ํ๋ณดํด์ผ ํ๋ ๋ถ๋ด์ด ์๋ค.
- ๋ชจ๋ ์์๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉด ๋งค๋ฒ ๋ณ๊ฒฝ์ฌํญ์ด ์๊ธธ ๋๋ง๋ค ๋ฉฑ์งํฉ์ ์๋ก ๊ตฌํด์ผ ํ๋ค.
- AbstractCollection ์ contains() ์ size() ๋ง ๊ตฌํํด์ฃผ๋ฉด ๊ตฌํ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๋ค.
- ์ด ๊ฒฝ์ฐ๊ฐ Collection ์ ๋ฐํํ๊ธฐ ์ ๋นํ ํํ๋ค.
- Stream ์ size ๋ฅผ ๊ตฌํ ์ ์๊ธฐ ๋๋ฌธ์ ์ด ๊ฒฝ์ฐ์ ์ ํฉํ์ง ์๋ค.
{% hint style="info" %} ์ถ์ฒ์ฌํญ {% endhint %}
- ํฐ ์ํ์ค๋ฅผ ์ฒ๋ฆฌํ ๋: ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ฆฌ๊ธฐ๋ณด๋ค ํ์ํ ์์ ์ ๋์ ์ผ๋ก ์์ฑํ๋๋ก ์ค๊ณํ์.
- ์ปฌ๋ ์ ์ ์ฌ์ฉํ๋ ์ด์ : ๋ฉฑ์งํฉ๊ณผ ๊ฐ์ด ๋ฐ์ดํฐ ์ฌ์ฌ์ฉ์ด ์ค์ํ๊ฑฐ๋, ๋ฐ๋ณต(iteration)์ด ๋ง์ด ๋ฐ์ํ๋ ๊ฒฝ์ฐ์ ์ ํฉํ๋ค.
{% hint style="danger" %}
Stream์ size()
๋๋ length
๊ฐ ์๋ ์ด์
{% endhint %}
๊ฒ์ผ๋ฅธ ํ๊ฐ๋ก ์ธํด ์ ์ฒด ๋ฐ์ดํฐ์ ํฌ๊ธฐ๋ฅผ ์ ์ ์๊ธฐ ๋๋ฌธ
- ๊ฒ์ผ๋ฅธ ํ๊ฐ๋ก ์ธํด ์ ํํ ํฌ๊ธฐ ์์ธก ๋ถ๊ฐ:
- ์คํธ๋ฆผ์ ๋ฐ์ดํฐ๋ฅผ ํ์ํ ๋๋ง ๊ฒ์ผ๋ฅด๊ฒ ํ๊ฐํ๋ค.
- ํ๊ฐ๊ฐ ์ด๋ฃจ์ด์ง๊ธฐ ์ ๊น์ง, ๋ฐ์ดํฐ๊ฐ ๋ช ๊ฐ์ ์์๋ฅผ ํฌํจํ ์ง ์ ์ ์๊ธฐ ๋๋ฌธ์, ์ ํํ ํฌ๊ธฐ๋ฅผ ๋ฐํํ๋
size()
์ ๊ฐ์ ๋ฉ์๋๋ฅผ ์ ๊ณตํ ์ ์๋ค.
- ๋ฐ์ดํฐ ๋ณํ์ ๋ถํ์ค์ฑ:
- ์คํธ๋ฆผ์ ๋ฐ์ดํฐ ๋ณํ์ ์ฌ๋ฌ ๋จ๊ณ์ ๊ฑธ์ณ ์ํํ ์ ์๋ค.
- ๋ณํ ๊ณผ์ ์์ ํํฐ๋ง๋๊ฑฐ๋ ์ถ๊ฐ๋๋ ๋ฐ์ดํฐ๊ฐ ์์ ์ ์๊ธฐ ๋๋ฌธ์, ์ต์ข ํฌ๊ธฐ๋ฅผ ์์ธกํ๊ธฐ ์ด๋ ต๋ค.
- ๋์
count()
๋ฉ์๋ ์ ๊ณต:- ์คํธ๋ฆผ์
size()
๋์count()
๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค. count()
๋ฉ์๋๋ ์คํธ๋ฆผ์ ์์ ๊ฐ์๋ฅผ ๊ณ์ฐํ์ฌ ๋ฐํํ์ง๋ง, ์คํธ๋ฆผ์ ์๋ชจํ๋ค. ์ฆ, ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ ์๋นํ์ฌ ๊ฐ์๋ฅผ ๊ณ์ฐํ๊ธฐ ๋๋ฌธ์ ์ดํ์๋ ํด๋น ์คํธ๋ฆผ์ ๋ค์ ์ฌ์ฉํ ์ ์๋ค.
- ์คํธ๋ฆผ์
Stream<String> names = Stream.of("Alice", "Bob", "Charlie");
long count = names.count(); // ์คํธ๋ฆผ์ ์์ ๊ฐ์ ๋ฐํ (3)
count()
๋ฅผ ์ฌ์ฉํ์ฌ ์คํธ๋ฆผ์ ๊ฐ์๋ฅผ ๊ณ์ฐํ ์ ์์ง๋ง, ์ด ๊ณผ์ ์์ ์คํธ๋ฆผ์ด ์๋ชจ๋๊ธฐ ๋๋ฌธ์ ์ดํ์ ๋์ผํ ์คํธ๋ฆผ์ ๋ค์ ์ฌ์ฉํ ์ ์๋ค.
๋ฆฌ์คํธ์ ๋ถ๋ถ ๋ฆฌ์คํธ๋ฅผ ์์ฑํ๊ณ ์ฒ๋ฆฌํ๋ ์์ ์ ์คํธ๋ฆผ์ ์ฌ์ฉํ๋ฉด ๊ฐ๊ฒฐํ๊ณ ๊ฐ๋ ์ฑ์ด ์ข๋ค.
static class SubLists {
// ์ฃผ์ด์ง ๋ฆฌ์คํธ์ ๋ชจ๋ ์ ๋์ฌ์ ์ ๋ฏธ์ฌ๋ฅผ ์คํธ๋ฆผ์ผ๋ก ๋ฐํ
public static <E> Stream<List<E>> of(List<E> list) {
Stream<List<E>> prefixes = prefixes(list);
Stream<List<E>> suffixes = suffixes(list);
return Stream.concat(prefixes, suffixes);
}
// ๋ฆฌ์คํธ์ ๋ชจ๋ ์ ๋์ฌ ๋ฐํ
private static <E> Stream<List<E>> prefixes(List<E> list) {
return IntStream.rangeClosed(1, list.size())
.mapToObj(end -> list.subList(0, end));
}
// ๋ฆฌ์คํธ์ ๋ชจ๋ ์ ๋ฏธ์ฌ ๋ฐํ
private static <E> Stream<List<E>> suffixes(List<E> list) {
return IntStream.range(0, list.size())
.mapToObj(start -> list.subList(start, list.size()));
}
}
@Test
void subListStreamTest() {
List<String> list = Arrays.asList("A", "B", "C", "D");
// ๋ถ๋ถ ๋ฆฌ์คํธ ์์ฑ ๋ฐ ์ฒ๋ฆฌ
SubLists.of(list).forEach(subList -> System.out.println("SubList: " + subList));
}
- ๋ฐ์ดํฐ ๋ณํ์ด๋ ํํฐ๋ง์ด ์ฃผ์ํ ๊ฒฝ์ฐ, ์คํธ๋ฆผ์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌ
- ๋ถ๋ถ ๋ฆฌ์คํธ์ ๊ฐ์ ๋ฐ๋ณต์ด ์์ฐ์ค๋ฌ์ด ๊ฒฝ์ฐ ์คํธ๋ฆผ์ด ๊ฐ๋ ์ฑ๊ณผ ์ฑ๋ฅ ๋ชจ๋์์ ๋ ์ ๋ฆฌ๋ค.
@Test
void streamFilteringTest() {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// ์ด๋ฆ์ด 'A'๋ก ์์ํ๋ ์ด๋ฆ๋ง ํํฐ๋งํ๊ณ ๋ชจ๋ ๋๋ฌธ์๋ก ๋ณํ
names.stream()
.filter(name -> name.startsWith("A")) // 'A'๋ก ์์ํ๋ ์ด๋ฆ ํํฐ๋ง
.map(String::toUpperCase) // ๋๋ฌธ์๋ก ๋ณํ
.forEach(System.out::println); // ์ถ๋ ฅ
// ์ถ๋ ฅ ๊ฒฐ๊ณผ: ALICE
}
@Test
void collectionReuseTest() {
List<String> items = Arrays.asList("apple", "banana", "cherry");
// ์ฒซ ๋ฒ์งธ ๋ฐ๋ณต: ๊ฐ ์์ดํ
์ ์ถ๋ ฅ
for (String item : items) {
System.out.println("Item: " + item);
}
// ๋ ๋ฒ์งธ ๋ฐ๋ณต: ๊ฐ ์์ดํ
์ ๊ธธ์ด ์ถ๋ ฅ
for (String item : items) {
System.out.println("Item length: " + item.length());
}
}
- ์ปฌ๋ ์ ์ฌ์ฉ ์ด์ : ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฌ ๋ฒ ๋ฐ๋ณตํ๊ฑฐ๋ ์ฌ์ฌ์ฉํด์ผ ํ ๋ ์ปฌ๋ ์ ์ด ๋ ์ ํฉํ๋ค.
- ์คํธ๋ฆผ์ ์ผํ์ฑ ์ฌ์ฉ์ด ๊ธฐ๋ณธ์ด๊ธฐ ๋๋ฌธ์ ๋ฐ๋ณต ์ฌ์ฉ์ด ํ์ํ ๊ฒฝ์ฐ ์ปฌ๋ ์ ์ด ๋ ํจ์จ์ ์ด๋ค.
{% hint style="success" %}
Stream ์ ๋ฐํ ํ์
์ผ๋ก ์ฌ์ฉํ๊ธฐ๋ณด๋ค๋ ๋จ์ํ ์ปฌ๋ ์
์ฒ๋ฆฌ๋ฅผ ์ํด ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค. ๋ฐํ์ ๋ค์ ์ปฌ๋ ์
์ผ๋ก ๋ณ๊ฒฝํด์ฃผ๋ ๊ฒ์ด ํ์ฉ์ฑ์ด ์ข๋ค. someStream.collect(Collectors.toList())
์ ๊ฐ์ ํจ์๋ฅผ ์ด์ฉํ๋ฉด ์ฝ๋ค.
{% endhint %}
๋ฐํ ์ ๋ถํฐ ์ด๋ฏธ ์์๋ค์ ์ปฌ๋ ์
์ ๋ด์ ๊ด๋ฆฌํ๊ณ ์๊ฑฐ๋ ์์ ๊ฐ์๊ฐ ์ ๋ค๋ฉด ArrayList
๊ณผ ๊ฐ์ ํ์ค ์ปฌ๋ ์
์ ๋ด์ ๋ฐํํ์. ๊ทธ๋ ์ง ์๋ค๋ฉด, ์ ์ฉ ์ปฌ๋ ์
์ ๊ตฌํํ ์๋ ์๋ค. ์ปฌ๋ ์
์ ๋ฐํํ๋๊ฒ ๋ถ๊ฐ๋ฅํ๋ค๋ฉด ์คํธ๋ฆผ๊ณผ Iterable
์ค ๋ ์์ฐ์ค๋ฌ์ด ๊ฒ์ ๋ฐํํ๋ฉด ๋๋ค.
์ปฌ๋ ์ ์ ๋ฐ๋ณต๊ณผ ์ฌ์ฌ์ฉ์ ์ ํฉํ๊ณ , ์คํธ๋ฆผ์ ๋ณํ๊ณผ ์ฒ๋ฆฌ์ ๋ ๊ฐ๋ ฅ
- ์คํธ๋ฆผ์ ๋๋ฆ๋๋ก์ ์ฅ๋จ์ ์ด ์์ด์, ๊ฒฝ์ฐ์ ๋ง๊ฒ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
- ๊ฐ์ฅ ํฐ ์ฅ์ ์ด์ ๋จ์ ์ด
์ง์ฐ ํ๊ฐ
๊ฐ ๋๋ค๋ ๊ฒ์ด๋ค. - ๊ธฐ๋ณธ์ ์ผ๋ก๋ ์ปฌ๋ ์
์ ๋ฐํํ๋ ๊ฒ ์ ์ฐํ๋ค. ๊ฐ๋ฅํ ๊ฒฝ์ฐ ์ปฌ๋ ์
์ ๋ฐํํ์ฌ
stream()
๊ณผfor-each
๋ฅผ ๋ชจ๋ ์ง์ํ๋๋ก ํ๊ณ , ๋ฐ์ดํฐ๊ฐ ํฌ๊ฑฐ๋ ์ผํ์ฑ์ด๋ผ๋ฉด ์คํธ๋ฆผ์ ๋ฐํํ๋ ๊ฒ์ด ์ข๋ค.
{% hint style="success" %} ์ปฌ๋ ์ ์ฌ์ฉ ์ถ์ฒ ์์ : {% endhint %}
- ๋ฐ์ดํฐ๊ฐ ์ฌ๋ฌ ๋ฒ ๋ฐ๋ณต๋๊ฑฐ๋ ์ฌ์ฌ์ฉ์ด ํ์ํ ๋.
- ๋ฐ์ดํฐ์ ์ ์ฒด ํฌ๊ธฐ๋ฅผ ํ์ ํด์ผ ํ ๋.
{% hint style="success" %} ์คํธ๋ฆผ ์ฌ์ฉ ์ถ์ฒ ์์ : {% endhint %}
- ๋ฐ์ดํฐ ๋ณํ ๋ฐ ํํฐ๋ง์ด ์ฃผ์ ์์ ์ผ ๋.
- ์ง์ฐ ์คํ์ ํตํด ํจ์จ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํด์ผ ํ ๋.
ํ๊ฐ(Evaluation)๋ ์คํธ๋ฆผ์ด ์ฐ์ฐ์ ๋๋ด๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ ๊ณผ์ ์ ์๋ฏธํ๋ค.
์คํธ๋ฆผ์ ์ง์ฐ ์คํ(Lazy Evaluation)์ ํตํด ํ์ํ ๋ฐ์ดํฐ๋ง ์ฒ๋ฆฌํ๋ฉฐ, ์ต์ข
์ฐ์ฐ(Terminal Operation)์ด ํธ์ถ๋๊ธฐ ์ ๊น์ง๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ์ํํ์ง ์๋๋ค. ํ๊ฐ ๋จ๊ณ์์ ์คํธ๋ฆผ์ ๋ ์ด์ ์คํธ๋ฆผ ํ์
(Stream)์ด ์๋๋ฉฐ, ๊ฒฐ๊ณผ๋ฅผ ํน์ ์๋ฐ ๊ฐ์ฒด๋ก ๋ฐํํ๋ค.
ํ๊ฐ๋ ์คํธ๋ฆผ ์ฐ์ฐ์ด ์๋ฃ๋์ด ๊ฒฐ๊ณผ๊ฐ ๋ฐํ๋๋ ์ํ๋ฅผ ๋งํ๋ค.
๋ค์๊ณผ ๊ฐ์ ์ต์ข
์ฐ์ฐ(Terminal Operation)์ ํตํด ํ๊ฐ๊ฐ ์ด๋ฃจ์ด์ง๋ค:
- ๋ฐ์ดํฐ๋ฅผ ์ปฌ๋ ์
, ๋ฐฐ์ด ๋ฑ์ผ๋ก ๋ณํ:
- ์:
toArray()
,collect()
- ์:
- ์ฐ์ฐ ๊ฒฐ๊ณผ๋ฅผ ํ๋์ ๊ฐ์ผ๋ก ์ถ์:
- ์:
reduce()
- ์:
- ๋ฐ์ดํฐ๋ฅผ ์๋นํ๊ฑฐ๋ ์ถ๋ ฅ:
- ์:
forEach()
- ์:
- ๋จ์ผ ์กฐ๊ฑด์ ํ๊ฐ:
- ์:
findFirst()
,anyMatch()
,allMatch()
- ์:
์คํธ๋ฆผ์ ํ๊ฐ ์ ๊น์ง ์คํ๋์ง ์๋๋ค (์ง์ฐ ์คํ)
์ค๊ฐ ์ฐ์ฐ(Intermediate Operation)
์ ๋ฐ์ดํฐ๋ฅผ ๋ณํํ๋ ์์ ์ ์ ์ํ์ง๋ง, ์ค์ ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ์ง๋ ์๋๋ค.- ์คํธ๋ฆผ์ ์ต์ข ์ฐ์ฐ(Terminal Operation)์ด ํธ์ถ๋ ๋๋ง ์คํ๋๋ค.
์์ : ์ง์ฐ ์คํ
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// ์ค๊ฐ ์ฐ์ฐ: ์คํ๋์ง ์์
Stream<String> stream = names.stream()
.filter(name -> {
System.out.println("Filtering: " + name);
return name.startsWith("A");
});
// ์ต์ข
์ฐ์ฐ: ์ฌ๊ธฐ์ ํ๊ฐ๊ฐ ๋ฐ์
List<String> result = stream.collect(Collectors.toList());
// ์ถ๋ ฅ:
// Filtering: Alice
// Filtering: Bob
// Filtering: Charlie
filter
๋ ์ค๊ฐ ์ฐ์ฐ์ผ๋ก ์ ์๋ง ๋์์ผ๋ฉฐ, ์ค์ ๋ก ๋ฐ์ดํฐ๋ ์ฒ๋ฆฌ๋์ง ์๋๋ค.collect
๊ฐ ํธ์ถ๋๋ฉด์ ์คํธ๋ฆผ์ด ํ๊ฐ๋๊ณ ๊ฒฐ๊ณผ๊ฐ ๋ฐํ๋๋ค.
๋จ๋ฝ ์กฐ๊ฑด (Short-Circuiting Condition)
- ์ผ๋ถ ์ต์ข ์ฐ์ฐ์ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ์ง ์๊ณ ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์๋ค.
- ๋จ๋ฝ ์กฐ๊ฑด์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๊ฐ ์๋ฃ๋ ์ ์๋ ์กฐ๊ฑด์ ๋งํ๋ค.
๋จ๋ฝ ์กฐ๊ฑด์ด ์ ์ฉ๋๋ ์ฐ์ฐ
์ฐ์ฐ | ์ค๋ช | ์์ |
---|---|---|
findFirst() | ์ฒซ ๋ฒ์งธ ์์๋ฅผ ์ฐพ์ผ๋ฉด ์คํธ๋ฆผ ์ฒ๋ฆฌ๊ฐ ์ข ๋ฃ๋ฉ๋๋ค. | stream.findFirst() |
anyMatch() | ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์๋ฅผ ํ๋๋ผ๋ ์ฐพ์ผ๋ฉด ์ฒ๋ฆฌ ์ข ๋ฃ. | stream.anyMatch(x -> x > 10) |
allMatch() | ์กฐ๊ฑด์ด ๋ชจ๋ ์์์ ๋ง์กฑํ์ง ์์ ๊ฒฝ์ฐ ์ฆ์ ์ฒ๋ฆฌ ์ข ๋ฃ. | stream.allMatch(x -> x > 0) |
noneMatch() | ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์๊ฐ ํ๋๋ ์์ ๊ฒฝ์ฐ ์ฒ๋ฆฌ ์ข ๋ฃ. | stream.noneMatch(x -> x < 0) |
limit(n) | ์ต๋ n ๊ฐ์ ์์๋ง ์ฒ๋ฆฌํ๊ณ ํ๊ฐ๋ฅผ ์ข
๋ฃ. | stream.limit(5).collect(Collectors.toList()) |
๋จ๋ฝ ์กฐ๊ฑด ์์
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
// ๋จ๋ฝ ์กฐ๊ฑด: ์ฒซ ๋ฒ์งธ ์์ ๋ฐ๊ฒฌ ์ ์ฒ๋ฆฌ ์ข
๋ฃ
Optional<Integer> first = numbers.stream()
.filter(n -> n > 3)
.findFirst();
System.out.println(first.get()); // ์ถ๋ ฅ: 4
findFirst
๋ ์กฐ๊ฑด์ ๋ง๋ ์ฒซ ๋ฒ์งธ ์์๋ฅผ ์ฐพ์ผ๋ฉด ์คํธ๋ฆผ ์ฒ๋ฆฌ๋ฅผ ์ข ๋ฃํ๋ค.
์ต์ข ์ฐ์ฐ์ ์คํธ๋ฆผ์ ํ๊ฐํ๋ฉฐ, ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๊ฑฐ๋ ๋ฐ์ดํฐ ์๋น๋ฅผ ์๋ฃํฉ๋๋ค.
3-1. ์ปฌ๋ ์ ์ผ๋ก ๋ณํ
toList()
: ์คํธ๋ฆผ ๋ฐ์ดํฐ๋ฅผList
๋ก ๋ณํ.toSet()
: ์คํธ๋ฆผ ๋ฐ์ดํฐ๋ฅผSet
์ผ๋ก ๋ณํ.toMap()
: ํค-๊ฐ ๋งคํ์ ๊ธฐ๋ฐ์ผ๋กMap
์ผ๋ก ๋ณํ.
์์
List<String> result = Stream.of("a", "b", "c").collect(Collectors.toList());
System.out.println(result); // ์ถ๋ ฅ: [a, b, c]
3-2. ์ถ์ (Reduction)
- ์คํธ๋ฆผ ๋ฐ์ดํฐ๋ฅผ ํ๋์ ๊ฐ์ผ๋ก ์ถ์.
- ์:
reduce()
,count()
,max()
,min()
.
์์
int sum = Stream.of(1, 2, 3, 4, 5)
.reduce(0, Integer::sum); // ์ด๊ธฐ๊ฐ 0, ํฉ์ฐ ์ฐ์ฐ
System.out.println(sum); // ์ถ๋ ฅ: 15
3-3. ์กฐ๊ฑด ๊ฒ์ฌ
- ๋ฐ์ดํฐ๊ฐ ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ๋์ง ๊ฒ์ฌ.
- ์:
anyMatch()
,allMatch()
,noneMatch()
.
์์
boolean hasNegative = Stream.of(1, 2, -3, 4, 5)
.anyMatch(n -> n < 0);
System.out.println(hasNegative); // ์ถ๋ ฅ: true
3-4. ๋ฐ์ดํฐ ์๋น
- ๋ฐ์ดํฐ๋ฅผ ์ํํ๋ฉฐ ์๋น.
- ์:
forEach()
,forEachOrdered()
.
์์
Stream.of("a", "b", "c").forEach(System.out::println);
// ์ถ๋ ฅ:
// a
// b
// c
์คํธ๋ฆผ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์์ฐจ ์ฒ๋ฆฌ๋ฅผ ์ํํ์ง๋ง, ๋ณ๋ ฌ ์คํธ๋ฆผ์ ์ฌ์ฉํ๋ฉด ์ฌ๋ฌ ๋ฐ์ดํฐ ์์๋ฅผ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค. ํ๊ฐ ๋จ๊ณ์์๋ ๋ณ๋ ฌ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
๋ณ๋ ฌ ์คํธ๋ฆผ ํ๊ฐ ์์
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
// ๋ณ๋ ฌ ์คํธ๋ฆผ์ผ๋ก sum ๊ณ์ฐ
int sum = numbers.parallelStream()
.reduce(0, Integer::sum);
System.out.println(sum); // ์ถ๋ ฅ: 21
- ๋ณ๋ ฌ ์คํธ๋ฆผ์ ๋ฐ์ดํฐ ์์๋ฅผ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ๋ฉฐ, ์ต์ข ๊ฒฐ๊ณผ๋ฅผ ๊ฒฐํฉํฉ๋๋ค.
- ํ๊ฐ ๊ณผ์ ์์๋ ๋ณ๋ ฌ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ฏ๋ก ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ์ ๋ฆฌํฉ๋๋ค.
- ํ๊ฐ(Evaluation): ์คํธ๋ฆผ ๋ฐ์ดํฐ๊ฐ ์ต์ข ์ฐ์ฐ์ ํตํด ํน์ ์๋ฐ ๊ฐ์ฒด๋ก ๋ณํ๋๋ ๊ณผ์ .
- ํ๊ฐ ๋ฐ์ ์กฐ๊ฑด: ์ต์ข ์ฐ์ฐ์ด ํธ์ถ๋ ๋๋ง ํ๊ฐ๊ฐ ์ด๋ฃจ์ด์ง.
- ๋จ๋ฝ ์กฐ๊ฑด: ํน์ ์กฐ๊ฑด์ ๋ฐ๋ผ ์คํธ๋ฆผ ์ฒ๋ฆฌ๊ฐ ์ค๋จ๋ ์ ์์ (
findFirst
,anyMatch
๋ฑ). - ์ง์ฐ ์คํ: ์คํธ๋ฆผ์ ํ๊ฐ ์ ๊น์ง ์คํ๋์ง ์์ผ๋ฉฐ, ์ ์๋ง ์ด๋ฃจ์ด์ง.
- ์ต์ข
์ฐ์ฐ ์ข
๋ฅ:
- ๋ฐ์ดํฐ ์๋น:
forEach
- ๋ฐ์ดํฐ ๋ณํ:
collect
,toList
,toMap
- ๋ฐ์ดํฐ ์ถ์:
reduce
,count
,max
,min
- ์กฐ๊ฑด ๊ฒ์ฌ:
anyMatch
,allMatch
,findFirst
- ๋ฐ์ดํฐ ์๋น:
์คํธ๋ฆผ ํ๊ฐ๋ฅผ ์ ํ์ฉํ๋ฉด ๋๊ท๋ชจ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ณ , ๊ฐ๋ ์ฑ๊ณผ ์ฑ๋ฅ์ ๋ชจ๋ ๋์ผ ์ ์์ต๋๋ค.
์ถ์ฒ ๋ฐ ์ฐธ๊ณ
- https://jake-seo-dev.tistory.com/449
- https://jake-seo-dev.tistory.com/459?category=906605
- https://velog.io/@semi-cloud/Effective-Java-%EC%95%84%EC%9D%B4%ED%85%9C-47-%EB%B0%98%ED%99%98-%ED%83%80%EC%9E%85%EC%9C%BC%EB%A1%9C%EB%8A%94-%EC%8A%A4%ED%8A%B8%EB%A6%BC%EB%B3%B4%EB%8B%A4-%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%B4-%EB%82%AB%EB%8B%A4
Footnotes
-
๋ฉ์น ํฐ ์ํ์ค๋, ๋ฐ์ดํฐ์ ํฌ๊ธฐ(์์์ ๊ฐ์๋ ๋ฐ์ดํฐ ์)๊ฐ ๋งค์ฐ ํฐ ๊ฒฝ์ฐ๋ฅผ ์๋ฏธํฉ๋๋ค. ์ฆ, ๋ฆฌ์คํธ, ๋ฐฐ์ด, ์คํธ๋ฆผ ๋ฑ์์ ์์์ ๊ฐ์๊ฐ ๋ง์์ ธ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด๋ ๊ณ์ฐ๋์ด ๋งค์ฐ ์ปค์ง ์ํ์ค๋ฅผ ๋งํฉ๋๋ค. ์ด๋ฌํ ๋ฉ์น ํฐ ์ํ์ค๋ฅผ ์ฒ๋ฆฌํ ๋๋ ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ, ์ฑ๋ฅ ๋ฌธ์ , ์ฒ๋ฆฌ ์๋ ๋ฑ์ ๊ณ ๋ คํด์ผ ํฉ๋๋ค.
๋ฉ์น ํฐ ์ํ์ค์ ์์
- ๋น
๋ฐ์ดํฐ:
- ์๋ฐฑ๋ง ๊ฐ์ ๋ฐ์ดํฐ ๋ ์ฝ๋๋ฅผ ํฌํจํ๋ ๊ฒฝ์ฐ.
- ์: ์ฌ์ฉ์ ๋ก๊ทธ, ์ผ์ ๋ฐ์ดํฐ ๋ฑ.
- ๋์ฉ๋ ์ปฌ๋ ์
:
- ์์์ ์๊ฐ ์์ญ๋ง, ์๋ฐฑ๋ง ์ด์์ธ ์ปฌ๋ ์ .
- ์: ์ฌ๋ฌ ํด ๋์์ ๋ ์จ ๋ฐ์ดํฐ, ๊ตญ๊ฐ์ ๋ชจ๋ ์ธ๊ตฌ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์ปฌ๋ ์ ๋ฑ.
- ๋ฌดํ ์คํธ๋ฆผ:
- ๋์ด ์์ด ์์ฑ๋๋ ์คํธ๋ฆผ.
- ์:
Stream.generate()
๋Stream.iterate()
๋ก ์์ฑ๋ ๋ฌดํ ์คํธ๋ฆผ.
- ์์ ๋ฐ ์์ฑ ๋ฐ์ดํฐ:
- ํฝ์ ์ ๋ณด, ์ค๋์ค ์ํ ๋ฑ์ด ํฌํจ๋ ๋ฐ์ดํฐ๋ก, ๊ฐ ํ๋ ์์ด๋ ์ํ์ด ๋งค์ฐ ํฐ ์ํ์ค๋ฅผ ํ์ฑ.
- ๋น
๋ฐ์ดํฐ: