Video icon 64
Learning to code? Skill up faster with our practical video courses. Start your free trial today.
Advertisement

Code Workshop: Java Strings

by
Student iconAre you a student? Get a yearly Tuts+ subscription for $45 →

In this Code Workshop we will be testing your knowledge of Java Strings. Within the sample code, String variables are going to be processed within a Java class, which in turn has an inner class. To successfully figure out what will happen when the code executes, you must understand not only String basics, but also the principles of objects and classes, as well as control structures including methods, loops and conditionals.

When you work through the code, remember that the programmer who wrote it may have mistakes in their logic. The code does not contain any syntax errors that will throw exceptions at runtime, but the outcome may not necessarily be what the programmer intended. When you work on any programming project, there is a strong chance you will end up working with someone else's code, or code you wrote yourself at some point in the past and can barely remember. Unfortunately, we humans tend not to produce perfect code very often, so reading with a critical eye is essential.


The Problem

The Java code below represents a Java class file with an inner class in it. In the code, text String variables undergo several different processes. What happens when the StringFun constructor method executes? Work through the code and take a note of what you think will be written out through the System output statements at points A, B, C, D, E and F, bearing in mind that any of these may execute more than once. You may find it easiest to use a pencil and paper to note what happens as the code progresses.

public class StringFun {
	
	public StringFun() {
		
		String initString = "abcdefghij";
		StringWorker strWorker = new StringWorker(initString);

		String theStr = strWorker.getText();
		System.out.println("POINT A: " + theStr);
		
		strWorker.setText(strWorker.multiplyText(1, theStr));
		System.out.println("POINT B: " + strWorker.getText());
		
		int endPosn = initString.length()/2;
		String endString = (theStr.length()>endPosn ? theStr.substring(0, endPosn) : theStr);
		System.out.println("POINT C: " + endString);
		
		String anotherString = endString.concat(strWorker.getText());
		System.out.println("POINT D: " + anotherString);
	}
	
	public class StringWorker {
		
		private String theText;
		private int maxLength;
		
		public StringWorker(String initText) {
			
		theText = initText;
		maxLength = 5;
		shortenString();
		multiplyText(2, theText);
		System.out.println("POINT E: " + theText);
		
		}
		
		private void shortenString() {
			
			if(theText.length()>maxLength)
				theText.substring(0, maxLength);

		}
		
		public String multiplyText(int multBy, String multText) {
			
			StringBuilder sBuild = new StringBuilder(multText);
			for(int i=0; i<multBy; i++)
				sBuild.append(multText);
			System.out.println("POINT F: " + multText);
			return sBuild.toString();
			
		}
		
		public String getText() {
			return theText;
		}
		
		public void setText(String newText) {
			theText = newText;
		}
	}
}

The Solution

This is what is output when the StringFun constructor method executes:

POINT F: abcdefghij
POINT E: abcdefghij
POINT A: abcdefghij
POINT F: abcdefghij
POINT B: abcdefghijabcdefghij
POINT C: abcde
POINT D: abcdeabcdefghijabcdefghij

Notice what String variable is being written out in each statement - sometimes it is the instance variable and sometimes it is a local variable. If this doesn't match what you thought would be output, don't worry. The code is intentionally tricky. If you got the output correct, well done!


Notes and Explanations

The attached source file contains the complete code with annotations explaining what happens during execution. You may gain a better insight by compiling and running the program and adding additional trace statements if you find that helps (add the source Java class file to a project and create an object instance of the StringFun class to begin).

Let's go over some of the trouble spots here.

Immutability

In the StringWorker constructor method, the "shortenString" method is called. Although this method calls the substring method on the instance variable String, it does not actually alter its value. In Java, Strings are immmutable. This means that when you alter a String, Java actually creates a new String. The substring method does not alter the String it is called on, but copies its content into a new String with the substring alteration applied, returning this new String value. If the substring method call was altered as follows:

theText = theText.substring(0, maxLength);

The result would be different, as the instance variable would be updated to contain the new substring. As the code stands, the method returns "abcde" but does nothing with it.

Parameters and Returns

Another potentially tricky part of the code is the "multiplyText" method. The confusion here is caused both by the method having an inappropriate name and it not being used appropriately. If, rather than working through the method content, you took an intuitive interpretation of this method, you would assume its purpose would be to multiply the text by the number passed as an integer parameter. In actual fact the method appends the text to itself that many times, which means it results in one more "times" itself than you might expect. Method names can have a huge impact on how usable a Java library or program is, as can variable and class names.

The "multiplyText" method is called twice in the code, once in the StringFun constructor and once in the StringWorker constructor. In the StringWorker constructor, the code does nothing with the returned String and so the method call effectively does nothing. The "multiplyText" method does not alter the instance variable String. It carries out alterations on a passed String, returning the result as a new String. When the "multiplyText" method is called in the StringFun constructor, this time the code does do something with the result - it sets the StringWorker instance variable to the returned String, using the "setText" method.

These confusions are not just an indicator of using a method inappropriately, but a sign that the method itself is probably badly designed and named. The "shortenString" method alters the class instance variable, whereas the "multiplyText" method does not have any affect on the instance variable. Whether either or both of these are appropriate depends on the purpose of the class within the application, but their names need to reflect their purpose in a way that is intuitive to understand.

Which Variable?

The other general source of confusion in the code is the fact that we are dealing with several different class and local variables. For example, if you look at the section in the StringFun constructor where we create a new local variable named "endString", you will see that it carries out processing on a variable named "theStr" which was created a few lines before. Given the processing that happens between these two sections, you may intuitively expect the "endString" section to be processing the newly altered StringWorker object instance variable rather than an earlier local variable. The code therefore seems counter-intuitive, but again, such interpretations are hampered by the lack of commentary indicating the purpose of either class, or any of the variables.


Conclusion

OK, so the code had a few tricks in it. However, this is to reflect the reality of working on many Java projects. Even with the best of intentions most code contains mistakes. Programming projects are often subject to changes of plan that end up resulting in misleading logic as well as variable and method names that seem confusing. If the code is poorly commented, or not commented at all as in the above example, this makes matters even worse.

Having the ability to read code realistically and using practical measures such as trace statements to see what's happening at different points during execution is a real asset in any programming project, as is understanding the language structures.

Advertisement