Java - First Impressions for a C++ Programmer

Steven Zeil

Last modified: Nov 29, 2019
Contents:

Moving from C++ to Java

1 Program Structure

Hello Java

The traditional starting point:

public class HelloWorld {

  public static void main (String[] argv)
  {
    System.out.println ("Hello, World!");
  }
}


Class Syntax

C++

class MailingList {
private:
   struct Node {
      Contact data;
      Node* next;
   };
   Node* first;
public:
   MailingList() 
   {
      first = nullptr;
   }
     ⋮
};

Java

public class MailingList {
   private class Node {
      Contact data;
      Node next;
   }
   private Node first;
   public MailingList() 
   {
      first = null;
   }
     ⋮
}


Packages

A Java package is like a C++ namespace:

C++

namespace myUtilities {
  class Randomizer {
    ⋮
  };
};

Java

package myUtilities;
class Randomizer {
   ⋮
}

C++ Java
myUtilities::Randomizer r; myUtilities.Randomizer r;

We Can Have Short-Cuts

C++

using myUtilities::Randomizer
   ⋮
Randomizer r;

Java

import myUtilities.Randomizer;
   ⋮
Randomizer r;


We Can Have Shorter Short-Cuts

C++

using namespace myUtilities;
   ⋮
Randomizer r;

Java

import myUtilities.*;
   ⋮
Randomizer r;


Cultural Difference

2 Program Structure == File Structure

2.1 Class == File


Classes are not Split into Two Files

2.2 Package == Directory

2.3 Packaging and Compiling

Suppose we are building a Java project in ~/jproject.

If we have a class

public class HelloWorld {

  public static void main (String[] argv)
  {
    System.out.println ("Hello, World!");
  }
}


Packaging and Compiling 2

Suppose we are building a Java project in ~/jproject.

If we have a class

package Foo;

public class HelloWorld {

  public static void main (String[] argv)
  {
    System.out.println ("Hello, World!");
  }
}

Important: Notice that we compile from the project’s “base directory”, not from the directory that contains the actual .java files.


Packaging and Compiling 3

Suppose we are building a Java project in ~/jproject.

If we have a class

package Foo.Bar;

public class HelloWorld {

  public static void main (String[] argv)
  {
    System.out.println ("Hello, World!");
  }
}


Is Java Just Trying to Be Annoying?

Actually, no.

3 Swimming in Pointers

Primitives are Familiar

int x = 2;
int y = x;
++x;
System.out.println ("x=" + x + " y=" + y);

prints “x=3 y=2”

3.1 Everything Else is a Pointer!!

void foo(java.awt.Point p) {
  p.x = 1;
  java.awt.Point w = p;
  w.x = 2;
  System.out.println ("p.x=" + p.x + " w.x=" + w.x);
}

prints “p.x=2 w.x=2”

  java.awt.Point w = p;

causes w to point to the same value that p does.

3.2 Lots of Allocation

Because all new class variables are really pointers, all new class values have to be created on the heap:

C++

Point p (1,2);

Java

Point p = new Point(1,2);

Arrays of Pointers

C++ programmers need to be particularly careful dealing with arrays:

C++

int a[10];
Point* p = new Point[10];

Java

int[] b = new int[10];
Point[] q = new Point[10];
for (int i = 0; i < q.length; ++i)
   q[i] = new Point();

Without the loop, q would actually be an array of null pointers.

3.3 Because there are so many pointers

3.4 There are no “delete”s in Java!

Java features automatic garbage collection.

3.4.1 Garbage Example

Consider the following code:

C++

void printSorted(const vector<int>& v)
{
   int* array = new int[v.size()];
   for (int i = 0; i < v.size(); ++i)
       array[i] = v[i];
   sort (array, array+v.size());
   for (int i = 0; i < v.size(); ++i)
       cout << array[i] << endl;
}

Java

void printSorted(ArrayList<int> v)
{
   int[] array = new int[v.size()];
   for (int i = 0; i < v.size(); ++i)
       array[i] = v.get(i);
   Arrays.sort (array);
   for (int i = 0; i < v.size(); ++i)
       System.out.println("" + array[i]);
}

(If you are interested in how garbage collection works, you can read about it here.)

3.5 Pointers and Equality

Beware of ==


equals

To compare objects to see if they have the same contents, use the equals function:

Point p = new Point(1,2);
Point q = new Point(1,2);
if (p.equals(q))
   System.out.println ("That's better.");
else
   System.out.println ("Pay no attention...");

4 Exceptions

An exception is a run-time error signal.


Playing Catch

Try compiling and (if successful), running each of the following:

OpenFile1.java
import java.io.*;

/**
   Demo of a program that may throw exceptions.
   @param argv The name of a file to open for input
*/
public class OpenFile1 {

  /**
     Attempt to open a file
  */
  static void openFile (String fileName) {
	FileReader reader = new FileReader(fileName);
  }
  
  /**
     Attempt to open the file whose name is given in
     the first command line parmaeter
  */
  public static void main (String[] argv) {
	String fileName = argv[1];
	openFile (fileName);
  }
}
OpenFile2.java
import java.io.*;

/**
   Demo of a program that may throw exceptions.
   @param argv The name of a file to open for input
*/
public class OpenFile2 {
  
  /**
     Attempt to open a file
  */
  static void openFile (String fileName)
	throws java.io.FileNotFoundException
  {
	FileReader reader = new FileReader(fileName);
  }
  
  /**
     Attempt to open the file whose name is given in
     the first command line parmaeter
  */
  public static void main (String[] argv) {
	String fileName = argv[0];
	openFile (fileName);
  }
}
OpenFile3.java
import java.io.*;

/**
   Demo of a program that may throw exceptions.
   @param argv The name of a file to open for input
*/
public class OpenFile3 {
  
  /**
     Attempt to open a file
  */
  static void openFile (String fileName)
	throws java.io.FileNotFoundException
  {
	FileReader reader = new FileReader(fileName);
  }
  
  /**
     Attempt to open the file whose name is given in
     the first command line parmaeter
  */
  public static void main (String[] argv) {
      try {
	  openFile (argv[0]);
      }
      catch (java.io.FileNotFoundException ex)
	  {
	      System.err.println ("Something is wrong with the file: " + ex);
	  }
      System.out.println ("All done");
  }
}

using both the names of existing and non-existing files, or no name at all.


Unchecked Exceptions

Exceptions come in two main kinds: checked and unchecked


Checked Exceptions

checked exceptions are more specialized


Another Cultural Difference

5 Corresponding Data Structures

5.1 The Java API

The Java API (the equivalent of the C++ std library) is huge, but well documented

5.2 Strings

C++ std::string : Java java.lang.String

C++

string s = ...
s[s.size()/2] = 'b';
s = s + s;

Java

String s = ...
s = s.substring(0,s.length()/2)
  + 'b' 
  +  s.substring(s.length()/2+1);
s = s + s;


If You Need to Change a Java String…

…use a StringBuilder

StringBuilder sb = new StringBuilder();
String line = input.readline();
while (line != null) {
  sb.append(line);
  sb.append("\n");
  line = input.readline();
}
String allTheText = sb.toString();

5.3 Container Data Structures

vector : ArrayList

C++

vector<string> v;
v.push_back("foo");
cout << v[0] << endl

Java

ArrayList<String> v = new ArrayList<String>();
v.add("foo");
System.out.println (v.get(0)); 


list : LinkedList

C++

list<string> L;
L.push_back("foo");
cout << L.front() << endl

Java

LinkedList<String> L = new LinkedList<String>();
L.add("foo");
System.out.println (L.getFirst()); 


set : TreeSet

C++

set<string> s;
s.insert("foo");
cout << s.count("foo") << endl

Java

TreeSet<String> S = new TreeSet<String>();
S.add("foo");
System.out.println ("" + S.contains("foo")); 


unordered_set : HashSet

C++

unordered_set<string> s;
s.insert("foo");
cout << s.count("foo") << endl

Java

HashSet<String> S = new HashSet<String>();
S.add("foo");
System.out.println ("" + S.contains("foo")); 


map : TreeMap

C++

map<string,int> zip;
zip["ODU"] = 23529;
cout << zip["ODU"] << endl

Java

TreeMap<String,Integer> zip
     = new TreeMap<String,Integer>();
zip.put("ODU", 23529);
System.out.println (zip.get("ODU")); 


unordered_map : HashMap

C++

unordered_map<string,int> zip;
zip["ODU"] = 23529;
cout << zip["ODU"] << endl

Java

HashMap<String,Integer> zip
     = new HashMap<String,Integer>();
zip.put("ODU", 23529);
System.out.println (zip.get("ODU")); 


Cultural Difference

By default


1: A fully qualified name is an unambiguous name for an entity (function, variable, class, etc.) that is independent of the context in which it is used. Generally this means that when you have a hierarchy of entities contained inside other entities, you must name all of the containers, in order.

For example, the familiar C++ output stream cout is contained in the namespace std, so it’s fully qualified name is std::cout. But cout has a member function flush(). It’s fully qualified name is std::cout.flush().