Monthly Archives: March 2013

How to Get Started With Java (as a Beginner)

For better or worse, Java is one of the dominant languages in the software engineering industry. As a software engineering professional, you’ll quite possibly have to work with a Java code base at one point in your career. I am not a big fan of Java, and I don’t think it’s a good first language in the computer science curriculum. Sadly, this is often the case. In fact, Java is a horrible first language. The first two “real” languages I learnt were Python and Scheme (Lisp), and thus I was used to elegance and expressiveness. Java felt like a big step back. For instance, here are a few lines of Python code that print the numbers from 1 to 5:

for i in range(1, 5):
    print i

Here is the equivalent in Java:

package demo;

public class RangeDemo {

	public static void main(String[] args) {
		
		for (int i = 1; i < 5; i++) {
			System.out.println(i);
		}
	}
}

Following Java style guides, you end up with a staggering 11 lines of code instead of 2. Just look at all the wasted horizontal space and the baroque syntax! Proponents of Java like to point out that their language was never designed to write simple “scripts”, but Java bloat is a factor no matter how large your program is. You’ll end up writing reams of code that do very little, and you quickly end up wondering why the code base is metastasizing in front of your eyes. What Python could do in, say, 100 lines could easily require about 1,000 lines in Java. This is not an exaggeration.

I could write a couple of blog posts on the downsides of Java, but my point is merely that there are better languages to learn as a beginner. You are probably better off checking out Python first if you are new to programming. But let’s say you’ve got no choice because you have enrolled in a computer science program, and now you find yourself sitting in an intro class, confused that CS isn’t about playing video games, web design, or using MS Office. Your instructor wields a 1,500 page tome on Java and pontificates about its “industrial strength” and the marvels of object-orientation.

Let’s start with textbooks first. Textbooks seem to get bigger and bigger so that they can be sold for more and more money. Yet, didactically, they only get worse. In case of Java, though, I do think that common textbooks mirror the verbosity of the language they describe in a wondrous way. The OOP course at university I attended used Liang’s Introduction to Java Programming. Just like other similar books, it lacks proper structure, and has absolutely no qualms about wasting the student’s time. The exercises were dull, repetitive and uninspiring. Fortunately, there is a free alternative out there that covers all bases, at least as far as introductory courses are concerned. It is Allen B. Downey’s Think Java: How to Think Like a Computer Scientist. In less than 300 (small) pages, you’ll get acquainted with the basics of the language. If you go through this book in a week or two, then a semester-long course on OOP with Java will teach you barely anything new. It will just take five times longer.

Some teachers tell beginning students to start programming in a text editor first, and to compile and execute their code via the command line. In the case of Java, this is seriously misguided advice. You do not want to spend hours looking for a missing curly bracket because you thought you were “hardcore” and turned off syntax highlighting in your editor. Likewise, tasks like compiling and executing your program are simply repetitive time wasters that should be automated. There is no learning experience in saddling yourself with that kind of manual labor. So, instead of an editor use an IDE. Eclipse is as just bloated as Java, and overkill for what you do in your typical first- or second-year CS course. A more lightweight (and free) alternative is DrJava.

Lastly, you’ll want to do plenty of exercises to get proficient at, well, writing code in Java. Unlike some textbook authors I see little point in going through exercises that have you write classes that don’t do anything but make you resent “object orientation” à la Java. After you’ve written a handful of those, you know how this works. Instead, you should practice programmatic thinking. For this purpose, the Java section on CodingBat is an excellent resource, providing a few hundred exercises. They won’t teach you everything you need to learn, but they will put you well ahead of the pack. If you get stuck, you are welcome to consult the solutions on my website.

Lastly, you might want to check out Stanford’s CS106A: Programming Methodology, which is a free online course that offers an introduction to programming with Java. This course and its associated textbook, The Art and Science of Java by Eric Roberts, start out with a special set of Java libraries, the ACM Java Libraries. Those hide some of the complexities of the language. They allow you to write more concise code, and they also lead to a gentle introduction to object-orientation with Java. The course itself is your standard-fare remedial programming course.

The lecturer, Mehran Sahami, is entertaining and competent, and the course focusses on pretty interesting programming tasks. One of the first bigger projects consists of writing a Breakout clone, for instance. Also, I really liked the introductory sequence, which covers “Karel the Robot”. If you’ve never programmed before and have to get started with Java, this would indeed be a very good starting point. Using those resources, you’ll be well on your way to becoming competent in Java, but I hope you’ll explore some other programming languages too.

CodingBat: Java. Update 2013.2

The Array-2 section on Coding Bat saw an update as well. Those four exercises gradually build up to a variation of the well-known FizzBuzz problem.

All solutions were successfully tested on 29 March 2013.

fizzArray:

public int[] fizzArray(int n) {
	int[] result = new int[n];
	for (int i = 0; i < n; i++)
		result[i] = i;
	return result;
}

fizzArray2:

public String[] fizzArray2(int n) {
	String[] result = new String[n];
	for (int i = 0; i < n; i++)
		result[i] = String.valueOf(i);
	return result;
}

fizzArray3:

public int[] fizzArray3(int start, int end) {
	int n = end - start;
	int[] result = new int[n];

	for (int i = 0; i < n; i++)
		result[i] = start++;
	return result;
}

fizzBuzz:

public String[] fizzBuzz(int start, int end) {
	int n = end - start;
	String[] result = new String[n];

	int pos = 0;
	for (int i = start; i < end; i++) {
		boolean fizz = i % 3 == 0;
		boolean buzz = i % 5 == 0;

		if (fizz && buzz) result[pos] = "FizzBuzz";
		else if (fizz) result[pos] = "Fizz";
		else if (buzz) result[pos] = "Buzz";
		else result[pos] = String.valueOf(i);
		pos++;
	}
	return result;
}

CodingBat: Java. Update 2013.1

As I thought I was done with publishing my solutions to the entire Coding Bat: Java library of exercises, with a total of over 200, Nick Parlante updated his website and added some more exercises. Apparently, his aim was to thoroughly prepare students for “FizzBuzz” interview questions.

The first exercise was added to Warmup-1, the others to Logic-1.

All solutions were successfully tested on 28 March 2013.

or35:

public boolean or35(int n) {
	return n % 3 == 0 || n % 5 == 0;
}

more20:

public boolean more20(int n) {
	return n % 20 == 1 || n % 20 == 2;
}

old35:

public boolean old35(int n) {
	return n % 3 == 0 ^ n % 5 == 0;
}

specialEleven:

public boolean specialEleven(int n) {
	return n % 11 == 0 || n % 11 == 1;
}

less20:

public boolean less20(int n) {
	return (n + 1) % 20 == 0 || (n + 2) % 20 == 0;
}

fizzString:

public String fizzString(String str) {
	boolean fizz = str.charAt(0) == 'f';
	boolean buzz = str.charAt(str.length() - 1) == 'b';

	if (fizz && buzz) return "FizzBuzz";
	if (fizz) return "Fizz";
	if (buzz) return "Buzz";
	return str;
}

fizzString2:

public String fizzString2(int n) {
	boolean fizz = n % 3 == 0;
	boolean buzz = n % 5 == 0;

	if (fizz && buzz) return "FizzBuzz!";
	if (fizz) return "Fizz!";
	if (buzz) return "Buzz!";
	return n + "!";
}

CodingBat: Java. Recursion-2

Finally we’ve reached the last section of Coding Bat: Recursion-2. Those nine exercises are all very similar. Once you’ve figured out one you can probably solve the others immediately.

I’ll just walk you through the general strategy, using the first exercise as an example: The method “groupSum” takes three arguments. The first, “start”, is the index of an array of integers, the second is the array of integers in question, and the third, “target” is the target value. Now, “start” increases by one with each recursive call. If this value is greater than or equal to the length of the array, then the entire array has been processed. At this point, only the evaluation step has to be done, which consists of checking whether the target value is zero.

“Why zero?”, you may ask. If “target” equals zero, then it is possible to pick a group of integers from the array that sum up to the target value. The calculation is done by selecting each value of the array and in one case subtracting it from “target”, while in the other leaving “target” unchanged. Thus, all possible combinations will eventually be checked. Finally, the method returns “true” once one of the results is “true”, which is a property of short-circuit evaluation of logical disjunctions.

All solutions were successfully tested on 28 March 2013.

groupSum:

public boolean groupSum(int start, int[] nums, int target) {
	if (start >= nums.length) return target == 0;
	return groupSum(start + 1, nums, target - nums[start])
			|| groupSum(start + 1, nums, target);
}

groupSum6:

public boolean groupSum6(int start, int[] nums, int target) {
	if (start >= nums.length) return target == 0;
	if (nums[start] == 6)
		return groupSum6(start + 1, nums, target - nums[start]);
	return groupSum6(start + 1, nums, target - nums[start])
			|| groupSum6(start + 1, nums, target);
}

groupNoAdj:

public boolean groupNoAdj(int start, int[] nums, int target) {
	if (start >= nums.length) return target == 0;
	return groupNoAdj(start + 2, nums, target - nums[start])
			|| groupNoAdj(start + 1, nums, target);
}

groupSum5:

public boolean groupSum5(int start, int[] nums, int target) {
	if (start >= nums.length) return target == 0;
	if (nums[start] % 5 == 0) {
		if (start < nums.length - 1 && nums[start + 1] == 1)
			return groupSum5(start + 2, nums, target - nums[start]);
		return groupSum5(start + 1, nums, target - nums[start]);
	}
	return groupSum5(start + 1, nums, target - nums[start])
			|| groupSum5(start + 1, nums, target);
}

groupSumClump:

public boolean groupSumClump(int start, int[] nums, int target) {
	if (start >= nums.length) return target == 0;

	int sum = nums[start];
	int count = 1;
	for (int i = start + 1; i < nums.length; i++)
		if (nums[i] == nums[start]) {
			sum += nums[i];
			count++;
		}
	return groupSumClump(start + count, nums, target - sum)
			|| groupSumClump(start + count, nums, target);
}

splitArray:

public boolean splitArray(int[] nums) {
	return helper(0, nums, 0, 0);
}

private boolean helper(int start, int[] nums, int sum1, int sum2) {
	if (start >= nums.length) return sum1 == sum2;
	return helper(start + 1, nums, sum1 + nums[start], sum2)
			|| helper(start + 1, nums, sum1, sum2 + nums[start]);
}

splitOdd10:

public boolean splitOdd10(int[] nums) {
	return helper(0, nums, 0, 0);
}

private boolean helper(int start, int[] nums, int sum1, int sum2) {
	if (start >= nums.length)
		return sum1 % 10 == 0 && sum2 % 2 == 1 || sum1 % 2 == 1
				&& sum2 % 10 == 0;
	return helper(start + 1, nums, sum1 + nums[start], sum2)
			|| helper(start + 1, nums, sum1, sum2 + nums[start]);
}

split53:

public boolean split53(int[] nums) {
	return helper(0, nums, 0, 0);
}

private boolean helper(int start, int[] nums, int sum1, int sum2) {
	if (start >= nums.length) return sum1 == sum2;
	if (nums[start] % 5 == 0)
		return helper(start + 1, nums, sum1 + nums[start], sum2);
	if (nums[start] % 3 == 0)
		return helper(start + 1, nums, sum1, sum2 + nums[start]);

	return helper(start + 1, nums, sum1 + nums[start], sum2)
			|| helper(start + 1, nums, sum1, sum2 + nums[start]);
}

CodingBat: Java. Recursion-1, Part III

countPairs:

public int countPairs(String str) {
	if (str.length() < 3) return 0;
	if (str.charAt(0) == str.charAt(2))
		return 1 + countPairs(str.substring(1));
	return countPairs(str.substring(1));
}

countAbc:

public int countAbc(String str) {
	if (str.length() < 3) return 0;
	if (str.substring(0, 3).equals("abc") 
			|| str.substring(0, 3).equals("aba"))
		return 1 + countAbc(str.substring(1));
	return countAbc(str.substring(1));
}

count11:

public int count11(String str) {
	if (str.length() < 2) return 0;
	if (str.substring(0, 2).equals("11"))
		return 1 + count11(str.substring(2));
	return count11(str.substring(1));
}

stringClean:

public String stringClean(String str) {
	if (str.length() < 2) return str;
	if (str.charAt(0) == str.charAt(1))
		return stringClean(str.substring(1));
	return str.charAt(0) + stringClean(str.substring(1));
}

countHi2:

public int countHi2(String str) {
	if (str.length() < 2) return 0;
	if (str.substring(0, 2).equals("hi"))
		return 1 + countHi2(str.substring(2));
	if (str.charAt(0) == 'x' && str.length() >= 3) {
		if (str.substring(1, 3).equals("hi"))
			return countHi2(str.substring(3));
		return countHi2(str.substring(1));
	}
	return countHi2(str.substring(1));
}

parenBit:

public String parenBit(String str) {
	if (!str.substring(0, 1).equals("("))
		return parenBit(str.substring(1));
	return (str.substring(0, str.indexOf(")") + 1));
}

nestParen:

public boolean nestParen(String str) {
	if (str.equals("") || str.equals("()")) return true;
	if (str.charAt(0) == '(' && str.charAt(str.length() - 1) == ')')
		return nestParen(str.substring(1, str.length() - 1));
	return false;
}

strCount:

public int strCount(String str, String sub) {
	if (str.length() < sub.length()) return 0;
	if (str.substring(0, sub.length()).equals(sub))
		return 1 + strCount(str.substring(sub.length()), sub);
	return strCount(str.substring(1), sub);
}

strCopies:

public boolean strCopies(String str, String sub, int n) {
	if (str.length() < sub.length()) return (n <= 0);
	if (str.substring(0, sub.length()).equals(sub))
		return strCopies(str.substring(1), sub, n - 1);
	return strCopies(str.substring(1), sub, n);
}

strDist:

public int strDist(String str, String sub) {
	if (str.indexOf(sub) == -1) return 0;
	if (str.substring(0, sub.length()).equals(sub)
			&& str.substring(str.length() - sub.length())
			.equals(sub))
		return str.length();
	if (!str.substring(0, sub.length()).equals(sub))
		return strDist(str.substring(1), sub);
	// case: (!str.substring(str.length()-sub.length()).equals(sub))
	return strDist(str.substring(0, str.length() - 1), sub);
}