Java FAQ

From Juneday education
Jump to: navigation, search

FAQ for Java students/readers

Here's a list of frequently asked question and answers regarding Java

I am sure I have fixed an error but when I run/compile the program it is not fixed

  • Are you editing the correct file? Make sure you are not editing a copy of the file you are compiling
  • Did you save before you compiled?
  • Did you get any compilation errors? You may be running an old version of your program - it is still there if you get an error when compiling

The best way to make sure you are compiling the same file you have in your editor, is to open your editor from the command line. The argument to the editor should be exactly the same as the argument to the javac compiler.

The teachers always tell me to indent my code - can my editor help me with that?

If you are using Atom, you should do the following before showing your code to the teachers:

  • Mark all text (Windows: Ctrl-A, Mac OS: Cmd-A)
    • Edit...
      • Lines...
        • Auto-indent

This is actually a great way to spot unbalanced curly braces too. If the editor can't indent your code, you may have missed a curly brace (or added one too many).

Why do I get 'Could not find or load main class Example'? (alt. I can compile but I can't execute the class)

When trying to execute my program (actually a class) I get

$ java Example
Error: Could not find or load main class Example

Why???

This means that java can't find the class Example. The class name (including package) could be misspelled or you're in the wrong directory when trying to execute the program. Read more about this at: Java Tools.

Check-list:

  • Does your class have a package declaration?
    • If the package is x.y.z then you must compile from the directory where also the x directory is
    • Don't cd down to the same directory as a java file if the file declares a package!
  • Did you spell the class correctly?
    • Java is case sensitive - MyClass is not the same as Myclass
  • Use ls to verify that the class file was created
    • You can use TAB completion to verify that you are in the correct place
  • Did you compile?

Does my program get bigger if I import too many classes or packages?

No.

If my program doesn't get any bigger if I import too much, why is that?

Import is just a help for the compiler (and the programmer). It allows you to say ArrayList in stead of java.util.ArrayList in your code if you import java.util.* or java.util.ArrayList. And it helps the compiler to understand what the heck you mean by saying "ArrayList". If you don't import java.util.ArrayList, and you don't have a class in scope (like in the same package as your class) named ArrayList, the compiler will complain:

FancyClass.java:4: error: cannot find symbol
  ArrayList list;
  ^
  symbol:   class ArrayList
  location: class Import
1 error

If you, on the other hand, import java.util.ArrayList, the compiler will replace all occurrencies of ArrayList with java.util.ArrayList in the resulting class file.

This can be verified by decompiling the class file using javap:

$ javap -c Import
Compiled from "FancyClass.java"
public class FancyClass {
  java.util.ArrayList list;

  public Import();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
}

You see? The variable list now has type java.util.ArrayList inside the class file.

Why doesn't my loop (or if statement) work?

Why doesn't my loop work. The thing I've written in the loop is executed only once:

for (int i=0; i<size; i++); {
  // some code
}

Note: the problem is the same for an if statement (if(expr); { // some code }) and a while statement (while(expr); { // some code }.

The code above is correct, at least when it comes to syntax. The code executed per loop, unless there's a block, is the code between the last parenthesis and the next semi colon - in this nothing at all. If we rewrite the code and add line numbers slightly it is easier to explain.

1 for (int i=0; i<size; i++)
2   ; 
3 {
4   // some code
5 }

Line 1 and 2 are part of the loop. Line 3-5 make up a block, which in turn is not related to the for statement.

Assuming you want to execute the //some code part as the body of the loop, you need to rewrite the code to the following (removing the semicolon):

for (int i=0; i<size; i++) {
  // some code
}

What's a for each loop?

Check out: for-each-loop

Why shouldn't I use == to check if two objects are equal in Java?

Let's start this discussion with some code:

  String s1 = new String ("Hi there");
  String s2 = "Hi";
  String s3 = s1;
  String s4 = s2 + " there";

In the code above we create two objects (via new String ("Hi there");, "Hi"; and " there";) and four reference variables (s1, s2, s3 and s4).

Let's start by asking whether s1 and s2 are the same. They're not. They're two different objects so clearly they're not the same. But if we're really interested in checking if s1 and s2 the same... well, then we simply use the == operator like this if (s1==s2) { ...... some code }. So if we check if s1 and s3 are the same the answer would be yes even though they are different reference variable. They are the same since they refer to the same object. Compare this to looking at two papers with an address on each of them. It is two pieces of paper but we will consider the address to be the same if they refer to the same house/apartment.

Are they equal? What do we mean with equal? Equality usually refers to comparing two objects with respect to some interesting attributes. This could be that two persons are considered equal if the names are the same. Comparing (checking equality) of two Strings is simply done by checking if the text in the two objects are the same. The code to manage this is something the people who developed the String class wrote. We check equality by invoking the method equal on one object and pass the other as an argument. Let's do some comparisons:

  s1.equals(s2) // will be evaluated to false since s1 refers to an object whose value is "Hi there" and s2 refers to an object whose value is "Hi";
  s4.equals(s1) // will be evaluated to true since s4 refers to an object whose value is "Hi there" and s1 also refers to an object whose value also is "Hi there";

In conclusion, the == operator, when applied to two references, checks whether the two references refer to one and the same object (in the JVM's heap memory area). This is a rather technical test, and not one we as programmers very often care about. Objects typically model some entity in the problem domain of our program, like a File, a Customer, an Order or a bank Account for instance. How these model objects are stored in the memory is not as interesting as the question "Are the objects these two variables refer to equivalent to each other?" If the variables happen to refer to exacly the same objet, then it is fair to cosider the answer to thar question as true.

What various classes consider to be equality (via the equals method), varies and is documented. For some examples, we encourage you to read the documentation for the equals method for some API classes, e.g. java.lang.String, java.lang.Integer, java.io.File and java.util.ArrayList.

Note that there are som conventions for writing an equals method, like also providing a hashCode() method, involving the same instance variables as the equals test.

Most classes that are Comparable, return 0 from the compareTo method for objects that are equal according to the equals method. Those that don't should document that and explain why.

Note:' check the constants pool in Java: Constant confusion

Note: we're using the variable names s1, s2 etc even though we usually complain about variable names such as these..... well, we're only humans after all.

What's this void keyword?

The keyword void is used when declaring (writing) a method which doesn't return any value. Many methods are declared with a return type, which specifies what type of value the method returns. But the void keyword instead specifies that the method in question doesn't return anything.

Look at the java.util.ArrayList class in the API documentation. Some examples of instance methods for an ArrayList are (arguments to the methods are omitted for brevity):

  • add() - adds an element to the list - returns nothing
  • clear() - deletes all elements in the list so that the list becomes empty - returns nothing
  • sort() - sorts a list using some comparator object which knows how to compare two elements - returns nothing

Those methods have in common the fact that they just do something and don't return any value at all.

The meaning of void is "Don't expect me to give you any value back, I'm just doing my job, and when I'm done, I'm done. You'll hear nothing from me."

So, you cannot have the return statement in a method which is declared void? Well, actually you can. But the return statement of a void method doesn't include a value to return. It looks like this:

return;

Looks pretty lonely and empty, doesn't it? Well, it's empty because it simply leaves the method and returns the execution of the code back to the point where the method was called. It doesn't include a value, because a void method doesn't return any value. It can return the execution back to the point where the method was called, but it doesn't include any value as it "returns".

Many methods declared void don't have any return statements. Instead they just do some tasks, and when the instructions in the method reaches the last line of the method body, the execution is automatically returned to the point where the method was called - there is nothing more to be done by the method so it implicitly returns the execution back to the point where the method was called.

The only reason to include an empty return statement in a void method, is when you want to leave the method early (still without sending any value along with the return of the execution).

Since void methods never return any value, they cannot be used as an expression or as a part of an expression.

You cannot, for instance, do like this:

Object o = System.out.println("Hey, baberiba"); // won't compile!!!

This is because println() (in class PrintStream) is declared void, so calling the method doesn't return a value (and thus doesn't even have a type!). So you cannot use a call to a void method as an expression in an assignment expression (or anywhere where you need an expresssion (something with a value and a type)).

curl downloads a JAR-file but it is saved as an HTML page

In some versions of curl (typically on older versions of MacOS), curl downloads a file (e.g. a zip file or a jar file) but treats it as if it were an HTML page (which is wrong). In such cases, you can try the following flags to curl:

$ curl -k -LJO http://some-link-to/some-file.jar

Refer to the curl manual on your system for an explanation. In short:

  • -L tells curl to follow moved files (caring about the Location: header in the HTTP response)
  • -J tells curl to use the Content-Disposition file name sent by the server
  • -O tells curl to use the file name as it is given as part of the URL (the way wget does it)
  • -k tells curl to accept to download over HTTPS without checking the certificates as explained here

My Java program/Servlet produces JSON but it uses comma as the decimal point character

Valid JSON uses a dot for floating point numbers decimal separator. In some Locales, Java will produce a real number with an comma instead of a dot when converting a double or a float to a String.

There are a few ways around this:

  • Call Locale.setDefault(Locale.ENGLISH); early in your code
  • Use a NumberFormat (use google to see how that works) to format the string in an English locale
  • Use a library for producing JSON, e.g. org.json for the production of JSON

The parts of the for loop - do we have to use ++ or -- ?

A lot of programming is about using idioms. An idiom is a way to write code which is so common, that almost "everyone" writes it in the same way. Since it is so common, we recommend that you stick to idioms, if for no other reason, because it helps making friends and it helps avoiding criticisms from future colleagues (and teachers).

The way we write a for loop in order to do something a known number of times, is an example of an idiom.

To loop, for instance five times, the idiom is to write like this:

for (int i = 0; i < 5; i++) {
  // do something
}
This is code which you shouldn't write!

Now, a question we have got is "So, we have an initialization like int i = 0; and then a test like i < 5 and then an expression which changes the value of i at the end of the iteration. But can we have an expression like "i = 7" at the end of the for loop so that it reads:

for (int i = 0; i < 5; i = 7) {
  // do something
}

The answer is:

Well, we are allowed to do that. But it is pointless. The whole point of the last part of the for loop header is to make sure that the loop terminates eventually. Again, the parts of the for loop header are:

  • declaration and initialization of the loop variable (typically i)
  • test of whether to enter the loop block or not - must be a boolean expression (something that is true or false).
  • change of the loop variable (without this, the loop will not terminate) - this must be a statement, not an expression

You cannot use an expression which is not a statement. Why? Because the last part of the loop header is a statement to be executed at the end of the iteration. An expression like 99 or even i + 99 is not a statement. The compiler will not accept it. If the compiler would accept an expression like i + 99, it would mean the same as the following while loop:

for (int i = 0; i < 5; i + 99) { // won't compile!
  // do something
}

int i = 0;
while (i < 5) {
  // do something
  i + 99; // compilation error - not a statement.
}

However, if you put "just any statement" in the last place of the for loop header, you might not change the loop variable! Then the loop may not terminate at all. So it is unwise to put something other than a change of the loop variable there. Which is also why you should stick to idioms, because they work and are predictable. That's why they became idioms!

So don't do this, even if it compiles: for (int i = 0; i < 5; i = 3) { ;; }. The fact that something compiles is not a proof that it is something which makes sense!

You can compile programs that follow the rules of Java syntax, but which are faulty programs (programs which do the wrong thing, or malfunction in various ways).

I always confuse Comparator<T> with Comparable<T> - what's the difference?

It's all in the name. Comparable<T> is an adjective. It's an interface for enhancing your own class to become something more than it is, to become also a class for objects that are comparable with each other. An object of a Comparable class, can be asked to compare itself to and object of the same class, and return an int value with the result (where a negative value means that the object comes before the other object, a value of 0 means that they are equal with regards to order, and a positive value means that the object comes after the other object). The method the Comparable<T> interface guarantees that implementing classes have is thus called compareTo(T other).

One feature of a class being enhanced to also be Comparable<T>, is that collections of instances (references to instances, really) can be sorted with e.g. java.util.Collections.sort(...). Why? Because the only requirement from the sort method, for it to be able to sort a collection, is that all the elements are comparable to each other.

In order to sort e.g. a list, you need to compare the elements to each other in order to decide between two elements, which should come first? Comparable objects are helpful to the sorter. The sorter can ask an element "please, compare(yourself)To(someOtherElement)".

Comparator<T> on the other hand, is a noun which sounds almost like a work description. Just like "Terminator", "Operator", "Investigator", "Splitterator", ...

So, a class implementing Comparator<T> is for creating objects with a job, to compare stuff. In more detail, the Comparator<T> interface guarantees that a Comparator<T> object has the compare(T a, T b) method. For instance, a Comparator<String> can compare(String a, String b) and return an int value with the same semantics as above, where a negative value means "a comes before b", zero means "a and b are equal when it comes to ordering", and a positive value means "a comes after b".

Therefore, a Comparator<T> isn't modifying any existing classes at all. It is there for creating new classes for objects that have one job, to compare two Ts.

This is also good news! Now, a second version of java.util.Collections.sort(...), that takes a collection and a Comparator, can sort anything. Why? Because with the help of a Comparator, it can ask the Comparator to compare pairs of elements and thus find out the order of the sorted collections.

For a longer explanation and some examples, see Comparable_vs_Comparator.