1

I have heard Java reflection is slower than a regular method call. But obviously it's needed in programming to call a method dynamically. I have seen frameworks like spring and hibernate uses reflection to call getter/setters and invoke web methods.

Spring mvc invoking a controller method:

at com.sampleapp.admin.controller.LoginController.login(LoginController.java:49)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:729)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)

Hibernate creating a new instance:

at com.sampleapp.orm.model.Publisher.<init>(Publisher.java:61)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.hibernate.engine.internal.UnsavedValueFactory.instantiate(UnsavedValueFactory.java:46)
    at org.hibernate.engine.internal.UnsavedValueFactory.getUnsavedIdentifierValue(UnsavedValueFactory.java:68)
    at org.hibernate.tuple.PropertyFactory.buildIdentifierProperty(PropertyFactory.java:75)
    at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:145)
    at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:505)
    at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:146)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.hibernate.persister.internal.PersisterFactoryImpl.create(PersisterFactoryImpl.java:163)
    at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:135)
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:381)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1746)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1784)

So that means even mature frameworks are using reflection regularly. Then is it good to use reflection in our code? Will it cause a notable performance impact? (If my app is expected to handle somewhat large number of requests per second) Or should I always look for alternatives such as 'bytecode manipulation'?

Craz Joe
  • 47
  • 4
  • 3
    Not sure whether to flag this as too broad or opinion-based, but it's not possible to give a substantive answer to the question as posed. – shmosel Feb 18 '18 at 08:31
  • *"But obviously it's needed in programming to call a method dynamically..."* Not necessarily, now that there are [method references](https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html). It depends on what you're doing. – T.J. Crowder Feb 18 '18 at 08:38
  • To focus on JPA/Hibernate, there isn't really an alternative to reflection. Also, bear in mind that database operations can take a relatively long time, if they connect to a different server, so the penalty of reflection may not be so bad. And there's the cost of having to develop and maintain non-reflection code such as JDBC. But indeed, the question *is* very broad. – SeverityOne Feb 18 '18 at 08:39
  • Whether it's okay for your project is something only you can decide. Implement a test case with the code/process that makes the most sense to you (is maintainable, understandable, robust, etc.), then measure that [carefully and correctly](https://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java) and make a decision whether it's good enough for what you need to do or you need to do something else that may be less maintainable, understandable, robust... We can't answer the question for you. – T.J. Crowder Feb 18 '18 at 08:43
  • Anyway thanks everyone. Yes I understand that _whether to use to not in project_ is something that I should decide. May be in most of the cases the performance penalty is neglect-able. We should worry about other things when it comes to performance. Isn't it? – Craz Joe Feb 18 '18 at 08:51
  • See also: https://stackoverflow.com/questions/19557829/faster-alternatives-to-javas-reflection – lexicore Feb 18 '18 at 10:45

2 Answers2

1

Trying to answer your (very broad) question:

It's not "good" to use reflection, it's an evil that you sometimes cannot avoid. Why is it evil?

  • Compile-time checks no longer apply. If you call a method with the wrong number or wrong types of arguments via reflection, the compiler no longer rejects your call, but you'll get an exception at runtime.

  • It makes static code analysis impossible, e.g. Eclipse's "Call Hierarchy" can't find the places where a method is called via reflection.

  • It is slower than a direct call.

To me, the first two reasons are important, meaning that you need to invest more effort into quality assurance, and have a less readable and maintainable code (because the usual tools don't help any more).

Regarding performance, don't think about that before you really experience a problem. Dont fall into a "Premature Optimization" trap.

So, if there is no other way to solve your problem (and please, think hard about that), go for reflection. But make sure to deal with the quality and maintenance risks you hereby introduce.

Ralf Kleberhoff
  • 6,990
  • 1
  • 13
  • 7
  • Yeah I understand now, It affects readability and maintainability rather than performance. Thank you very much. – Craz Joe Feb 18 '18 at 14:20
0

If you can avoid reflection in frequently-called methods, do avoid it. The problem is, however, than you often really need some kind of reflected invocation so there are cases where you simply can't avoid reflection.

The question is then not really if you should or should not use reflected invocations but rather if and how you should optimize such calls.

For this, please see the following post:

Faster alternatives to Java's reflection

This answer suggests that reflection performance in Java 8 was quite improved. So before you start optimizing anything, it would make sense to run some benchmarks or do some profiling (run a lot of iterations) to make sure that it's really reflection which eats your performance.
Hint: it is mostly not.

Anyway, I won't really worry about reflection performance. There are very good techniques to improve performance of reflected invocations which even don't need much code changes. See this blog post, for instance for example of using LambdaMetafactory to almost achieve the performance of direct invocations. If you worry about performance, it might make sense to implement reflected invocations in some kind of utility class/method centrally so that you could reimplement/improve it later on in just one place.

lexicore
  • 42,748
  • 17
  • 132
  • 221
  • Thank you very much. Seems like there are good alternatives to reflection most of the time. Worth reading! – Craz Joe Feb 18 '18 at 14:23
  • @CrazJoe FYI I'm developing Java for almost 20 years now and I never actually needed to replace reflection with anything else. I did it a couple of times (bytecode generation) and found out that it was unnecessary optimization and complexity afterwards. – lexicore Feb 18 '18 at 14:24