Java without OOPs
Introduction
Although Java is an object orientated language, it is still possible to write some applications in Java with minimal knowledge of object orientated progranming (OOP). This might be necessary if Java is the only language available to you and you have no time to learn OOP and Java's implementation of it. If you don't need a graphical user interface you still do quite lot.
This is NOT a tutorial on Java! Rather, it shows a few examples of what you can do without needing to understand OOP.
Software needed for Java
To compile Java code you need install the Java SDK.
To run Java code you need to install the Java runtime - this is automatically installed when you install the Java SDK.
You can download these from Oracle's website
Hello World
First, here is the ususal "Hello World" program:
public class HelloWorld // This line creates the only class you need and you can call it whatever you like { // This is the entry point for the application and is very similar to C public static void main(String[] args) // "String[] args" is a an array of strings passed to the program on the command line { System.out.printf("Hello World\n"); // this printf() works just like the C printf(). You just call it differently } }
Compiling and running Java
You can write the code in a text editor and save it as "HelloWorld.java" and compile it using javac:
javac HelloWorld.java
This creates a HelloWorld..class file that holds Java code converted into Java bytecode for the Java virtual machine (JVM) to run.
The HelloWorld.class can be run by the JVM like this:
java HelloWorld
Adding functions
You can add functions/methods to your Java code like this:
public class Eaxmple1 { public static void main(String[] args) { func1(); func2(); } void func1() { System.out.printf("func1() called\n"); } void func2() { System.out.printf("func2() called\n"); } }
Types
Java has these types:
- boolean - 16 bit
- byte - 8 bit
- char - 16 bit for Unicode characters
- short - 16 bit
- int - 32 bit
- long - 64 bit
- float - 32 bit
- double - 64 bit
- object references - 32 bit (see below)
if, for, while and switch
The "if", "for", "while" and "switch" statements all behave like in C and several other languages with an important exception.
"if" and "while" conditions MUST be Boolen expressions. This C style of code is invalid:
int i = 10; while(i) { // do something with i }
Classes, instances, constructors and references
Java holds code for methods within classes. Methods are like functions and classes are like libraries in traditional languages.
Some methods/functions can be called directly by using the name of the class/library they are in e.g System.out.printf(). In this case the class that holds the printf() method/function is nested within another class so there are two parts to the class/library name - "System.out".
Other methods require that first you create an "instance" of the class that holds the method using their "constructor". This return a "refernce" to the "instance". Then you can use the "reference" to call the methods.
This is similar to calling library funtion to give you handle (e.g. to file) and then using the handle with the other library functions (e.g. to read or write to the file).
You can think of calling the class "constructor" like calling the library fucntion that creates and returns a handle. The reference is like a handle.
// Java: // Fred is a class // ref is a reference // new Fred() creates and returns the reference Fred ref = new Fred();
To use the reference to call a method, use the format reference.method e.g ref.func1(). This is like calling a library func1(handle). The essential difference is that in Java the reference comes before the name of the function to call instead of calling a library function where the handle is the first parameter to the function.
Arrays
Arrays are created differently from in C. In Java an array must be created using "new" e.g.
int[] arr = new int[10];
The "int[] arr" on the left of the = does NOT create an array. It ONLY declares that "arr" can hold a reference to an array.
The "new int[10]" on the right of the = creates the array and returns the reference to it.
Once the array is created it can be used as expected:
arr[5] = 10; int i = arr[5];
ArrayList
There is a more flexible version of an array called ArrayList. A normal array is created with a fixed size that can't be changed once it is created. An ArrayList lets you add and remove eleemts from the array similar to a linked list, but still allows you to read or write values to specific places in the array.
ArrayList<Integer> ar = new ArrayList<Integer>(); // create a new empty array integers ar.add(10); // add a element to the array and set it to 10 ar.add(20); // add a element to the array and set it to 20 int i = ar.get(0); // retrieve the value of the first element of the array ar.set(0, 30); // set element 0 of the array to a new value ar.remove(0); // remove element 0 from the array. All the other elements move down 1
What are the benefits?
There are benefits to using Java even without fully exploiting its OOP capabilities:
- Your complied code will run on any machine with a JVM
- There are many very powerful Java classes your code can make use of
Using Thread Pools
One of the most powerful classes Java offers allows you to you to:
- Create a pool of threads
- Submit an array of tasks to be executed by this pool of threads
- Collect the results of all of these tasks in an array
import java.util.ArrayList; // declares we will use the ArrayList class import java.util.List; // declares we will use the List class import java.util.concurrent.*; // declares we will use several classes from the java.util.concurrent set of classes // This is the only class we need to write. Call it whatever you like public class ExecutorServiceExample implements Callable<Integer> // declares we will have a call() method that returns an Integer { // "final static" declares a constant final static int NUM_THREADS = 10; // numbers of threads to use in the thread pool final static int NUM_TASKS = 10000; // numbers of tasks we want the thread pool to process final static int LOOP_SIZE = 100_000; // used in arbitary code in the task // the application starts here public static void main(String[] args) { // This creates a pool of threads to do your bidding ExecutorService execServ = Executors.newFixedThreadPool(NUM_THREADS); // This creates an ArrayList to hold references to the to the tasks you want done // The ExecutorService requires that the references are "Callable" which means they have a method called "call" // which we define below. This is the method that will be called by each thread. // The "<Integer>" declares that our call() method will return an Integer result. // We can choose a different return type if we wish ArrayList<Callable<Integer>> testsArrayList = new ArrayList<Callable<Integer>>(); // We build the array of tasks we want done for(int counterInt = 0; counterInt < NUM_TASKS; counterInt++) { testsArrayList.add(new ExecutorServiceExample()); // this a separate reference to our class for each entry } try // This is compulsory exception handling code for errors that might occur { // Called the ExecutorService to process our array of tasks using the threads in the thread pool // It returns when all the tasks have been completed // "List<Future<Integer>>" is a List of Integers that will be filled with the results of // each task. The List is built up as each task completes // The "Future" indicates that this integer does not exist yet but will soon List<Future<Integer>> resultList = execServ.invokeAll(testsArrayList); // we can process the results of all the tasks for(int counterInt = 0; counterInt < NUM_TASKS; counterInt++) { // retrieve result of each task Future<Integer> fut = resultList.get(counterInt); int resultInt = fut.get(); System.out.println("Result of test " + counterInt + " = " + resultInt); } } catch (InterruptedException e) // This is compulsory exception handling code for errors that might occur { e.printStackTrace(); } catch (ExecutionException e) // This is compulsory exception handling code for errors that might occur { e.printStackTrace(); } } // This is the task you want the threads to execute // You can't change the name of the method/function, but you can choose the type of the value it returns @Override public Integer call() throws Exception { // ARBITARY CODE // put whatever calculation you want to here int valueInt = ThreadLocalRandom.current().nextInt(1, 1000); for(int counterInt = 0; counterInt < LOOP_SIZE; counterInt++) { valueInt += ThreadLocalRandom.current().nextInt(1, 1000); valueInt /= 2; } return valueInt; // return the result of your calculation here } }