Java Puzzlers - Scraping the Bottom of the Barrel (Google I/O 2011)
ํฌํธ์ ๋์๋ค๋๋ ์ค์ ์ฌ๋ฐ๋ Java ์์๋ฅผ ๋ฐ๊ฒฌํ์ต๋๋ค. ๋ฐ๋ก Google I/O 2011์ ์์๋ Java Puzzler๋ผ๋ ๊ฒ์ธ๋ฐ์.
์ด ์์์์๋ ๋ฐํ์ JOSH BLOCH, JEREMY MANSON ๋ ์ฌ๋์ด 6๊ฐ์ง์ Java ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ํผ์ฆ์ ๋ฐํํฉ๋๋ค.
๋จผ์ ๊ทธ ์ฒซ ๋ฒ์งธ, Time for a Change,
์์์ ๋์จ ์์ค๋๋ก ์ ๋ ฅํ์ ๋, ๊ฑฐ์ค๋ฆ ๋์ ์ผ๋ง์ ๋๊น? ๋ผ๋ ๋ฌธ์ ์ง์. ์ฌ๊ธฐ์ ๊ฐ์ฅ ์ค์ํ ๊ฒ์, ์๋ฃํ์ด double์ด๋ผ๋ ๊ฒ์ ๋๋ค.
๊ฑฐ์ค๋ฆ๋์ 0.8999999999999999๊ฐ ๋์ต๋๋ค. ์ ๊ทธ๋ด๊น์?
Java์์ double ์ฐ์ฐ์ ์ ํํ ๊ฐ์ ์ ๊ณตํด์ฃผ์ง ์๋๋ค๋ฉฐ, big decimal์ ์ฌ์ฉํ๋ผ๊ณ ๊ถ์ฅํฉ๋๋ค. ๋ฐ๋ผ์ Big Decimal์ ์ฌ์ฉํด ๋ค์ ํ ๋ฒ ์ฐ์ฐ์ ํด๋ณด๋๋ก ํฉ์๋ค.
1. A change is Gonna Come
์ ์ด๋ฒ์, BigDecimal ํด๋์ค๋ฅผ ์ฌ์ฉํด์ ์์ค๋ฅผ ๋ค์ ํ ๋ฒ ์ ๋ ฅํด๋ดค์ต๋๋ค.
์์์์ ๋ณด๊ธฐ a, b, c, d ์ค ๋ต์ ๊ณ ๋ฅด๋ผ๊ณ ํ์ง์. ๊ทธ๋ฐ๋ฐ, ๊ณผ์ฐ ๋ต์ด ์์๊น์? ์ ๋ต์ a,b,c ๋ชจ๋ ์๋ d : ์ ๋ต์ด ์์. ์ด ๋ง์ต๋๋ค. ์ฒญ๊ฐ๋ค ๋ชจ๋ ์๊ณ ์์ฃ ใ ใ ใ ์ ๊ทธ๋ผ ๋ต์ด ์ด๋ป๊ฒ ๋์๋์ง ์ ๊ฐ ํ ๋ฒ ์ดํด๋ฆฝ์ค์์ ์ฝ๋ฉ์ ํด ๋ณธ ๊ฒฐ๊ณผ, 0.899999999999999911182158029987476766109466552734375 ๋ผ๋ ์ด๋ง์ด๋งํ ๊ฐ์ด ๋์์ต๋๋ค. ์ ๊ทธ๋ด๊น์?
๋ถ๋ช ์์์์๋ BigDecimal ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ผ๊ณ ๊ถ์ฅ์ ํ์ต๋๋ค. ํ์ง๋ง BigDecimal ํด๋์ค๋ฅผ ์ฌ์ฉํ๊ณ , ์ธ์๊ฐ์ double ์๋ฃํ์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์ ๋ฐ ๊ฒฐ๊ณผ๊ฐ์ด ๋์ค๋ ๊ฒ๋๋ค. BigDecimal(double val)์ double ๊ฐ์ BigDecimal๋ก ํํํ๋ ๊ฒฝ์ฐ์ด๋ฏ๋ก ๊ทธ๋ฅ double์ ์ด ๊ฒ์ด๋ ๋ค๋ฆ์ด ์์ง์.
๊ทธ๋์ ์ ์์์์๋ double์ด ์๋ String ์ผ๋ก ์ธ์๊ฐ์ ์ฌ์ฉํ๊ธฐ๋ฅผ ๊ถ์ฅํฉ๋๋ค. ์ ํํ ๊ฐ์ ๋์ถ์ ํญ์ double ์๋ฃํ์ด ์๋ String์ ์ฌ์ฉํฉ์๋ค.
OK? ์ฌ์ฐ๋ฉด์๋ ์ ๋ง ์ ์ฉํ ์ฒซ ๋ฒ์งธ ํผ์ฆ์ด์์ต๋๋ค.
2. Size Matters
๋ ๋ฒ์งธ๋ ์ฌ์ด์ฆ(ํฌ๊ธฐ)์ ๊ด๋ จ๋ ๋ฌธ์ ์ธ๋ฐ์. ์ฌ๊ธฐ์ ๋ค๋ฃจ๋ ๊ฒ์ Map์ ๋๋ค. Map์๋ ์ข ๋ฅ๊ฐ ๋ง์ง์. HashMap, TreeMap, EnumMap .... ๊ทธ ์ค ์ฌ๊ธฐ์๋ HashMap๊ณผ EnumMap์ ๋ค๋ฃจ๊ณ ์์ต๋๋ค.
์ ์ด ์ฝ๋์์๋ ์ด๋ค ๊ฒฐ๊ณผ๊ฐ ์ถ๋ ฅ์ด ๋ ๊น์?
์์์์๋ 2 1 ์ด ์ถ๋ ฅ๋๋ค๊ณ ๋์ต๋๋ค๋ง ํ์ฌ๋ 2 2 ์ ํํ๊ฒ ๋์ค๊ณ ์๋ค์. ์ฐจ๋ก์ฐจ๋ก ์ดํด๋ณด๋๋ก ํด๋ณด์ง์.
๋จผ์ ์์์์ ์๋ชป๋๋ค๊ณ ์ง์ ํ๋ size ์์ค์์ MALE FEMALE์ ๋ฃ์ด์ฃผ๊ณ , ๋ง์ง๋ง์ Set ํ ๊ฒฝ์ฐ์ธ HashSet์ ๋ณด๋๋กํฉ์๋ค.
key๊ฐ์ ๊ฐ์ ธ์์ ๊ณ์ฐํ ๋ค์ addAll ํจ์๋ฅผ ์ทจํ๊ณ ์๊ตฐ์.
addAll ํจ์๋ฅผ ๋ณด๋ฉด, Iterator ํจํด์ ํตํด, hasNext๋ฅผ ํตํด์ ๋์์์ด ๋ฐ๋ณตํ๊ณ , ๊ทธ ๋ฐ๋ณต์ ํตํด modified ๋ฅผ ๋ฆฌํดํด์ฃผ๊ณ ์์ต๋๋ค. ํ ๋ง๋๋ก ๋ ธ๊ฐ๋ค์ด์ง์;;
Map์ผ๋ก ์ ์๋ ๋ชจ๋ ๊ฐ์ ๋ฐ์์์ ์ ์ฅํ๋๊ตฐ์.
์์์์ ์ ๊ธฐํ๋ ๋ฌธ์ ๋ ๋ฐ๋ก ์ด ๋ถ๋ถ์ ๋๋ค. ๋ฐ๋ก EntryIterator ๋ถ๋ถ์ธ๋ฐ์. ์ด ์์ค๋ openjdk6-b14์ ๋ด๊ฒจ์๋ ์์ค ์ฝ๋์ ๋๋ค. ๋ฌธ์ ๊ฐ ๋๋ ๋ถ๋ถ์ openjdk6 ๋ฒ์ ์์๋ง ์ค๋ฅ๋ฅผ ๋ ๋๋ค. ์์์ด 2๋ ์ ๊ฒ์ด๋ผ ์จ๋๊ฐ๋ค๋ณด๋ ๊ทธ๋ ๊ตฐ์. ์์ค ์ฝ๋๋ฅผ ์ดํด๋ณด์๋ฉด ๊ฐ์ ๊ฐ์ ธ์ค๊ณ next๋ก ๋ฐ๋ณต์ ํ๋ฉด์ this๊ฐ์ ๋ฆฌํดํ๊ณ ์์ต๋๋ค. ์ฆ, Iterator๋ง ๋๊ณ ์๊ณ , Entry๋ ์ ์๋ฆฌ ๊ฑธ์์ ์น๊ณ ์๊ตฐ์. ๋ณดํต Next(); ๋ฌธ์ ๊ฑฐ์น๊ฒ ๋๋ฉด, ์๋ก์ด Entry๊ฐ ์์ฑ๋๋ฉด์ return์ด ๋ฉ๋๋ค. ๊ทธ๋ฐ๋ฐ ์ ์์ค์ฒ๋ผ EnumMap EntryIterator๋ Entry๋ ๋ด๋ฒ๋ ค๋๊ณ , ์์๊ฐ๋ง์ ๊ฐ์ ธ์ค๊ณ , ๋ ์๋ก ๊ฐ์ ธ์ค๊ณ ์ด๋ฐ์์ด์ง์. ์ฆ, ์์์์ ๋งํ๋ ๊ฒ์ฒ๋ผ Entry ์์ด ๊ทธ๋ฅ ๋จ์ํ ์์์ ๋ง๋ key, value๋ง ๊ฐ์ ธ๋ค๊ฐ returnํ๊ฒ ๋ฉ๋๋ค. EnumMap์ ํน์ฑ์ ์ฒ๋ฆฌ ์๋๊ฐ ๋น ๋ฅด๋ค๋ ํน์ง์ด ์์ด ์์ฃผ ์ฌ์ฉํ๋ ํธ์ด์๋๋ฐ, ์ด๋ฐ ์๋ชป๋ ๊ฐ์ ์ถ๋ ฅํ๋ ๋ถ์์ฉ์ด ์์๊ตฐ์. ์ด ๋ฒ๊ทธ๋ 1997๋ ๋ถํฐ ์กด์ฌํ์์ผ๋ฉฐ IdentityHashMap, ConcurrentHashMap, EnumMap ๋ชจ๋ ์ด๋ฐ ํํ๋ก ๊ฐ์ถฐ์ ธ์์ด ๊ฐ์ ์ํฅ์ ๋ฏธ์น ๋ชจ์์ ๋๋ค. ๋คํํ ์๋๋ก์ด๋์๋ ์ ์ฉ์ด ์๋์ด์๋ค๊ณ ํ๋๊ตฐ์ ใ ใ ;
์ ์์ค๋ ํ์ฌ ๊ณ ์ณ์ง openjdk7-b147 ์์ค์ ๋๋ค. ์ ์์ค์ ๋ฌ๋ฆฌ Iterator ๋ฐ๋ณต๊ณผ ๋์์ Entry๋ฅผ ์์ฑํ๋ฉด์ ๋์๊ฐ๊ณ ์๊ตฐ์. EnumMap์ ์ฌ์ฉํด์ ์์ค ์ฝ๋ ์์ฑ์ ์ฐธ๊ณ ๋ฐ๋๋๋ค.
์ ์์์์ ์ ์ํ๋ ์์ ๋ ์์ค ์ฝ๋์ ๋๋ค. ์ต์ ๋ฒ์ ์์ ์ ์์ค๊ฐ ๊ณ ์ณ์ก์ผ๋ ๊ตณ์ด AbstractMap์ ์จ๊ฐ๋ฉด์ ๊น์ง ์ถ๊ฐํ๋ ๊ฒ์ ์ถ์ฒํ์ง ์์ต๋๋ค๋ง jdk6์์ ๊ผญ ์ฌ์ฉํด์ผํ ๊ฒฝ์ฐ์๋ง ์ฐธ๊ณ ํ์๋๊ฑธ ์ถ์ฒํฉ๋๋ค.
3. The Match Game
Pattern์ด๋ผ๋ ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ๋ง๋ Match Game ์์ค ์ฝ๋์ ๋๋ค. ์์งํ ๋งํ์๋ฉด ์ฃผ์ด์ง Pattern ๋ถํฐ๊ฐ ์กฐ๊ธ ๊ณผํ Pattern ์ ๋๋ค๋ง. ์ด์จ๋ ์ด๋ค ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํด์ค๊น์?
์๋๋ ๋ค๋ฅผ๊น, Java์์ ์ ํํ ๊ฐฏ์๋ฅผ ํ์ํด์ฃผ์ง ์๋๊ตฐ์.
์ฌ๊ธฐ์ ๋ฐํ์๊ฐ ์ธ๊ธํ๋ ๊ฒ์ด ๋ฐ๋ก catastrophic backtracking์ด๋ผ๋ ๊ฒ์ ๋๋ค.
์์์ ๋ณด๋ฉด, ์ค์ฒฉ๋๋ฉด์ ์คํจํ๋ ๊ฒ๊น์ง ๋ค ํฌํจํด์ ๋งค์นญํ๋ค๊ณ ํฉ๋๋ค. aab? ์ ๊ท์๊ณผ ๋น์ทํ aa|aab? ๋ฐฉ์์ ์จ๋ณด๋ JVM์ด ๋ ์๊ฐ ๋ฏ์ด ๋ฉ์ถ์ง ์๋๋ผ๊ตฌ์ ใ ใ ; ์ด์ฒ๋ผ Pattern ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ์ ๊ท์์ ์ฌ์ฉํด ์์ธ์ ํ๋๋ฐ, ์ ์์ค์ฒ๋ผ ๋ ๊ฐ์ง ์ด์์ ์กฐ๊ฑด์ผ๋ก ์์ธ์ ํ ๊ฒฝ์ฐ, ๊ณผ๋ถํ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ด๋ Java ๋ฟ๋ง ์๋๋ผ PHP, Perl ๋ฑ๋ ๋ง์ฐฌ๊ฐ์ง๋ผ๊ณ ํฉ๋๋ค. Java์์๋ ์๋ง ์ํ๋๋ ์ ๊ทํํ์์ ํ์งํด๋ด์ ํ๋ก๊ทธ๋จ์ ๋ฉ์ถ๊ณ 0์ ํ์ํ๋ ๋ฏํฉ๋๋ค.
4. The Sinking Feeling
package javapuzzler;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
abstract class Sink<T> {
abstract void add(T... elements);
void addUnlessNull(T... elements) {
for(T element: elements) {
if(element != null) {
add(element);
}
}
}
}
public class StringSink extends Sink {
private final List<String> list = new ArrayList<String>();
void add(String... elements) {
list.addAll(Arrays.asList(elements));
}
public String toString() {
return list.toString();
}
public static void main(String[] args) {
Sink<String> ss = new StringSink();
ss.addUnlessNull("null", null);
System.out.println(ss);
}
}
์ ์์ค๊ฐ ๋ฐ๋ก ์์ ํ ๊ณ ์ณ์ง ์์ค์ ๋๋ค. ์์์์ object์์ string์ผ๋ก ๋๊ธฐ๋ bridged method์ ์ฌ์ฉ์ ๋งค์ฐ ๋์๋ค๊ณ ์ฃผ์ฅํ์ฌ ๊ทธ ๋ฐฉ๋ฒ์ ๋ฒ๋ฆฌ๊ณ , Collection์ ์ฌ์ฉํ์์ต๋๋ค. Collection์ ์ฌ์ฉํจ์ผ๋ก์จ ์ฝ๋์ ์๋ฅผ ์ค์ด๊ณ , ๋ถํ์ํ ๊ณผ์ ์ ์๋ตํ๋ค๊ณ ์๊ธฐํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์์์์ ์ค์ํ๊ฒ ์ธ๊ธํ ๊ฒ์ฒ๋ผ ์์ ์ค๋ฅ, ๊ฒฝ๊ณ ํ๋๋ ์ํํ ํ์ง ๋ง์๋ค ใ ใ
5. Glommer Pile
Arrays.asList๋ก 1 2 3 ์ ์ฃผ๊ณ ๋ฉ์๋๋๋ก ์ถ๋ ฅํ๋ผ๋ ์์ค๊ตฐ์. ์ ์ด ์์ค์์ ๋ํ๋๋ ์ค๋ฅ๊ฐ ๊ณผ์ฐ ์์๊น์? ์์์ ๊ธฐ์ค์ openjdk6 ๋ฒ์ ์ด๋ผ๋ ๊ฒ์ ์ผ๋ คํด๋์ ์ผ ํฉ๋๋ค ใ ใ
์ ๋ต์ ์ค๋ฅ๊ฐ ๋์จ๋ค์ฃ , ์ฌ๊ธฐ์ ์ธ๊ธํ๋ ๊ฒ์ Raw type์ ์ํํ๋ค๊ณ ํฉ๋๋ค. ์ ๊ทธ๋ด๊น์?
์ง๊ธ์ Raw type์ ์จ๋ JVM์์ ์์์ ์ฒ๋ฆฌํด๋ฒ๋ฆฌ์ง๋ง, ๋น์์๋ Raw type์ผ๋ก ๋ฐ์ ๊ฒฝ์ฐ, Generic Type (์ด๋ ํ ๊ฐ์ฒด๋ฅผ ๋ฏธ๋ฆฌ ๋ช ์ํจ์ผ๋ก์จ ํ๋ณํ์ ํ์ง ์๊ณ ์ฌ์ฉํ๋ ํ์ ) ๊ฐ์ฒด๋ค์ด ๋ชจ๋ ์์ด์ง๋ค๋ ๊ฒ์ ๋๋ค. ์ด๊ฒ๋ ์ปดํ์ผ๋ฌ์ ๋ฒ๊ทธ์ธ ๋ฏํฉ๋๋ค.
package javapuzzler;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class source5 {
String glom(Collection<?> objs) {
String result = "";
for(Object o : objs) {
result += o;
}
return result;
}
int glom(List<Integer> ints) {
int result = 0;
for(int i : ints) {
result += i;
}
return result;
}
public static void main(String[] args) {
List<String> strings = Arrays.asList("1", "2", "3");
System.out.println(new source5<Random>.glom(strings));
}
}
๋ง์ง๋ง์ ๊ต์ฅํ ๊ฐ๋จํฉ๋๋ค. ์ฒซ๋ฒ์ฌ ๋ฌธ์ ๋ณด๋ค๋ ํจ์ฌ ๊ฐ๋จํ์ฃ . ์ ๊ณผ์ฐ ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ ์ด๋ป๊ฒ ๋์ฌ๊น์?
์ซ์ ๊ฐ์ง๊ณ ๋์๋ณธ ์ฌ๋์ ๋ค ์๋งํ ์ฌ์ค์ ๋๋ค. ๊ทธ๋ฐ๋ฐ, ์ ์ด๋ฐ ๊ฒฐ๊ณผ๊ฐ ๋์ค๋๊ฑธ๊น์?
Java์์ 0์ ์์ ๋๊ฒ๋๋ฉด decimal, ์ฆ 8์ง์๋ก ์ฒ๋ฆฌ๋์ด 10์ง์์ ๊ฒฐ๊ณผ๊ฐ ๋์์ 668์ด ์ฐํ๋ฒ๋ฆฝ๋๋ค. ์ด๋ java ๋ฟ๋ง ์๋๋ผ C์ธ์ด๋ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค. ๋ต์ ๊ฐ๋จํ์ง์? 0 ์ง์์ฃผ์๋ฉด ๋๊ฒ ์ต๋๋ค~
๊ทธ๋ฆฌ๊ณ ๋ฐํ์๋ถ ๊ป์ I l ๊ฐ์ง๊ณ ์ฅ๋์น์ง ๋ง๋ผ๊ณ ํ๋๊ตฐ์.. ใ ใ ํน์ ํธ๊ธฐ์ฌ์ ํด๋ณด์ ๋ถ๋ค ๋ถ๋ช ์์ผ์ค ๊ฒ ๊ฐ์ต๋๋ค. (์ ๋ ํด๋ดค์ง๋ง์ใ ใ )
๋ง์ง๋ง์ผ๋ก ์ด ํฌ์คํ ์ ์ ๊ฒ๋ ๊ณ๊ธฐ๋....
2๋ ์ ๋ ๋์ด์ ์ด์ ์์ ๋ณด๋ฉด, ์กฐ๊ธ ์๋ฏธ๊ฐ ์๋ ๋ถ๋ถ๋ ์์ง๋ง ์ด๋ป๊ฒ ๋ณด๋ฉด ๊ผญ ๋จ๊ธฐ๊ณ ์ถ์ ์์์ด์ ๊ธ์ด๊ธฐ๋ ํฉ๋๋ค. ์ค์ํ ๋ด์ฉ๋ ์ธ๊ธ์ด ์ ๋์ด ์๊ณ , ๋ฏธ๋์ ํ๋ก๊ทธ๋๋จธ๋ค์ ์ํ ๋ํ์ ๋ด์ง ํน์ ๊ทธ๊ฑธ ํฌ๋งํ๊ณ ์๋ ์ฒญ์๋ ๋ค์๊ฒ๋ ์ข์ ๋ด์ฉ์ด ์๋๊น ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ , ์ ๊ฐ ๊ฐ์ธ์ ์ผ๋ก ๋ณด๊ดํ๊ณ ์ถ์ ์์ดํ ์ด๊ธฐ๋ ํ๊ตฌ์. ์ด๋ฒ ํฌ์คํ ์ ์ฌ๊ธฐ์ ๋ง์น๊ฒ ์ต๋๋ค.
'Programming > Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[RxJava] 2. Reactive ๊ธฐ๋ณธ ์ฐ์ฐ์(Operator) - map, filter, reduce (0) | 2021.01.23 |
---|---|
[RxJava] 1. RxJava์ ๊ธฐ๋ณธ - Observable (0) | 2021.01.10 |
[RxJava] RxJava๋ก ์์ํ๋ Java Reactive ํ๋ก๊ทธ๋๋ฐ (5) | 2021.01.09 |
[Java] - Java Stream API (0) | 2020.01.11 |
[GP] Junit5๋ฅผ ์ฌ์ฉํ Java ํ ์คํธ ์ฝ๋ ์์ฑ (0) | 2019.09.29 |