Monday, January 15, 2007

Making Java Strings Simple

Your professor may tell you that using the String concatenation operator "+" can be inefficient. This is not entirely true.
String str = "foo" + "bar" + "Oh my, there must be a more efficient way to concatenate a String";

The above code is optimized by the compiler into something like this
StringBuffer/Builder* _temp = new StringBuffer/Builder().append("foo").append("bar")
.
append("Oh my, there must be a more efficient way to concatenate a String");
String str = _temp.toString();

So which is more efficient for you, typing 97 characters or 191 characters? More than 100% more typing for the same byte code.

There are exceptions though. The most important one being loops.
StringBuffer/Builder _temp = new StringBuffer/Builder();
while(moreDataToAppend()) {
_temp.append(someString);
}
String str = _temp.toString();

The above is preferred to this
String str = "";
while(moreDataToAppend()) {
str + someString;
}

because the second example creates a new StringBuffer/Builder for each iteration (read "more resources are used").


Here is some bytecode to back these claims. First the slower way:
7: getstatic #3; //Field i:I <----Here is the beginning of the loop
10: bipush 36
12: if_icmpge 51
15: new #4; //class java/lang/StringBuilder
18: dup
19: invokespecial #5; //Method java/lang/StringBuilder."":()V <----Here is
the allocation of the StringBuilder (this is invoked in every iteration of the loop)

22: aload_1
23: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)
Ljava/lang/StringBuilder;
26: getstatic #7; //Field data:[Ljava/lang/String;
29: getstatic #3; //Field i:I
32: aaload
33: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)
Ljava/lang/StringBuilder;
36: invokevirtual #8; //Method java/lang/StringBuilder.toString:()
Ljava/lang/String; <----This can also be move outside of the loop
39: astore_1
40: getstatic #3; //Field i:I
43: iconst_1
44: iadd
45: putstatic #3; //Field i:I
48: goto 7 <----Here is the end of the loop


And now the quicker way:
51: new #4; //class java/lang/StringBuilder
54: dup
55: invokespecial #5; //Method java/lang/StringBuilder."":()V <----Here is
the allocation of the StringBuilder

58: astore_2
59: iconst_0
60: putstatic #3; //Field i:I
63: getstatic #3; //Field i:I <----Here is the beginning of the loop
66: bipush 36
68: if_icmpge 94
71: aload_2
72: getstatic #7; //Field data:[Ljava/lang/String;
75: getstatic #3; //Field i:I
78: aaload
79: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)
Ljava/lang/StringBuilder;
82: pop
83: getstatic #3; //Field i:I
86: iconst_1
87: iadd
88: putstatic #3; //Field i:I
91: goto 63 <----Here is the end of the loop
94: aload_2
95: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;


As you can see in this example only the append() method is called inside the loop, whereas in the slower example

*Prior to Java 5 StringBuffer was used, now the preferred class is StringBuilder.

Monday, March 06, 2006

c++ Function Returns

Alas, after using Java compilers for so long now I made another ignorant assumption about c++. If you place your return value for your function inside any type of branching or looping structure make sure that at least one of the return statements can always be reached. If not you will have some major run-time errors that are hard to track down.
string SomeClass::getName() {
if(this->hasName())
return className;
}

In this example when the 'hasName()' function returns false nothing is returned.
But in the case below, even if 'hasName()' is false, something is returned from the function.
string SomeClass::getName() {
if(this->hasName())
return className;
else
return "";
}


Or as I've now learned to do. Turn On The Damn Compiler Warnings!

Monday, December 19, 2005

Java Visible Screen

For Mac OS X you can use Toolkit.getScreenInsets() to setup a full size GUI without rendering into the menubar or the Dock.

An update with more detail:
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] gs = ge.getScreenDevices();
// this only works for one screen, if you need to access more than one
// you will need to loop through every GraphicsDevice
Insets in = Toolkit.getDefaultToolkit().getScreenInsets(gs[0].getConfigurations()[0]);
Dimension size = Toolkit.getDefaultToolkit().getScreenSize();

left = in.left;
right = size.width - in.left - in.right;
top = in.top;
bottom = size.height - in.top - in.bottom;
setBounds(left, top, right, bottom);

Saturday, December 10, 2005

c++ Copy Constructor Conventions

A couple of very simple to follow rules for copy constructors.
Case A: An object has no dynamically allocated pointers. Let the default copy constructor do the work and don't bother writing one.

Case B: If said object does contain dynamic pointers, then you'll need to write your own copy constructor as follows.
MyObject(const MyObject& o) {
// Do some stuff for a true deep copy
// Make new pointers and stuff :)
}

Wednesday, December 07, 2005

c++ Type Conversions Rehash

Another popular way to write this function is by using templates.
template <typename T>
string toString(T& i) {
ostringstream oss;
oss << fixed << i;
return oss.str();
}
This should be put in a header file and needs the following:
sstream
iomanip
string

Tuesday, December 06, 2005

c++ Type Conversions

This will eventually come up in your programming days, so I thought I'd post it.

You need to convert a string input by the user to another data type (I'll use double here to demonstrate.)
//you'll need these includes
#include <string>
#include <sstream>

string s = "23.5"; // we need a string to work with
istringstream istr(s); // this is the stream we pump the string into (done by constructor)
double d; // a place to store the double we are asking for
istr >> d; // here we tell the sstream to pump our string out as a double

This can be easily formed into a function.
double toDouble(string& s) { // we only need a reference to the string since we are not going to modify it
istringstream istr(s);
double d;
istr >> d;
return d;
}

We can also reverse the process.
string toString(int& i) { // we only need a reference to the int since we are not going to modify it
ostringstream ostr;
ostr << fixed << i;
ostr << fixed << setw(8) << setprecision(3) << i;
// this second version adds some handy formatting
return ostr.str();
}

Friday, December 02, 2005

Math4J Library

Math4J: A Mathematics Library

This is new approach for math coding, at least for me. I plan to complete the function design and introduce a statistics design.

Math4J is a java library with an object-oriented design of some mathematical ideas: functions, primality, complex numbers, etc. It also consists of some utility methods and classes for mathematical constructions. This library is open source and currently only in alpha development.