Coding differences

C++ and Java look very similar at the low level, with identical syntax for many expressions and control structures. Unfortunately there are also some differences which can catch you out.

Integer sizes

In C++, the size of an int type is machine/compiler dependent. The main reason for this is that it allows the compiler to use an integer size which matches the processor architecture (eg an int is 32 bits on a 32 bit processor, 64 bits on a 64 bit processor) – this can be more efficient. Similarly short and long sizes are machine dependent, subject to certain constraints around the relative sizes of the different types.

However, this can make it very difficult to write code which works corectly across multiple platforms and multiple compilers. Typically this is solved by using typedefs to define integers of known size (eg int32).

Java runs within a virtual machine, so there is very little advantage in matching integer sizes to the processor architecture. In addition, Java is intended to be platform independent. It should be no surprise that Java defines the exact size of its integer types:

  • byte is an 8 bit signed int
  • short is a 16 bit signed int
  • int is a 32 bit signed int
  • long is a 64 bit signed int

You can write Java code secure in the knowledge that wherever it runs, and int will be exaclty 32 bits long.

Unsigned integers

Java does not support unsigned values (with the exception of the char type described later, but that type isn't intended for arithmetic).

It is not clear whether this was a delibrate design decision, or simply something which never got implemented.

Unfortunately, unsigned integers tend to occur in binary formats, such as image files or sound files. As a C++ programmer, if you had to read in a two byte value from a file, representing an integer between 0 and 65535, you would probably use an unsigned short (especially if you had a large array of value to read in). In Java, you must read in those two bytes and create a 32 but int, using twice as much memory. This annoys many C++ programmers, but that's the way it is.

Floating point arithmetic

Java defines two floating point types:

  • float based on the IEEE-745 specification 32 bit format
  • double based on the IEEE-745 specification 64 bit format

double is precise to about 15 decimal places, float is precise to around 7 decimal places (but float calculations are usually faster than double). C++ also provides similar float and double types, but the exact specification is hardware and compiler dependent.

For a particular floating point calculation you should (in theory) get the same answer whichever Java compiler you use. For C++ the answer could vary between compilers and depending on the hardware. This is unlikely to affect most code (unless it is badly written). The fact is, Java and C++ will both get the answer very slightly wrong when performing floating point calculations, but Java will give you the same wrong answer across different platforms, C++ might give you a different wrong answer from one platform to the next. In either case the errors are very small.

A more important factor is that IEEE-745 has ways to represent numbers such as infinity and NaN (not a number). This means that a calculation such as 1/0 does not throw a runtime exception, it merely returns the result “infinity”. That can be good or bad depending on the type of program you are writing. If you want to handle infinite values gracefully, the Java model is good. If you need to handle division by zero as a serious runtime error, then with Java you will need to calculation results at key times.

Boolean values

In Java, boolean is a separate type, with possible values true or false.

An integer value is not converted to a boolean based on its value, you must test the value of an integer variable explicitly:

if (i!=0)
  //i is non-zero

A null object reference (equivalent to a null pointer in C++) has a value null , rather than 0:

if (p!=null)
  //p is not a null reference

Code such as:

if (i)
  //illegal

will cause a compiler error in Java, you cannot do a logical test on an integer value.

Characters and Strings

Java uses unicode strings. Unicode characters are 16 bit characters.

The primitive type char is a 16 bit unsigned quantity which holds a Unicode character. A Java char is equivalent to a C++ _wchar. Java has no equivalent to a C++ char (the Java byte is an 8 bit integer, but it is a signed quantity).

C++ typically uses null terminated char arrays to represent strings. This is quite a low level method, and potentially quite dangerous, but it can also be very efficient because in C++ a char array is just a memory buffer whuch can be accessed via a pointer.

The alternative in C++ is to use some kind of String class (eg STL string, or the old Windows MFC CString). This is higher level, safer, but less efficient.

In Java, arrays of chars are rarely used to represent strings. A Java array is an object and its elements cannot be accessed directly via pointers. Storing a string as an array of chars gives no great efficiency, it just makes life more complicated for no real benefit.

Instead, character strings are represented by String objects. Although String is a class not a primative type, strong support for String is built in to Java at a deep level. For example, every object has a toString() method which converts the objects value to a String. Leave char* behind when you start Java.

One thing to be aware of is that String is an immutable type in Java. Once a String has been created, its value cannot be changed. For example, the following code has no effect:

String a = "abc";
String d = "def";
a.concat(d);

The concat() function concatenates a (“abc”) with d (“def”), but it doesn't change a, it can't because a is a reference to a String whose value can never change. What concat() does is return a new string “abcdef”. You need:

String a = "abc";
String d = "def";
a = a.concat(d); //Now it works, but remember that a is no longer the same object

Operators

C++ allows operators to be overloaded for user defined classes. For example, the shift left and shift right operators << and >> are often overloaded for stream classes to allow code such as

ostream << std::string("i = ") << i << endl;

This can be very powerful, particularly in cases where the existing operators have a natural and obvious meaning in a new scenario (for example, in a library which supports complex numbers – it is nice to be able to use the + operator to add them). But this feature can also be abused, and if operands are overloaded randomly it can result is code which is very difficult to read.

Java does not allow operator overloads. That isn't completely true, it defines two specific overloads of + and += for the String class – but that is all. There are no programmer defined overloads. This avoids the sort of bad code mentioned above, but it also means that a complex number library written in Java must use functions to implement basic things like add and multiply.

Type conversion

C++ permits automatic widening type conversions, for example if you assign a char value to an int variable, or a float value to a double variable, the data will be converted automatically.

C++ also permits automatic narrowing type conversions, for example you can assign an int value to an char variable, or a double value to a float variable. This will often result in a compiler warning, because data may be lost, but the code will compile and run.

Java only permits widening conversions. A narrowing conversion will give a compiler error unless and explicit cast is used.

const

If a C++ variable is declared as const, its value cannot be changed after the initial declaration. In Java the final keyword performs a similar function:

final int five = 5; //five will always be 5

If a C++ pointer is declared const, it can never be reassigned to point to something else. In Java, a final reference has similar characteristics:

final MyObject obj = new MyObject(); //obj will never reference a different object

In C++, you can also declare a pointer to a const value, meaning that the pointer cannot be used to change the object it points to. There is no equivalent functionality in Java.

C++ allows you to declare a class member function as const, which guarantees that calling the method will not alter the state of the object. Again, Java has no equivalent.

Note that final is used in other places in the Java language.

goto

C++ allows goto statements, although you don't see them used very often. It is difficult to think of a case where breaking the normal structure of a C++ function is a good idea.

Java does not allow goto. It does have labelled break and continue statements.

In Java, you cannot place labels at arbitrary points in the code, but you can place a label immediately before a switch, for, while or do block. This labels the block.

A normal break statement breaks the code out of the inner-most switch, for, while or do block. A break statement with a label breaks the code out of the labelled block. Labelled continue statements work in a similar way.

This is more structured than goto, but it isn't a language feature I would tend to use myself. Any Java reference will cover this in more detail.