Эффективное использование Java Reflection - это взлом или стандартная практика? - PullRequest
5 голосов
/ 22 февраля 2010

Привет, долгое время слушатель, впервые звонящий, и я задаю вопрос, связанный с рефлексией Java, и как легко она поддается, по-видимому, уродливому кодированию. Следующий метод пытается взять два одинаковых объекта (один объект имеет все поля другого объекта, а затем несколько) и сравнить два из них на равенство. Он (предположительно) вернет истину, если получатели, разделяемые объектами, равны, и вернет ложь, если они не равны.

public boolean validateArchive( Object record, Object arcRecord ) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException
{
    log.debug( record.getClass().toString() );

    Object methodValue;
    Object arcMethodValue;

    for ( Method method : record.getClass().getMethods() )
    {
        if ( method.getTypeParameters().length == 0 && method.getName().startsWith( "get" ) && !method.getName().startsWith( "getClass" ) )
        {
            methodValue = method.invoke( record );
            arcMethodValue = arcRecord.getClass().getMethod( method.getName() ).invoke( arcRecord );

            log.debug( "Method name: " + method.getName() );
            log.debug( "Archive value: " + arcMethodValue );
            log.debug( "Object value: " + methodValue );

            if ( arcMethodValue != null && methodValue != null && !arcMethodValue.equals( methodValue ) )
            {
                return false;
            }
            else
            {
                if ( arcMethodValue == null && methodValue != null || methodValue == null && arcMethodValue != null )
                {
                    return false;
                }
            }
        }
    }

    return true;
}

Этот метод делает то, что я ожидаю, что он сделает в модульных тестах, но выглядит уродливо, и чувствует себя неправильно (я особенно не фанат вложенного «если»). Я просто надеялся на некоторые советы о том, как сделать это более эффективно / результативно. Если я нарушил какое-то правило публикации, не стесняйтесь поправлять меня, я стремлюсь учиться и т. Д.

Ответы [ 4 ]

6 голосов
/ 22 февраля 2010

Для этой конкретной задачи я бы порекомендовал реализовать метод equals в сравниваемых классах, если у вас нет этой опции (например, если у вас нет исходного кода для исходного класса). Как и IntelliJ, IDE обеспечивают поддержку создания методов «равно» и «хэш-код» (в IntelliJ вы предоставляете поля, которые будут сравниваться, и какие поля могут быть нулевыми или нет). Для этого конкретного случая, я бы сказал, пойти с этими инструментами.

Есть один случай, когда я думаю, что реализация, использующая Reflection, будет полезна - в модульном тесте, если вы хотите выбросить ошибку подтверждения, если равенство не истинно, вы можете фактически выбросить утверждение для точного поля, которое ошибка, а не просто общая ошибка утверждения «объект не тот же» - даже в этом случае я бы выполнил равные после моей первоначальной проверки, просто чтобы убедиться, что объекты совпадают, или по крайней мере, метод equals реализован и работает должным образом.

PS: Если вы хотите избавиться от всего этого кодирования, проверьте библиотеку Beans Common ; PS 2: Отражение неплохое, и оно используется везде, где у вас нет явного вызова кода - например, файлы конфигурации Spring. Только не злоупотребляйте этим.

2 голосов
/ 22 февраля 2010

Поскольку вы ищете только «свойства», вы можете использовать commons beanutils , а точнее этот класс ...

(Я полагаю, вы не можете реализовать .equals, потому что ваши объекты не имеют одинаковый тип ...)

1 голос
/ 22 февраля 2010

Я полагаю, что вы проверяете ненужные случаи в ваших if утверждениях и можете свести их к следующему:

if ( arcMethodValue == null ) {
    if ( methodValue != null) {
        return false;
    }
} else if ( !arcMethodValue.equals( methodValue ) ) {
    return false;
}

Кроме того, вы звоните method.getName() 4 раза, вы можете создать переменную и затем использовать ее.

0 голосов
/ 23 февраля 2010

Ваш код возврата неоправданно сложен. Стандартная идиома для сравнения ссылочных типов такова:

  (field1 == null) ? (field2 == null) : field1.equals(field2);

Это намного понятнее и довольно стандартно (Effective Java 2nd Edition, стр. 43).


Обновление:

Была путаница, так как ранее я написал return [idiom]. Да, в этом случае return не будет тем, что хочет оригинальный плакат. Он хотел бы if ![idiom] return false; вместо этого. Я хочу сказать, что [idiom] работает, и он намного лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...