I would say that the two things you cite as "an aide to comprehensibility" actually detract from the comprehensibility. Non-autoboxing in particular is pretty annoying: now that Java has thankfully gotten rid of that terrible implementation detail, why foist it upon new learners anyway?
In addition, while tutoring an important part of the process would be to communicate language conventions---such as not including such extra spaces, or the placement of braces. I have actually seen the newline-for-each-brace style referred to as "Java style" before, so take that into consideration.
I think the best tip I can give you for preparing useful code examples, is this: have the person you're tutoring write some code him self. I think that will be the most instructive code you can give him. It has several advantages:
- You don't waste time teaching him things he already does right.
- You have good examples of things he does wrong, in a context that he understands.
- He has already learnt things by coding the assignment you have given him.
You can give assignments that teach him various valuable topics, such as:
- Inheritance: let him code some simple inheritance hierarchy, such as animals, or shapes. Make sure to put some gotchas in the assignment.
- Algorithms: have him implement some well-known algorithm.
- APIs: let him re-implement some simplified variation of a real feature that is typical for the applications in your company. Usually that will imply some real-world coding is to be done, and usually some API calls are necessary for that.
After he has completed each assignment, you have some perfect example code that you can use to teach your student how to improve his coding style!
Also, it might help to find a couple of colleagues to implement your assignments first, so that you know where the pitfalls of each assignment will be. That way, you could adjust them, if necessary, before handing them over to your student.
Keeping my old answer to the previous version of this question, for historical purposes, and also so that the comments will keep making some sense:
When I'm tutoring Java, I discourage people to use break
. I forbid them to use labels. (They're goto
s in disguise.)
In my opinion, labels and (to a lesser extent) break
s encourage bad coding style, and can usually be rewritten with a while
or a for
loop. Often your code is much clearer because of it.
I'd rewrite your inner loop as follows:
int index = 0;
int finalIndex = (int)Math.sqrt(value);
while (isPrime && index <= finalIndex) {
Integer prime = primes.get(index);
if (value % prime == 0) {
isPrime = false;
}
index++;
}
I don't totally agree with your use of spacing: your pupils might become used to seeing code like that, and might be confused when they're let loose on 'real' code.
I do agree with your point on autoboxing, though. I would use int
s in production code, but for educational purposes it might indeed be useful to spell things out explicitly. However, there's still some autoboxing voodoo going on in your example code, where you calculate value % prime
:).
Use capacity on the arraylist to avoid frequent resizing.
Use Integer.valueOf() instead of newing up them.
Start the loop from 5 and step 2 at a time with value.
What is the experience level of your students?
Perform Source Code Reviews
If you are looking to help instill good programming practices in your students, I would recommend finding the source code for problems that have been already solved by students. There are a number of places that would likely be happy to provide you with content, including:
- High schools
- Community colleges
- Hobbyists
- The Internet
Once you receive (an anonymous archive of) the students' work, sit down for an evening and perform a code review. Here is an actual example from a high school student:
//accepts full name and breaks it into first and last names
public Name (String name) {
int index = 0; //index of full name
//find the space between first name and last name
while (true) {
if (name.charAt(index) == ' ') {
break;
}//if
index++;
}//while
//set first name and last name
first = name.substring(0, index);
last = name.substring(index + 1, name.length());
//encrypt the full name
encrypt();
}//constructor
//set methods
public void setFirst (String _first) {
first = _first;
//encrypt the full name
encrypt();
}//setFirst
This provides much learning fodder. Here are the major points (without getting too technical or overly picky) that I would make:
- The documentation does not conform to Javadoc standards. Javadoc is a standard way of writing source code comments that can be transformed into a useful series of web pages.
- Do not comment the closing brace, especially when the opening brace is only a few lines away. It is a waste of development and compile time, while it offers no help to experienced developers, and serves only to clutter code readability.
- An accessor for setFirst is provided and should be used throughout the entire class. This is the rule of Don't Repeat Yourself. When a version of Java is released that is more like Smalltalk in the way variables are treated (i.e., the accessor is hidden yet always available), this will not be an issue.
- Eliminate the duplicate calls to
encrypt()
(which happens naturally by reusing the set accessor). - What happens when only a single name is passed (with no space) via the constructor, or even a null value? (Discuss defensive programming, possibly assertions.)
- The
while( true )
loop should useString.indexOf(...)
. - Bonus marks for those who use
String.split(...)
and a regular expression to extract the first and last names. - Comments should tell the reader why the code was written, not what it does.
Then show the rewritten code:
/**
* Accepts full name and breaks it into first and last names.
*
* @param name A full name, including first and last name, with a single
* space separator.
*/
public Name( String name ) {
if( name != null ) {
// Find the space that separates the first and last name.
int index = name.indexOf( ' ' );
// Extract and set the first and last names from the name.
if( index > 1 ) {
setFirst( name.substring( 0, index ) );
setLast( name.substring( index + 1 ) );
}
else {
// No space: only a single name was provided, or no text at all.
setFirst( name );
setLast( "" );
}
}
}
/**
* Changes the first name for this instance, then reencrypts the cipher
* text using the given first name (the current last name is reused).
*
* @param first The new first name for this instance.
*/
public void setFirst( String first ) {
this.first = first;
encrypt();
}
Some closing thoughts:
- From just two routines, written by budding programmers, there are many tips to be learned.
- Consider returning the reviewed code.
- Be sure to provide logical reasons for critiques. (Saying, "Don't comment closing braces" is relatively useless -- supporting the argument adds value.)
Show them some common algorithm implementations... BFS, DFS, Djikstras, A*, Mergesort, Quicksort, etc.
I'd say code that has a wide range of uses is best. wide as in, not code that is "this counts to 100 and prints the numbers that are modulo 3 and 5 and is totally useless." but code that solves a real problem. Once you say "A* can make a path from start to finish" then you've got their attention because they know it's useful.
The sorts and the Breadth/Depth first searches are good because they can be short and comprehended easily and have very clear implementations that can teach some good coding practices. The sorts are especially good examples of recursion.