DevLog ๐ถ
[Java] ConcurrentModificationException์ ์ธ์ ๋ฐ์ํ ๊น? iterator์ ๋์ ์๋ฆฌ ์ดํด๋ณด๊ธฐ ๋ณธ๋ฌธ
[Java] ConcurrentModificationException์ ์ธ์ ๋ฐ์ํ ๊น? iterator์ ๋์ ์๋ฆฌ ์ดํด๋ณด๊ธฐ
dolmeng2 2023. 3. 6. 22:02๐ฌ ๋ชจ๋ ์๋ฐ๋ฅผ ๊ณต๋ถํ๋ ๋์ค์, ์ฑ ์์ ๋์๋ ์์ ๋ฅผ ์ปค์คํ ํ๋ ค๋ค๊ฐ ์ด๋ฐ ์ํฉ์ ๋ง๋ฌ๋ค.
โ๏ธ ๋ฌธ์ ์ํฉ
๋จผ์ , ์ฌ์ฉํ ํฌ๋ฃจ ํด๋์ค์ ๋ํ ์ ๋ณด์ด๋ค.
public class Crew {
private String name;
private String nickname;
private int age;
private Course course;
private Crew() {
// ์ธ๋ถ์์ ์ธ์คํด์คํ ๋ง๊ธฐ
}
public static Crew createByName(final String name, final int age, final Course course) {
Crew crew = new Crew();
crew.name = name;
crew.age = age;
crew.course = course;
return crew;
}
public static Crew createByNickname(final String nickname, final int age, final Course course) {
Crew crew = new Crew();
crew.nickname = nickname;
crew.age = age;
crew.course = course;
return crew;
}
public int getAge() {
return age;
}
public Course getCourse() {
return course;
}
public String getNickname() {
return nickname;
}
}
์ดํ, ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ํฉ์ด๋ค. ์ฑ ์์๋ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ๋ํด์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค๊ณ ํ์๋ค.
List<Crew> crews = new ArrayList<>();
crews.add(Crew.createByNickname("hi", 20, Course.BACKEND));
crews.add(Crew.createByNickname("hello", 21, Course.BACKEND));
crews.add(Crew.createByNickname("hihi", 22, Course.BACKEND));
for (Crew crew : crews) {
if (crew.getAge() == 20) {
crews.remove(crew);
}
}
์ด ๊ฒฝ์ฐ์์๋ ๋น์ฐํ๊ฒ๋ ConcurrentModificationException์ด ๋ฐ์ํ๋ค.
โ๏ธ ConcurrentModificationException์ด๋?
๋จผ์ , ConcurrentModificationException์ด๋, ์๋ฐ์์ ์ปฌ๋ ์ ๋ด๋ถ์ ์์๋ฅผ ๋์์ ์์ ํ๋ ค๊ณ ํ ๋ ๋ฐ์ํ๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ์๋ฐ์ ์ปฌ๋ ์ ํ๋ ์์ํฌ๋ Iterator๋ฅผ ์ฌ์ฉํ์ฌ ์ปฌ๋ ์ ์ ์์๋ฅผ ๋ฐ๋ณตํ๋๋ฐ, ์ด๋ ์ปฌ๋ ์ ์ ์์ ํ๋ฉด์ ๋์์ ๋ฐ๋ณต์ ๋๊ฒ ๋๋ฉด ํด๋น ์์ธ๊ฐ ๋ฐ์ํ๋ค. ๋ณดํต์ ๊ฒฝ์ฐ๋ ๋ค์ค ์ค๋ ๋์์ ๋์์ ์์ ํ ๋ ๋ง์ด ๋ฐ์ํ์ง๋ง, ๋จ์ผ ์ค๋ ๋์์๋ ์์ ๊ฐ์ด ์ปฌ๋ ์ ์ ์์๋ฅผ ์ํํ๋ ๋์์, ํด๋น ์ปฌ๋ ์ ์ ์์๋ฅผ ์ ๊ฑฐํ๊ฒ ๋๋ฉด ๋ฐ์ํ ์ ์๋ค.
์ ์ด๋ฐ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋์ง๋ ์๋์์ ์ดํด๋ณด๊ณ , ๋ค์์ ์์ ๋ฅผ ์๊ฐํด๋ณด์.
List<Crew> crews = new ArrayList<>();
crews.add(Crew.createByNickname("hi", 20, Course.BACKEND));
crews.add(Crew.createByNickname("hello", 21, Course.BACKEND));
for (Crew crew : crews) {
if (crew.getAge() == 20) {
crews.remove(crew);
}
}
์ ์ฝ๋์์ crews.add()๋ฅผ ํ๋ ์์ ์ ํ ์ค ์ ๊ฑฐํ์ ๋ฟ์ด๊ธฐ ๋๋ฌธ์, ์ด ์ฝ๋ ์ญ์ ๋น์ฐํ๊ฒ ์์ธ๊ฐ ๋ฐ์ํ ๊ฒ์ด๋ค.
ํ์ง๋ง, ๋๋๊ฒ๋ ์๋ฌด ์ค๋ฅ๋ ๋ฐ์ํ์ง ์๋๋ค... (???)
์ฒ์์ ์ด๊ฑธ ๋ณด๊ณ ๋์ฒด ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์๋ ๊ฒ์ผ๊น, ์์ฒญ ๊ณ ๋ฏผํ์๋๋ฐ ์ด๋ for-each์ ๋์ ๊ณผ์ ์ ์ดํดํ๋ฉด ๋๋ค.
โ๏ธ Iterator ์ดํดํ๊ธฐ
์ฐ์ , ์ฒซ ๋ฒ์งธ ์ผ์ด์ค๋ ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ผ๊น? ํด๋น ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ด Iterator๋ฅผ ์ฌ์ฉํ๋๋ก ๋ณ๊ฒฝ๋๋ค.
List<Crew> crews = new ArrayList<>();
crews.add(Crew.createByNickname("hi", 20, Course.BACKEND));
crews.add(Crew.createByNickname("hello", 21, Course.BACKEND));
crews.add(Crew.createByNickname("hihi", 22, Course.BACKEND));
for (Iterator<Crew> iterator = crews.listIterator(); iterator.hasNext();) {
Crew crew = iterator.next();
if (crew.getAge() == 20) {
crews.remove(crew);
}
}
์ด๋, iterator.next()๋ฅผ ์งํํ๋ฉด์ ๋ค์ ์์๋ฅผ ๊ฐ์ ธ์ค๊ฒ ๋๋๋ฐ, next()๋ ๋ด๋ถ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ๋์ด ์๋ค.
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
์ฌ๊ธฐ์, ๊ฐ์ฅ ์๋จ์ checkForModification() ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค. ํด๋น ๋ฉ์๋๋ฅผ ํตํด ์ด๋ ํ ์์ ์ ํ๊ณ , (๊ทธ๊ฒ์ ์๋์์ ์ค๋ช ํ ์์ ์ด๋ค!) ํด๋น ์์์ ์ธ๋ฑ์ค์ ๋ํด์ cursor๋ฅผ ์ค์ ํ๊ฒ ๋๋ค. ๊ทธ๋ฆฌ๊ณ , ๋ง์ฝ ์ธ๋ฑ์ค๊ฐ ์ฌ์ด์ฆ๋ณด๋ค ํฌ๋ฉด ๋ค์ ์์๊ฐ ์์์ ๋ํ๋ด๋ฉฐ, elementData์์ ํด๋น ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ cursor๋ ๊ทธ ๋ค์ ์์์ ์ธ๋ฑ์ค๋ฅผ, lastRet์๋ ํ์ฌ ์์์ ์ธ๋ฑ์ค๋ฅผ ์ ์ฅํ๊ฒ ๋๋ค.
๐ฌ checkForComodification()
๋จผ์ , checkForComodification()์ ๋ํด์ ์ดํด๋ณด์.
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
modCount์ expectedModCount๊ฐ ๋ฌด์์ผ๊น?
modCount๋ ModificationCount๋ก, ํด๋น ๋ฆฌ์คํธ์ ๋ํ ์์ ๋ ํ์๋ฅผ ๊ด๋ฆฌํ๋ค. ํด๋น ํ๋๊ฐ ๊ตฌํ๋ ๊ณณ์ ๊ฐ์ ์ฃผ์์ ์ดํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์์ฑ๋์ด ์๋ค.
The number of times this list has been structurally modified.
If the value of this field changes unexpectedly, the iterator (or list iterator) will throw a ConcurrentModificationException in response to the next, remove, previous, set or add operations.
๊ตฌ์กฐ์ ์ผ๋ก ์์ ๋ ํ์์ ๋ํด์ ๊ด๋ฆฌํ๋ฉฐ, ์๊ธฐ์น ์๊ฒ ๋ณ๊ฒฝ์ด ๋์์ ๊ฒฝ์ฐ ์์ธ๋ฅผ ๋ฐ์์ํจ๋ค๊ณ ๋์ ์๋ค. next(), remove(), previous() ๋ฑ์ ๋ฉ์๋๋ฅผ ํธ์ถํ ๋๋ง๋ค modCount๊ฐ 1์ฉ ์ฆ๊ฐํ๊ฒ ๋๋ค.
๋ฐ๋ฉด์, expectedModCount๋ ArrayList์ ๋ฐ๋ณต์(iterator)๊ฐ ์์ฑ๋ ๋์ modCount๋ฅผ ์ ์ฅํ๋ค.
public Iterator<E> iterator() {
return new Itr();
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
// prevent creating a synthetic constructor
Itr() {}
...
}
์ค์ ๋ก ๋ด๋ถ ๊ตฌํ์ ๋ณด๋ฉด, Itr๋ผ๋ ํด๋์ค์์ expectedModCount์ ๋ํด modCount๋ก ์ด๊ธฐ๊ฐ์ ์ง์ ํด๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ฆ, modCount๋ ๋ฐ๋ณต์์ ๊ด๋ จ๋ ๋ฉ์๋๋ฅผ ํธ์ถํ ๋๋ง๋ค, expectedModCount๋ ๊ฐ์ฅ ์ฒ์ ์์ฑํ ๋์ modCount๋ฅผ ์ ์ฅํ๋ค๋ ๊ฒ์ด๋ค. ์ด๊ธฐ ์ํ๋ฅผ ์ ์ฅํด๋๊ณ , ์ด๋ฅผ ๋น๊ตํ๋ฉด์ ๊ด๋ฆฌํ๋ ๊ฒ์ด๋ค. ์ด๊ธฐ ์ํ์์ ๋ฌ๋ผ์ก๊ธฐ ๋๋ฌธ์ ํ์ฌ ์ํ๊ฐ ๋์ผํ์ง ์๋ค๋ ์๋ฏธ๋ก concurrentModficiationException์ด ๋ฐ์ํ๊ฒ ๋๋ ๊ฒ์ด๋ค.
๊ทธ๋ ๋ค๋ฉด, ๋ค์ ์ฐ๋ฆฌ์ ๊ตฌํ์ฒด๋ฅผ ๋ณด์. ํ์ฌ ์ฐ๋ฆฌ๋ if ์กฐ๊ฑด๋ฌธ์ ์ผ์นํ๋ ์์์ ๋ํด์ ์ ๊ฑฐ ์์ ์ ์งํํ๊ณ ์๋ค.
ํ์ฌ ํฌ๋ฃจ ๋ฆฌ์คํธ์๋ ๋์ด๊ฐ 20์ธ ํฌ๋ฃจ๊ฐ ์กด์ฌํ๋ค. ๊ทธ๋ฆฌ๊ณ , ํด๋น ํฌ๋ฃจ์ ๋ํด ์ ๊ฑฐํ๋ ์์ ์ ์งํํ๊ฒ ๋๋ค.
public boolean remove(Object o) {
final Object[] es = elementData;
final int size = this.size;
int i = 0;
found: {
if (o == null) {
for (; i < size; i++)
if (es[i] == null)
break found;
} else {
for (; i < size; i++)
if (o.equals(es[i]))
break found;
}
return false;
}
fastRemove(es, i);
return true;
}
remove ๋ฉ์๋๋ ์ ๊ฑฐํ ์์์ ์ธ๋ฑ์ค๋ฅผ ์ฐพ์๋ธ ๋ค์, ํด๋น ์ธ๋ฑ์ค์ ์๋ ๊ฐ์ ์ ๊ฑฐํ๋ค. ์ด๋, elementData๋ ArrayList์์ ๊ด๋ฆฌํ๋ ๋ด๋ถ ๋ฐฐ์ด์ด๊ณ (๋ฆฌ์คํธ๋ ์๋ ๋ฐฐ์ด๋ก ๊ด๋ฆฌ๋๋ค) size๋ ํ์ฌ ์ ์ฅ๋ ์์์ ๊ฐ์๋ฅผ ๋ํ๋ธ๋ค. ๋ง์ฝ ์์๊ฐ null์ด๋ผ๋ฉด ==๋ก, null์ด ์๋๋ผ๋ฉด equals๋ก ๋น๊ตํ๊ฒ ๋๋๋ฐ, for๋ฌธ์ ๋๋ฉด์ ์ ๊ฑฐํ ์์๋ฅผ ์ฐพ์๋ด๋ฉด ํด๋น ์์์ ์ธ๋ฑ์ค๋ฅผ ๋ฐํ์ผ๋ก fastRemove() ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค.
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
if ((newSize = size - 1) > i)
System.arraycopy(es, i + 1, es, i, newSize - i);
es[size = newSize] = null;
}
์ด๋, fastRemove ๋ฉ์๋๋ฅผ ๋ณด๋ฉด ์ต์ํ ๋ฌด์ธ๊ฐ๊ฐ ๋ณด์ธ๋ค. ๋ฐ๋ก, modCount์ด๋ค! ํด๋น ๋ฆฌ์คํธ์ ๋ํด ์์ ์ด ๊ฐํด์ก๊ธฐ ๋๋ฌธ์ modCount๋ฅผ ์ฆ๊ฐํ๊ฒ ๋๊ณ , ํด๋น ์ธ๋ฑ์ค ์ดํ์ ๋ชจ๋ ์์๋ฅผ ์์ผ๋ก ํ ์นธ์ฉ ๋น๊ธฐ๋ ์์ ์ ์งํํ๋ค.
๊ทธ๋ผ, ์ฌ๊ธฐ์ ํ์ฌ modCount๋ 1 ์ฆ๊ฐํ ํํ์ผ ๊ฒ์ด๋ค. ์ด ์ํ๋ก ๋ค์ iterator๋ฅผ ๋๊ฒ ๋๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
public boolean hasNext() {
return cursor != size;
}
๋จผ์ , hasNext๋ฅผ ํตํด์ cursor์ ์ฌ์ด์ฆ๊ฐ ์ผ์นํ๋์ง ์ฒดํฌํด์ ๋๊น์ง ๋๋ฌํ๋์ง๋ฅผ ์ฒดํฌํ๋ค.
๊ทธ๋ฆฌ๊ณ , ๋ค์ next()๋ฅผ ํตํด์ ์์๋ฅผ ๊บผ๋ด์ค๊ฒ ๋ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ , ๋ ๋ค์ checkForComodification() ๋ฉ์๋๋ฅผ ํ์ธํ๊ฒ ๋ ๊ฒ์ด๊ณ , ์ด๋ ์ด๋ฏธ ๋ณ๊ฒฝ๋ modCount ๋ณ์๋ก ์ธํด์ expectedModCount์ ๋ฌ๋ผ์ง๊ฒ ๋์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ด๋ค! ๐ฅฒ
์ค์ ๋ก ๋๋ฒ๊น ๊ฒฐ๊ณผ, ์ด๊ธฐ์ expectedModCount๋ 3์ด์ง๋ง, modCount๋ 4๊ฐ ๋์ด์ ์์ธ๊ฐ ๋ฐ์ํจ์ ํ์ธํ ์ ์๋ค!
โ๏ธ ์... ๊ทธ๋ผ ์์๊ฐ 2๊ฐ์ผ ๋๋ ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์์์ง?
์ด์ ๋ ๋จ์ํ๋ค. 'hi' ์์๊ฐ ์ ๊ฑฐ๋ ์ดํ, ๋ฆฌ์คํธ์ iterator์ ์ ๋ณด์ด๋ค. ์ด๋ฏธ ๋ฆฌ์คํธ์์ ์์๊ฐ ์ ๊ฑฐ๋์๊ธฐ ๋๋ฌธ์ ๋ด๋ถ์ ์ผ๋ก ๊ด๋ฆฌ๋๋ ArrayList์ ์ฌ์ด์ฆ๊ฐ 1์์ ๋ณผ ์ ์๋ค. (hello๋ง ๋จ์์์)
for (Iterator<Crew> iterator = crews.listIterator(); iterator.hasNext();) {
Crew crew = iterator.next();
if (crew.getAge() == 20) {
crews.remove(crew);
}
}
์ด๋, iterator์ hasNext()๋ฅผ ํตํด ๋ค์ ์์๊ฐ ์กด์ฌํ๋์ง ์ฒดํฌํ๋๋ฐ, ์๊น ๋ดค๋ ๊ฒ์ฒ๋ผ cursor์ size์ ์ ๋ณด๊ฐ ๋์ผํ์ง ์๋ค๋ฉด ๋ค์ ์์๊ฐ ์๋ค๊ณ ํ๋จํ๋ค. ์ด๋, 1 (์ปค์ ์์น) = 1 (์ฌ์ด์ฆ)๋ก ๋ ๊ฐ๊ฐ ๋์ผํ ์ํฉ์ด ๋ง๋ค์ด์ง๋ฉด์, next() ๋ฉ์๋๋ฅผ ํตํด ๊ฒ์ฆ ๋ฉ์๋๋ฅผ ๊ฑฐ์น๊ธฐ๋ ์ ์ ๊ทธ๋ฅ for๋ฌธ์ด ์ข ๋ฃ๋์ด ์์ธ๊ฐ ๋ฐ์ํ์ง๋ ์๊ณ ๋๋๋ ๊ฒ์ด์๋ค.
โ๏ธ ์ ๋ฆฌ - ๊ทธ๋ฌ๋ฉด ์ด๋ป๊ฒ ํด๊ฒฐํ ์ ์์ง?
๐ก ๊ทธ๋์, ์ ํํ๊ฒ๋ '์กฐ๊ฑด์ ํด๋นํ๋ ์์' ๋ค์์ ์์๊ฐ 1๊ฐ๋ง ์กด์ฌํ๊ณ , ๋ฐ๋ณต์๋ฅผ ์ด๊ธฐํํ์ง ์๋๋ค๋ฉด ์ปค์ ์์น์ ์ฌ์ด์ฆ๊ฐ ๋์ผํ ์ํฉ์ด ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์, ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์๊ณ ์ข ๋ฃ๋ ์ ์๋ค! ๋ผ๊ณ ์ดํดํ๋ฉด ๋๋ค.
// ์์ธ ๋ฐ์ X
List<Crew> crews = new ArrayList<>();
crews.add(Crew.createByNickname("hello", 21, Course.BACKEND));
crews.add(Crew.createByNickname("hi", 20, Course.BACKEND));
crews.add(Crew.createByNickname("hihi", 23, Course.BACKEND));
for (Iterator<Crew> iterator = crews.listIterator(); iterator.hasNext(); ) {
Crew crew = iterator.next();
if (crew.getAge() == 20) {
crews.remove(crew);
}
}
// ์์ธ ๋ฐ์
List<Crew> crews = new ArrayList<>();
crews.add(Crew.createByNickname("hello", 21, Course.BACKEND));
crews.add(Crew.createByNickname("hi", 20, Course.BACKEND));
crews.add(Crew.createByNickname("hihi", 23, Course.BACKEND));
crews.add(Crew.createByNickname("wow", 23, Course.BACKEND));
for (Iterator<Crew> iterator = crews.listIterator(); iterator.hasNext(); ) {
Crew crew = iterator.next();
if (crew.getAge() == 20) {
crews.remove(crew);
}
}
๋จ์ํ ์์์ ๊ฐ์๋ง ์๊ด์๋ ๊ฒ์ด ์๋๋ผ, ๋ค์๊ณผ ๊ฐ์ด ์กฐ๊ฑด์ ์ผ์นํ๋ ์์ ๋ค์์ ์์๊ฐ 2๊ฐ ์ด์ ์กด์ฌํ ๋ ์์ธ๊ฐ ๋ฐ์ํ๋ค.
๊ทธ๋์, ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ์์ ์์ฒด๋ฅผ ์ญ์ ํ๋ ๊ฒ๋ณด๋ค๋ iterator๋ฅผ remove() ํด์ค์ผ ํ๋ค.
List<Crew> crews = new ArrayList<>();
crews.add(Crew.createByNickname("hi", 20, Course.BACKEND));
crews.add(Crew.createByNickname("hello", 21, Course.BACKEND));
crews.add(Crew.createByNickname("hihi", 23, Course.BACKEND));
for (Iterator<Crew> iterator = crews.listIterator(); iterator.hasNext();) {
Crew crew = iterator.next();
if (crew.getAge() == 20) {
iterator.remove();
}
}
๊ทธ ์ด์ ๋ ๋ด๋ถ ๊ตฌํ์ ๋ณด๋ฉด ๋ฐ๋ก ์ ์ ์๋ค.
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount; // ํต์ฌ ๋ก์ง!
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
lastRet๋ next()์์ ์ฐพ์ ์์์ ์ธ๋ฑ์ค๋ฅผ ์ ์ฅํด๋์๋๋ฐ, ํด๋น ์ธ๋ฑ์ค์ ํด๋นํ๋ ์์๋ฅผ ์ ๊ฑฐํ๊ณ , ์ปค์๋ฅผ ํด๋น ์ธ๋ฑ์ค๋ก ๋๋ฆฌ๋ ๊ฒ์ ๋ณผ ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ , ์ฐพ์ ์ธ๋ฑ์ค์ ๋ํด์ -1๋ก ์ค์ ํด์ ์ ๊ฑฐ ์๋ฃ๋์์์ ํ์ํด๋๊ณ , expectedModCount์ modCount์ ์ํ๋ฅผ ์ผ์น์์ผ ์์ธ๊ฐ ๋ฐ์ํ์ง ์๋๋ก ๋ง๋ค์ด ์ค๋ค! ๐
์ปฌ๋ ์ ์ํ ์, ๋ฌด์ฌ์ฝ ์ฌ์ฉํ์ง ์๊ณ ์ฌ๋งํ๋ฉด ๋ฐ๋ก ๋ณต์ฌ๋ณธ์ ์ฐธ์กฐํ์ฌ ์ ๊ฑฐํ๋๋ก ํ๊ฑฐ๋, ์ด๋ฐ ์์ผ๋ก iterator๋ฅผ ์ ๊ฑฐํ๋ ์์ผ๋ก ์ฝ๋๋ฅผ ์์ฑํ์ ๐
'โ๏ธ > Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋ถ๋ณ๊ฐ์ฒด๋ก ๋ง๋๋ ๊ฒ์ด ํญ์ ์ข์๊น? - Value Object vs Reference Object (0) | 2023.04.21 |
---|---|
[Java] Classic TDD vs Mockist TDD (0) | 2023.03.28 |
[Java] ๋ฌธ์์ด - String pool๊ณผ String concatenation (6) | 2023.03.05 |
[TDD] ์๋ฐ ํ ์คํธ ์ฝ๋, ๋จ์ ํ ์คํธ, ํ ์คํธํ๊ธฐ ์ด๋ ค์ด ๋ถ๋ถ (feat. ์๋์ฐจ ๊ฒฝ์ฃผ ๊ฒ์) (0) | 2023.02.14 |
[Java] Method Naming Convention (0) | 2022.10.22 |