U E D R , A S I H C RSS

Java/Mode Selection Performance Test

Servlet ์—์„œ, ๋˜๋Š” Switch - Case ๋“ฑ ๋งŽ์€ ๋ถ„๊ธฐ๋ฅผ ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๋””์ž์ธ & ํผํฌ๋จผ์Šค ๊ด€์ ์—์„œ์˜ ๊ตฌ๊ฒฝ.

1. if-else

๋Œ€๊ฐ• ๋‹ค์Œ์˜ ์ฝ”๋“œ ์Šคํƒ€์ผ์ผ๊ฒƒ์ด๋‹ค.
~cpp 
public class IfElse {
    public void printPerformance(String[] modeExecute) {
        long start;
        long end;
        start = System.currentTimeMillis();
        for (int i = 0; i < ModeChoicePerformanceTest.LOOPING_COUNT; i++) {
            executeIfElse(modeExecute);
        }
        end = System.currentTimeMillis();
        System.out.println("if - else elapsed time :" + (end - start) + "ms ");
    }

    private void executeIfElse(String[] modeExecute) {
        for (int i = 0; i < modeExecute.length; i++) {
            executeWithIfElse(modeExecute[i]);
        }
    }

    public void executeWithIfElse(String mode) {
        if (mode.equals("One")) {
            doOne(1);
        } else if (mode.equals("Two")) {
            doTwo(1);
        } else if (mode.equals("Three")) {
            doThree(1);
        } else if (mode.equals("Four")) {
            doFour(1);
        } else if (mode.equals("Five")) {
            doFive(1);
        } else {
            doDefault(1);
        }
    }


    public void doOne(int i) {
        i = 10;
    }

    public void doTwo(int i) {
        i = 10;
    }

    public void doThree(int i) {
        i = 10;
    }

    public void doFour(int i) {
        i = 10;
    }

    public void doFive(int i) {
        i = 10;
    }

    public void doDefault(int i) {
        i = 100;
    }
}
์ด ๋ฐฉ๋ฒ•์€ ์ผ๋‹จ ์†๋„์ƒ์œผ๋ก  ๊ฐ€์žฅ ๋น ๋ฅด๋‹ค. ํ•˜์ง€๋งŒ, ํ•œํŽธ์œผ๋กœ
Seminar:WhySwitchStatementsAreBadSmell์— ๊ฑธ๋ฆฌ์ง€ ์•Š์„๊นŒ? ๊ทผ๋ฐ.. ๊ทธ์— ๋Œ€ํ•œ ๋ฐ˜๋ก ์œผ๋กœ ๋“ค์–ด์˜ค๋Š”๊ฒƒ์ด '์ด๊ฑด mode ๋ถ„๊ธฐ์ด๋ฏ€๋กœ ์•ž์—์„œ์˜ Switch-Statement ์—์„œ์˜ ์˜ˆ์™€๋Š” ๋‹ค๋ฅธ ์ƒํ™ฉ ์•„๋‹ˆ๋ƒ. ์–ด์ฐจํ”ผ ๋ถ„๊ธฐ ์ดํ›„์—” ๊ทธ๋ƒฅ ํ•ด๋‹น ๋ถ€๋ถ„์ด ์‹คํ–‰๋˜๊ณ  ๋์ด๋‹ค.' ๋ผ๊ณ  ๋งํ• ๊ฒƒ์ด๋‹ค. ๊ธ€์Œ”. ๋ชจ๋ฅด๊ฒ ๋‹ค.
ํ•œํŽธ์œผ๋กœ ๋А๊ปด์ง€๋Š” ๊ฒƒ์œผ๋กœ๋Š”, switch ๋กœ ๋ถ„๊ธฐ๋ฅผ ๋‚˜๋ˆŒ mode string ๊ณผ ์›น parameter ์™€์˜ ์ค‘๋ณต์ด ์žˆ์„ ๊ฒƒ์ด๋ผ๋Š” ์ ์ด ๋ณด์ธ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•˜๋‚˜์˜ mode ๊ฐ€ ๋Š˜์–ด๋‚ ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น method ๊ฐ€ ๋Š˜์–ด๋‚˜๊ณ , mode string ์ด ๋Š˜์–ด๋‚˜๊ณ , if-else ๊ตฌ๋ฌธ์ด ์ฃผ์šฑ ๊ธธ์–ด์ง„๋‹ค๋Š” ์ ์ด ์žˆ๋‹ค. ์ง€๊ธˆ์€ ๋ฉ”์†Œ๋“œ๋กœ ์ถ”์ถœ์„ ํ•ด๋†“์€ ์ƒํ™ฉ์ด์ง€๋งŒ, ๋งŒ์ผ ์ € ๋ถ€๋ถ„์ด ๋ฉ”์†Œ๋“œ๋กœ ์ถ”์ถœ์ด ์•ˆ๋˜์–ด์žˆ๋‹ค๋ฉด? ๊ทธ๊ฑด ๋‹จ ํ•œ๋งˆ๋”” ๋ฐ–์— ํ• ๋ง์ด ์—†๋‹ค. (๋‹จ, ์ € ๋…ผ๋ฌธ์„ ์•„๋Š” ์‚ฌ๋žŒ์— ํ•œํ•ด์„œ) GotoStatementConsideredHarmful.

๋‘๋ฒˆ์งธ - Method reflection

~cpp 

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

public class MethodFullReflection {
    public void printPerformance(String[] modeExecute) throws InvocationTargetException, IllegalAccessException {
        long start;
        long end;
        start = System.currentTimeMillis();
        for (int i = 0; i < ModeChoicePerformanceTest.LOOPING_COUNT; i++) {
            executeReflection(modeExecute);
        }
        end = System.currentTimeMillis();
        System.out.println("elapsed time :" + (end - start) + "ms ");

    }

    private void executeReflection(String[] modeExecute) throws InvocationTargetException, IllegalAccessException {
        for (int i = 0; i < modeExecute.length; i++) {
            Method method = null;
            try {
                method = this.getClass().getMethod("do" + modeExecute[i], new Class[]{int.class});
                method.invoke(this, new Object[]{new Integer(1)});
            } catch (NoSuchMethodException e) {
                this.doDefault(1);
            } catch (SecurityException e) {
                e.printStackTrace();  //To change body of catch statement use Options | File Templates.
            }
        }
    }

    private void doDefault(int i) {
        i = 100;
    }

    public void doOne(int i) {
        i = 10;
    }

    public void doTwo(int i) {
        i = 10;
    }

    public void doThree(int i) {
        i = 10;
    }

    public void doFour(int i) {
        i = 10;
    }

    public void doFive(int i) {
        i = 10;
    }

}
์žฅ์  : MODE ๊ฐ€ ์ถ”๊ฐ€๋ ๋•Œ๋งˆ๋‹ค doXXX ์‹์œผ๋กœ ์ด๋ฆ„์„ ์ •ํ•ด์ฃผ๊ณ  ์ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค. ์กฐ๊ฑด ๋ถ„๊ธฐ ๋ถ€๋ถ„์˜ ์ฝ”๋“œ๊ฐ€ ์ฆ๊ฐ€๋˜์ง€ ์•Š๊ณ , ํ•ด๋‹น Mode ๊ฐ€ ์ถ”๊ฐ€๋ ๋•Œ๋งˆ๋‹ค ๋ฉ”์†Œ๋“œ ํ•˜๋‚˜๋งŒ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
๋‹จ์  : ์ž๋ฐ”์—์„œ๋Š” Method Reflection & Invoke ๊ฐ€ ์—„์ฒญ ๋А๋ฆฌ๋‹ค.; ์†๋„๋Š” ๋ฐ‘์˜๊บผ ์ฐธ์กฐ.

์„ธ๋ฒˆ์งธ. ์œ„์˜ ๋ฐฉ๋ฒ•์„ ๋ณด์™„ํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค. ๋ฐ”๋กœ ์ผ์ข…์˜ Table Lookup.

~cpp 

import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

/**
 * User: Administrator Date: 2003. 7. 12. Time: ์˜ค์ „ 12:48:38
 */
public class MethodTableLookupReflection {
    public void printPerformance(String[] modeExecute) throws InvocationTargetException, IllegalAccessException {
        long start;
        long end;
        start = System.currentTimeMillis();
        initReflectionMap(modeExecute);
        end = System.currentTimeMillis();
        System.out.println("reflection with method initialize table elapsed time :" + (end - start) + "ms ");

        start = System.currentTimeMillis();
        for (int i = 0; i < ModeChoicePerformanceTest.LOOPING_COUNT; i++) {
            executeReflectionWithMapping(modeExecute);
        }
        end = System.currentTimeMillis();
        System.out.println("reflection with method elapsed time :" + (end - start) + "ms ");

    }

    private static Map methodMap;


    private void executeReflectionWithMapping(String[] modeExecute) throws InvocationTargetException, IllegalAccessException {
        for (int i = 0; i < modeExecute.length; i++) {
            Method method = (Method) methodMap.get(modeExecute[i]);
            if (method != null)
                method.invoke(this, new Object[]{new Integer(1)});
            else
                doDefault(1);
        }
    }

    private void initReflectionMap(String[] methodNames) {
        methodMap = new HashMap();
        for (int i = 0; i < methodNames.length; i++) {
            try {
                methodMap.put(methodNames[i], this.getClass().getMethod("do" + methodNames[i], new Class[]{int.class}));
            } catch (NoSuchMethodException e) {
            } catch (SecurityException e) {
            }
        }

    }

    private void doDefault(int i) {
        i = 100;
    }

    public void doOne(int i) {
        i = 10;
    }

    public void doTwo(int i) {
        i = 10;
    }

    public void doThree(int i) {
        i = 10;
    }

    public void doFour(int i) {
        i = 10;
    }

    public void doFive(int i) {
        i = 10;
    }
}
์ด ๋ฐฉ๋ฒ•์€ ์œ„์˜ ๋ฐฉ๋ฒ•๊ณผ ๊ฐ™์€ ์žฅ์ ์„ ์ง€๋‹ˆ๋ฉด์„œ ํผํฌ๋จผ์Šค๋ฅผ ๊ฑฐ์˜ 10๋ฐฐ๊ฐ€๋Ÿ‰ ํ–ฅ์ƒ์‹œํ‚จ๋‹ค.

๋„ค๋ฒˆ์งธ. Inner Class ์— ๋Œ€ํ•ด Command Pattern ์˜ ์‚ฌ์šฉ.

~cpp 

import java.util.Map;
import java.util.HashMap;

/**
 * User: Administrator Date: 2003. 7. 12. Time: ์˜ค์ „ 12:57:7
 */
public class InterfaceTableLookup {
    protected Map modeMap = new HashMap();

    public void printPerformance(String[] modeExecute) {
        long start;
        long end;
        start = System.currentTimeMillis();
        initModeMap();
        end = System.currentTimeMillis();
        System.out.println("interface table lookup init table elapsed time :" + (end - start) + "ms ");

        start = System.currentTimeMillis();
        for (int i = 0; i < ModeChoicePerformanceTest.LOOPING_COUNT; i++) {
            executeInnerclassMapping(modeExecute);
        }
        end = System.currentTimeMillis();
        System.out.println("interface table lookup elapsed time :" + (end - start) + "ms ");


    }

    private void executeInnerclassMapping(String[] modeExecute) {
        for (int i = 0; i < modeExecute.length; i++) {
            executeMode(modeExecute[i]);
         }
    }

    private void executeMode(String s) {
        IMode mode = (IMode) modeMap.get(s);
        if (mode == null) doDefault(1);
        else mode.execute(1);
    }

    public class ExOne implements IMode {
        public void execute(int i) {
            i = 10;
        }
    }

    public  class ExTwo implements IMode {
        public void execute(int i) {
            i = 10;
        }
    }

    public class ExThree implements IMode {
        public void execute(int i) {
            i = 10;
        }
    }

    public class ExFour implements IMode {
        public void execute(int i) {
            i = 10;
        }
    }

    public class ExFive implements IMode {
        public void execute(int i) {
            i = 10;
        }
    }

    private void initModeMap() {
        modeMap.put("One", new ExOne());
        modeMap.put("Two", new ExTwo());
        modeMap.put("Three", new ExThree());
        modeMap.put("Four", new ExFour());
        modeMap.put("Five", new ExFive());
    }
}
์ด ๋ฐฉ๋ฒ•์€ initModeMap ์—์„œ ๋งค๋ฒˆ Mode์— ๋Œ€ํ•œ ๋“ฑ๋ก์„ ํ•ด์ค˜์•ผ ํ•œ๋‹ค. ํผํฌ๋จผ์Šค๋Š” Method Reflection ๋ณด๋‹ค ํ›จ์”ฌ ๋น ๋ฅด๋‹ค.

๋งˆ์ง€๋ง‰ ๋ฐฉ๋ฒ• - interface & reflection

์œ„์˜ ๋ฐฉ๋ฒ•์— initModeMap ์„ reflection ์œผ๋กœ ์ฒ˜๋ฆฌํ•œ ๊ฒƒ์ด๋‹ค.
~cpp 
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * User: Administrator Date: 2003. 7. 12. Time: ์˜ค์ „ 1:2:16
 */
public class InterfaceTableLookupReflection {
    public void printPerformance(String[] modeExecute) throws NoSuchMethodException, InstantiationException, ClassNotFoundException, InvocationTargetException, IllegalAccessException {
        long start;
        long end;
        start = System.currentTimeMillis();
        initModeMapWithReflection(modeExecute);
        end = System.currentTimeMillis();
        System.out.println("interface reflection & table lookup init able elapsed time :" + (end - start) + "ms ");

        start = System.currentTimeMillis();
        for (int i = 0; i < ModeChoicePerformanceTest.LOOPING_COUNT; i++) {
            executeInnerclassMapping(modeExecute);
        }
        end = System.currentTimeMillis();
        System.out.println("interface reflection & table lookup elapsed time :" + (end - start) + "ms ");

    }

    private void executeInnerclassMapping(String[] modeExecute) {
        for (int i = 0; i < modeExecute.length; i++) {
            executeMode(modeExecute[i]);
         }
    }

    private void executeMode(String s) {
        IMode mode = (IMode) modeMap.get(s);
        if (mode == null) doDefault(1);
        else mode.execute(1);
    }

    protected Map modeMap = new HashMap();
    public final static String modeClassHeader = "Ex";
    String expectedClassNameHeader = this.getClass().getName() + "$" + modeClassHeader;

    private void initModeMapWithReflection(String[] modeExecute) throws InstantiationException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Class[] consParamClasses = new Class[]{this.getClass()};
        Object[] consParams = new Object[]{this};


        Class[] inners = this.getClass().getClasses();
        for (int i=0;i<inners.length;i++) {
            if (inners[i].getName().startsWith(expectedClassNameHeader)) {
                Constructor innerCons = inners[i].getDeclaredConstructor(consParamClasses);
                modeMap.put(modeExecute[i], innerCons.newInstance(consParams));
            }
        }
    }

    public void doDefault(int i) {
        i = 100;
    }

    public class ExOne implements IMode {
        public void execute(int i) {
            i = 10;
        }
    }

    public  class ExTwo implements IMode {
        public void execute(int i) {
            i = 10;
        }
    }

    public class ExThree implements IMode {
        public void execute(int i) {
            i = 10;
        }
    }

    public class ExFour implements IMode {
        public void execute(int i) {
            i = 10;
        }
    }

    public class ExFive implements IMode {
        public void execute(int i) {
            i = 10;
        }
    }
}
์ด ๋ฐฉ๋ฒ•์€ Mode ์ถ”๊ฐ€์‹œ ๊ทธ๋ƒฅ ExModeName ์‹์œผ๋กœ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด์„œ Mode ์กฐ๊ฑด ๋ถ„๊ธฐ ๋ถ€๋ถ„์ด ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค. Reflection์œผ๋กœ table lookup ์ฑ„์šฐ๋Š” ๋ถ€๋ถ„์ด๋‚˜ Mode ์กฐ๊ฑด ๋ถ„๊ธฐ ๋ถ€๋ถ„์„ ์•„์— ์ƒ์œ„ ํด๋ž˜์Šค๋กœ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. ํผํฌ๋จผ์Šค๋ฉด์—์„œ๋Š” ์˜์™ธ๋กœ ์•ž์—์„œ ์ˆ˜๋™์œผ๋กœ map ์„ ์ฑ„์šฐ๋Š” ๋ฐฉ๋ฒ•๊ณผ ๊ฐ™๋‹ค. ์œ ์—ฐ์„ฑ๊ณผ ํผํฌ๋จผ์Šค ๋‘๊ฐ€์ง€๊ฐ€ ์ ์ ˆํžˆ ์–ด์šธ์–ด์ง€๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.


์ด๊ฑด ์œ„์˜ ํ…Œ์ŠคํŠธ๋“ค์„ ํ•œ๋ฒˆ์— ์‹คํ–‰์‹œํ‚ค๊ธฐ ์œ„ํ•œ runner class.
~cpp 
import java.lang.reflect.InvocationTargetException;

/*
  ํ‰๊ฐ€ํ•˜๋ ค๋Š” ์กฐ๊ฑด๋“ค :
  1. ํ•ด๋‹น method ์˜ naming ์œผ๋กœ reflection call.
  2. switch - case ๋กœ mode ๊ตฌ๋ถ„.
  3. interface & class - command pattern ์˜ ๊ตฌํ˜„.

  ํ‰๊ฐ€์š”์†Œ๋“ค
  1. ํ•ด๋‹น ์ฝ”๋“œ ์ž‘์„ฑ๋Œ€๋น„ ๋Š˜์–ด๋‚˜๋Š” ๋ฐ˜๋ณต ์ž‘์—…๋“ค
  2. performance
  3. maintance
*/
public class ModeChoicePerformanceTest {
    public static final int LOOPING_COUNT = 1000000;

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ClassNotFoundException, InstantiationException {
        String[] modeExecute = new String[]{"One", "Two", "Three", "Four", "Five", "hugu"};

        new IfElse().printPerformance(modeExecute);
        new MethodFullReflection().printPerformance(modeExecute);
        new MethodTableLookupReflection().printPerformance(modeExecute);
        new InterfaceTableLookup().printPerformance(modeExecute);
        new InterfaceTableLookupReflection().printPerformance(modeExecute);
    }
}

๊ฒฐ๊ณผ

~cpp 
if - else elapsed time :611ms 
elapsed time :61889ms 
reflection with method initialize table elapsed time :0ms 
reflection with method elapsed time :6459ms 
interface table lookup init table elapsed time :10ms 
interface table lookup elapsed time :741ms 
interface reflection & table lookup init able elapsed time :10ms 
interface reflection & table lookup elapsed time :731ms 


Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:23:33
Processing time 0.0098 sec