Try this. The initial reflection is certainly expensive, but if you're going to use it many many times, which I think you will, this is most certainly a better solution what what you're proposing. I don't like using reflection, but I find myself using it when I don't like the alternative to reflection. I do think that this will save your team a lot of headache, but you must pass the name of the method (in lowercase).
In other words, rather than pass "name", you would pass "fullname" because the name of the get method is "getFullName()".
Map<String, Method> methodMapping = null;
public Object getNode(String name) {
Map<String, Method> methods = getMethodMapping(contact.getClass());
return methods.get(name).invoke(contact);
}
public Map<String, Method> getMethodMapping(Class<?> contact) {
if(methodMapping == null) {
Map<String, Method> mapping = new HashMap<String, Method>();
Method[] methods = contact.getDeclaredMethods();
for(Method method : methods) {
if(method.getParameterTypes().length() == 0) {
if(method.getName().startsWith("get")) {
mapping.put(method.getName().substring(3).toLower(), method);
} else if (method.getName().startsWith("is"))) {
mapping.put(method.getName().substring(2).toLower(), method);
}
}
}
methodMapping = mapping;
}
return methodMapping;
}
If you need to access data contained within members of contact, you might consider building a wrapper class for contact which has all methods to access any information required. This would also be useful for guaranteeing that the names of the access fields will always remain the same (I.e. if wrapper class has getFullName() and you call with fullname, it will always work even if contact's getFullName() has been renamed -- it would cause compilation error before it would let you do that).
public class ContactWrapper {
private Contact contact;
public ContactWrapper(Contact contact) {
this.contact = contact;
}
public String getFullName() {
return contact.getFullName();
}
...
}
This solution has saved me several times, namely when I wanted to have a single data representation to use in jsf datatables and when that data needed to be exported into a report using jasper (which doesn't handle complicated object accessors well in my experience).
I was then asked how many strings this program would generate, assuming garbage collection does not happen. My thoughts for n=3 was (7)
Strings 1 (""
) and 2 ("a"
) are the constants in the program, these are not created as part of things but are 'interned' because they are constants the compiler knows about. Read more about this at String interning on Wikipedia.
This also removes strings 5 and 7 from the count as they are the same "a"
as String #2. This leaves strings #3, #4, and #6. The answer is "3 strings are created for n = 3" using your code.
The count of n2 is obviously wrong because at n=3, this would be 9 and even by your worst case answer, that was only 7. If your non-interned strings was correct, the answer should have been 2n + 1.
So, the question of how should you do this?
Since the String is immutable, you want a mutable thing - something you can change without creating new objects. That is the StringBuilder.
The first thing to look at is the constructors. In this case we know how long the string will be, and there is a constructor StringBuilder(int capacity)
which means we allocate exactly as much as we need.
Next, "a"
doesn't need to be a String, but rather it can be a character 'a'
. This has some minor performance boosting when calling append(String)
vs append(char)
- with the append(String)
, the method needs to find out how long the String is and do some work on that. On the other hand, char
is always exactly one character long.
The code differences can be seen at StringBuilder.append(String) vs StringBuilder.append(char). Its not something to be too concerned with, but if you're trying to impress the employer it is best to use the best possible practices.
So, how does this look when you put it together?
public String foo(int n) {
StringBuilder sb = new StringBuilder(n);
for (int i = 0; i < n; i++) {
sb.append('a');
}
return sb.toString();
}
One StringBuilder and one String have been created. No extra strings needed to be interned.
Write some other simple programs in Eclipse. Install pmd and run it on the code you write. Note what it complains about and fix those things. It would have found the modification of a String with + in a loop, and if you changed that to StringBuilder, it would have maybe found the initial capacity, but it would certainly catch the difference between .append("a")
and .append('a')
Best Answer
As far as I can tell, the question is why wrapping String constants into enum hasn't been considered sufficient to cover the needs of language users. This has been addressed in the official feature proposal announced at JDK 7 (project Coin) mailing list.
Per my reading of the proposal, alternative of using enums has been dismissed on the ground that it introduces types bloat. For your convenience, relevant part of the proposal is quoted below, with the statement addressing enums quoted in bold: