There are at least two parts to teaching naming. The first is to have a good standard that the students know and understand. This can be provided in a checklist. But the more important aspect is to always demonstrate good naming in all examples that you use and in all quizzes and exams that you give them; even for very simple exercises.
The Naming Standard
The goal of a naming standard is to make programs easy to understand and to reason about. There are a number of possibilities here and you can and should develop your own. Here is one I use:
Intention Revealing Names: A name should always have semantic content related to the problem being solved. Don't use abstract names like $x$ and $y$ . Use semantic names like $size$ and $figure$ .
Names from the problem space, not the solution space. If you are totaling up some array, don't use $total$, use $sumOfAges$ , if that is a concept in the problem space. This can permit each statement in the program to read like a description of some thing or action in the language of the problem being solved.
In Java, use singular nouns for class names. Use verbs and verb phrases for the names of mutator methods, describing what the method does. Use nouns and noun phrases for accessor methods, describing what the method returns. Predicates can usefully start with $is$ , as in $isRunning$ . An implication is that methods should not be simultaneously an accessor and a mutator. There are other reasons why access-mutators are a bad idea in any case.
One name per concept. The same concept will occur in a program in several ways. A class name $Ramp$ describes how to construct a ramp. A variable name can be $ramp$ . An accessor method in some class might be $ramp()$ . A field in some class might be $ramp$ . Java does a good job of keeping these distinct, thought you sometimes need to (and should) write $this.ramp$ . Since the language can distinguish them the programmer doesn't need to keep track of an entire set of names for the one concept. And, concept is from the problem space, not the solution space. This helps the student programmer imagine that their program is a model of some "real" world scenario, not just a set of notations providing a result. (See Miller's Rule, below)
Avoid names that emphasize the implementation of a class. Names should emphasize the structure and evolution of a concept, not the fields of a class and their modifications. Unfortunately names like $getSize()$ and $setSize()$ emphasize that there is likely a field named $size$ . (See below for more).
Don't abbreviate names. Ever. Always spell out your names and never abbreviate them. You will, over a lifetime of programming spend more time looking back for the definition of something you abbreviated to use it consistently than you will just typing it out in the first place. A few exceptions to this rule can be tolerated for standard things, but in general, you waste time abbreviating. The thing that makes programming hard isn't typing. It is understanding. Modern IDEs can help you with word completion, of course.
Note that good naming will usually mean that you need fewer (if any) inline comments. Providing java doc to document the intent and usage of classes and methods is nearly always sufficient.
Also note that I haven't mentioned the capitalization preferences in my standard, though I do observe and expect them: Bumpy case for most things. All CAPS for constants, etc. I'm more concerned with the clarity and instant understandability of the names in the above.
Teaching the Standard
For students to easily and naturally adopt the standard there are a few tricks that don't involve forcing students. The first rule is to be consistent yourself when you show them examples and when you test them. Even when teaching the lowest level concepts, you can have some metaphor in mind that guides your naming and makes the "problem space" rule natural. For example if you are teaching the a loop to sum an array, it is common to use an example like:
int x= 0;
for(int i = 0; i < n; ++i){
x += y[i];
}
But this example has no semantic context. What is $x$ ? How is it related to $y$ ? How is $n$ related to $y$ . For experienced programmers this isn't an issue and if they already have good naming practice, an abstract example like this works fine, but it doesn't emphasize the larger lesson that naming is always important. You can just as well show them:
int totalPrice = 0;
for(int i = 0; i < priceCount; ++i){
totalPrice += allPrices[i];
}
or, for the absolute purist:
int totalPrice = 0;
for(int index = 0; index < priceCount; ++ index){
totalPrice += allPrices[index];
}
The structure is the same, but the relationship between the three variables is much clearer now. (Yes, $index$ is from the solution space, I realize.)
If you are developing an example in real time (black/white board...) you can have a mental metaphor before you start. It can even be fun to ask for suggestions from the students for a "problem space" in which you will create names (or even ask for them).
This is based, of course, on the idea that students will naturally emulate what you do. If you normally and naturally just use abstract names for things, then they will be lulled into thinking that it is ok to do so. So try, with beginners, to always give them some semantic context in which to think about problems.
The above goes for quizzes and exams as well. Give them (only) problems, even quite small problems, in which the names at least potentially mean something in a supposed problems space.
In doing OO programming the understanding of a program can be enhanced by using good variable names for objects. If you have a declaration
Particle x = ...
then a half a page later, when you see $x$ again, you want to know what can be done with it. What messages does it accept? So, say the following, instead:
Particle particle = ...
Now it is clearer what the variable refers to and so the student requires a much simpler mapping process to proceed.
In evaluating student work it is a good practice to note their poor naming when it occurs and ask them to improve it. The compiler doesn't care, of course, but you do, as you need to understand what they have written. Modern Java IDEs are good about changing names using contextual (not just textual) replacement. You can change the name of a variable from $x$ to $size$ without changing every "x" in the program as a word processor would do.
Miller's Rule of Seven (plus or minus two)
In a famous Paper in Psychology, George Miller suggests that the human mind is capable of simultaneously juggling only about seven concepts. Many of the rules of the naming convention above are informed by this rule. For example, one name per concept reduces the load of detail that the programmer much keep track of while thinking higher level thoughts.
Likewise naming from the problem space, rather than the solution space is helpful because the "world out there" is, itself, logically consistent, so using naming and concepts from there (or from a suitable consistent metaphor) keeps the number of concepts more reasonable.
Moreover, the very idea that our programs build higher level abstractions is informed by Miller's rule, since the abstractions we build are normally built on a lot of detail, that we abstract away in our classes and functions. Once we have built a class, we can think of the objects as a simple thing (the abstraction) rather than the detail on which they depend. Thus our limited capacity for detail is overcome by thinking about higher level things, upon which we build still higher level abstractions.
get-set considered harmful
Many teachers seem to use the JavaBean naming convention when teaching Java to novices. Students adopt this, thinking that it is a Java Standard. It is not.
JavaBeans, from Oracle, introduced a Java method naming "convention" that lets the system infer some things about objects. These are the "getter" and "setter" methods, normally used to get and set values of fields. However, I find that this "convention" is not conducive to teaching students good OO programming habits since the names themselves indicate to the student (as they do to the Bean system) that there is a field that is being retrieved or set. This is all about the implementation of the class, not the concept that it represents. It leads students to think in terms of implementation too early.
My preference in teaching students how to write a class is to ignore the implementation at the beginning and to think about the concept. One good way to do this is to develop a formal interface for the class using names from the problem space. What is is that an object should be able to do? What should it be able to tell me? Look at some potential code that refers to this interface to be sure that what you have is likely complete and sensible. Then, and only then, write the class. You don't need "getters" and "setters" since the fields are hidden and only used for implementation, rather than being exposed (even safely) to clients. I use the words "accessor" for getting information (not fields) and "mutator" for updating the state of the object. And, for other reasons, prefer mutators, using the "Tell, Don't Ask" rule of OO software that is discussed elsewhere.
Programs should read like poetry.