Лучшая альтернатива отражению, чем большой оператор switch с использованием java 8 - PullRequest
1 голос
/ 07 мая 2020

Мой старый код создает подкласс FrameBody на основе идентификатора

Class<AbstractID3v2FrameBody> c = (Class<AbstractID3v2FrameBody> Class.forName("org.jaudiotagger.tag.id3.framebody.FrameBody" + identifier);
Class<?>[] constructorParameterTypes = {Class.forName("java.nio.ByteBuffer"), Integer.TYPE};
Object[] constructorParameterValues = {byteBuffer, frameSize};
Constructor<AbstractID3v2FrameBody> construct = c.getConstructor(constructorParameterTypes);
frameBody = (construct.newInstance(constructorParameterValues));

Но анализ профиля показывает, что он немного медленный, альтернативой использованию отражения является большой оператор переключения

switch(identifier)
{
    case ID3v24Frames.FRAME_ID_AUDIO_ENCRYPTION:

        frameBody = new FrameBodyAENC(byteBuffer, frameSize);
        break;

    case ID3v24Frames.FRAME_ID_ATTACHED_PICTURE:

        frameBody = new FrameBodyAPIC(byteBuffer, frameSize);
        break;

                .......
    }   

но у меня более 100 идентификаторов, поэтому это кажется немного громоздким

Есть ли более элегантный способ сделать это в Java 8?

1 Ответ

2 голосов
/ 07 мая 2020

РЕДАКТИРОВАТЬ :

Это действительно можно упростить, как предлагает Хольгер:

 Map<String, BiFunction<ByteBuffer, Integer, AbstractID3v2FrameBody>> LOOKUP = Map.of(
           FRAME_ID_AUDIO_ENCRYPTION, FrameBodyAENC::new,   
           FRAME_ID_ATTACHED_PICTURE, FrameBodyAPIC::new
 );

А затем так же просто, как:

LOOKUP.get(ID3v24Frames.FRAME_ID_AUDIO_ENCRYPTION)
      .apply(byteBuffer, frameSize);

ПРЕДЫДУЩЕЕ ПРЕДЛОЖЕНИЕ

Это всего лишь образец, вам нужно будет адаптировать его для ваших классов:

private static final Lookup L = MethodHandles.lookup();
private static final MethodHandle CONS;

static {
    try {
        CONS = L.findConstructor(SomeClass.class, MethodType.methodType(void.class, int.class));
    } catch (Throwable t) {
        throw new RuntimeException(t);
    }
}

private static final Map<String, MethodHandle> LOOK_UP = Map.of(
    "SOME_CLASS", CONS
);

public static void main(String[] args) {

    try {
        SomeClass sc = (SomeClass) LOOK_UP.get("SOME_CLASS").invokeExact(42);
        System.out.println(sc.getX());
    } catch (Throwable t) {
        t.printStackTrace();
    }

}

static class SomeClass {

    private final int x;

    public SomeClass(int x) {
        this.x = x;
    }

    public int getX() {
        return x;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...