People I trust have said that they have run benchmarks that say
reflection 
can cost 5% to 10% more than direct method invocation.

http://archives.java.sun.com/cgi-bin/wa?A2=ind0001&L=jsp-interest&P=R35735

Now this is enough for some maven to put it on an optimization
punchlist, 
along with unrolling loops, and other time vs space trade-offs. But, 
personally, I don't find the need to unroll many loops in the
applications 
I write ;-)

So it's important to ask yourself whether 5% to 10% is a difference that 
makes a difference?

Also remember that in a real application, we are looking at one 
utility method, like BeanUtils.populate(), being threaded with all the 
assignments. I would think this is much more efficient than loading 
several hundred "optimized" methods just to manage direct method
invocations. 
BeanUtils.populate() also caches the descriptors so subsequent calls are 
even cheaper than the first.

Real-life optimizations are differences that make a real difference.
When 
the EJB platform was being designed, object creation ~did~ make a 
difference, and caching ~was~ vital. To an extent it still is, 
especially with deep hierarchies, like those many EJB applications 
find themselves using. But object creation and garbage collection in a
late 
model JVM is not what it used to be ;-) Progress!

Meanwhile, personally, I've started to build calls to
BeanUtils.populate()
into my own data transfer utilities. This lets me put a call deep inside
the resource layer that neatly turns an arbitrary ResultSet into a 
collection of arbitrary beans. It just matches the rset columns with the 
jbean properties.

// Transfer ResultSet to Collection of target beans **
if (resultSet!=null) {
        collection = ResultSetUtils.getCollection(
                target,resultSet);
}

Where ResultSetUtils does this 

    public static void populate(Object bean,
                                ResultSet resultSet)
        throws SQLException {
        // Build a list of relevant column properties from this
resultSet
        HashMap properties = new HashMap();
        // Acquire resultSet MetaData
        ResultSetMetaData metaData = resultSet.getMetaData();
        int cols = metaData.getColumnCount();
        // Scroll to next record and pump into hashmap
        if (resultSet.next()) for (int i=1; i<=cols ; i++) {
            // :TODO: Let native types through
            /*
            int type = metaData.getType(i);
            if ...
            properties.put(metaData.getColumnName(i),
                resultSet.getObject(i));
            else
            */
            properties.put(metaData.getColumnName(i),
                resultSet.getString(i));
        }
        // Set the corresponding properties of our bean
        try {
            BeanUtils.populate(bean, properties);
        } catch (Exception e) {
            throw new SQLException("BeanUtils.populate threw " +
e.toString());
        }
    }

This can save hundreds of lines of code that would have otherwise have
been 
needed to write custom transfer utilities. (Been there, did that, not
fun.)

Of course, it works with more than just ResultSets. I wrote a similar
set
of utilities last week that turned a Lucene Hits list into a collection 
of beans. Sweet ;-)


Here are some other links from this list:

http://www.mail-archive.com/struts-user@jakarta.apache.org/msg12574.html

http://www.mail-archive.com/struts-user@jakarta.apache.org/msg13847.html

http://www.mail-archive.com/struts-user@jakarta.apache.org/msg13294.html

http://www.mail-archive.com/struts-user@jakarta.apache.org/msg13149.html

http://www.mail-archive.com/struts-user@jakarta.apache.org/msg11933.html

http://www.mail-archive.com/struts-user@jakarta.apache.org/msg02683.html

http://www.mail-archive.com/struts-user@jakarta.apache.org/msg00374.html


Other background links:

http://java.sun.com/j2se/1.4/docs/guide/reflection/

http://www-106.ibm.com/developerworks/library/introspect/index.html

http://www.javaworld.com/javaworld/jw-11-1999/jw-11-servlet_p.html

http://www.javaworld.com/javaworld/jw-11-1998/jw-11-batch_p.html

http://www.ddj.com/articles/1998/9801/9801c/9801c.htm

http://www.javaworld.com/javaworld/jw-09-1997/jw-09-indepth_p.html


Today's quote:

"We should forget about small efficiencies, say about 97% of the time:
premature optimization is the root of all evil." - Donald Knuth

-T.


Bryan Field-Elliot wrote:
> This is incredibly important stuff! I'm sick to death of making tons of
> EJB entity beans, and then "Value Objects" (or data objects) which are
> very similar, and with Struts, "Form Beans" which again are very
> similar. Often I wish I could just use generic property sets (using
> HashMap, or any other generic collection). But I have resisted on
> principle, because I thought it would be a poor performer compared to
> "straight Java" variables and getters and setters. But here you are
> saying "reflection is no longer a point of concern". What information
> have you got in this regard?
> 
> Also, you go on to say 'ditto for objection creation", and that it's
> "more expensive to cache an object than recreate it". Where are you
> getting this information? It goes against the design considerations of
> virtually every "highly optimized" Java system I've seen, including EJB
> which goes to EXTREME lengths to reuse rather than recreate. You see the
> same pattern with JSP custom tags (nowadays they are pooled), and you
> even see the same thing in the Servlet spec design (which is to have one
> multithreaded instance of the servlet class, rather than one per user
> which would make more logical sense).
> 
> So, my apologies if this is off-topic of Struts, but these seem like
> very important and impactful design issues, relevent (even if
> peripherally) to good Struts design and development.
> 
> Thanks,
> 
> Bryan

Reply via email to