DEV Community

Cover image for Introduction to the Java programming language
Gabriele Boccarusso
Gabriele Boccarusso

Posted on • Originally published at boccarusso.com

Introduction to the Java programming language

99% of developers begin their path in two ways: either with python or javascript.
These two languages alone are very powerful for countless of reasons. They have both a very strong ecosystem and can be both used pretty much for anything. But a developer that knows only one language and its ecosystem pretty well will always have a very narrow point of view regarding software development in general. creating a sort of golden cage.

The problem is that focusing too much on a certain ecosystem and even getting a job solely about that, while certainly increasing your expertise, will will narrow your overall knowledge of the field. It is for these reasons that is useful to develop cross-discipline expertise, called T shaped expertise too, so to become a more valuable software engineer overall. The question is, how to do it?

Programming languages will always be the basics of the field and knowing the cons and pros of at least the major ones will give you a great advantage in the decision making process (especially if you are a senior or if you ever want to be one).
The best one to learn for someone well versed in languages that abstract way too many things like python and javascript, is java for the following reason:

  • Heavily Object-Oriented: in java everything is a class, thus making the paradigm a core part of the design
  • Robust: it offers all of the features of C/C++ pointer but without the memory management
  • Architecture neutral: it provides hardware and operative system abstraction so that it runs the same everywhere

To get started in Java an IDE is not required and the first times is better to just use the command line.
To download Java you can simply click here and follow the appropriate instructions based on your operative system. I'm currently using Linux (thus the dollar sign when referring to the cli) but the difference will be minimal at a such early stage.
To check if Java is installed correctly you can just check what current version is installed by typing in the command line:

$ java -version
Enter fullscreen mode Exit fullscreen mode

Which should output something similar to:

openjdk version "11.0.13" 2021-10-19
OpenJDK Runtime Environment (build 11.0.13+8-Ubuntu-0ubuntu1.20.04)
OpenJDK 64-Bit Server VM (build 11.0.13+8-Ubuntu-0ubuntu1.20.04, mixed mode, sharing)
Enter fullscreen mode Exit fullscreen mode

Don't worry if you have download a different version, be it lower or greater, that makes a difference only in the process of making a project.
Now that everything is set up we can make first.java and write in it a classic hello world:

public class First {
    public static void main(String[] args) {
        // in java every instruction must end
        // with a semi-colon (;)
        System.out.println("hello world");
    }
}
Enter fullscreen mode Exit fullscreen mode

To compile this hello world we have to type $ java first.java in the cli.
It appears clear from the very first moment what we are getting the hang on.
We create a class and in it we create the main method which has some code inside, but for now it looks like just a big main function but with extra steps.
Before starting with the OOP (Object Oriented Programming) let's see quickly the basics of the language

Basic syntax

Everything that we care about is happening in the main function.
Java has two way to output data, using print() and println(). The first will output everything on the same line while the second will output it on a new line.

public class Main {
    public static void main(String[] args) {
        System.out.println("first line"); // first line
        System.out.print("second"); // second line
        System.out.print(" line\n");
        /* when outputting in java you can concatenate 
         things using the "+" operator. Every variable will be
         automatically converted to a string /*
         System.out.println("My favorite number is " + 5);
    }
}
Enter fullscreen mode Exit fullscreen mode

it will output

first line
second line
My favorite number is 5
Enter fullscreen mode Exit fullscreen mode

Data types and variables

Java has 6 different types of variables

  • String: to store text -> "hello"
  • char: to store single characters -> 'a'
  • int: to store integers
  • float: to store decimals -> 10.5F*
  • double: same as float but more precise and space consuming
  • boolean: to store true or false

To declare a variable we have to define what type it is:

float f = 10.5F;
f = 11.5;
System.out.println(num); // 11.5
Enter fullscreen mode Exit fullscreen mode

*every time you declare a float the F at the end is mandatory, otherwise java will interpret it as a double.
To make a constant you simply add final before the variable declaration.

final int num = 50;
num = 100; // this will generate an error
Enter fullscreen mode Exit fullscreen mode

note that concatenating two numbers in a print() or println() function will sum them:

int a = 5, b = 15;
System.out.println("the sum of " + a + " and " + b + " is " + (a + b) );
Enter fullscreen mode Exit fullscreen mode
the sum of 5 and 10 is 15
Enter fullscreen mode Exit fullscreen mode

Conditionals & loops

Java conditionals, or control flow, and loops are the same as every other language so we'll just go through a quick recap.

  • equal to: a == b
  • not equal/different to: a != b
  • less than: a < b
  • less or equal than: a <= b
  • greater than: a > b
  • greater or equal than: a >= b

If and else

if (condition) {
    // code
} else if (condition) {
    // code
} else {
    // code
}
Enter fullscreen mode Exit fullscreen mode

Switch

switch(condition) {
case <i>a</i>:
    // code 
    break;
case <i>b</i>:
    // code 
    break;
default:
    // code 
}
Enter fullscreen mode Exit fullscreen mode

While loop

while (condition) {
    // code 
}
Enter fullscreen mode Exit fullscreen mode

Do while loop

do {
    // code
} while (<i>condition</i>);
Enter fullscreen mode Exit fullscreen mode

For loop

for(int i = 0; i < 10; i++) {
    System.out.println(i);
}
Enter fullscreen mode Exit fullscreen mode

Functions

Due to Java being an entirely object oriented languages, as we have already shortly mentioned,
it doesn't have functions but methods.
The difference between functions and methods will become clear on the OOP section,
for now their difference relies only in their names.

public class First {
    // static means that it belongs to the 
    // class and that is not an object
    // more on that later
    static void executeMe(int num) {
        System.out.println("executed for the " + num + "° time.");
    }
    public static void main(String[] args) {
        executeMe(1);
        executeMe(2);
        executeMe(3);
    }
}
Enter fullscreen mode Exit fullscreen mode

In Java to a method is defined using the type of value that it has to return.

// this method doesn't return anything
// so you have to put void in front of it
static void sayHi() {
    System.out.println("Hi");
}
Enter fullscreen mode Exit fullscreen mode
// this method returns a float
static float getTemperature() {
    float temperature;
    // calculating temperature
    temperature = 11.5F;
    return temperature;
}
Enter fullscreen mode Exit fullscreen mode

method's arguments follow the same rules

static int power(int a, int b) {
    int c = a;
        for (int i = 1; i < b; i++) {
        c = c * a;
    }
    return c;
}
Enter fullscreen mode Exit fullscreen mode

OOP

Object Oriented Programming is a way to organize the code by dividing it into fully functioning
abstract entities: objects.


A class is a blueprint for objects and an object contains some data,
attributes and can execute certain behaviors, methods.


Let's create a class car to see how this concept works overall.

public class First {
    public static void main(String[] args) {
        // what we define as object is the instance of a class
        Car firstCar = new Car();
        // to access an object properties we use the dot (.) notation
        // we are now setting the data that it will have to contain
        firstCar.setColor("black");
        firstCar.setNameCar("Toyota AE86");
        firstCar.setSeatbelts(5);

        // we are now calling an object method
        firstCar.explainCar();
    }
}

class Car {
    // those are the attributes of the class,
    // the data that the object will keep stored
    String color;
    String nameCar;
    int numSeatbelts;

    // methods that start with set are used 
    // to set an attribute and are called setters
    void setColor(String aColor) {
        color = aColor;
    } 

    /* we can set the data of an object by doing
        object.attribute = X, or as in this case
        firstCar.color = "black", but this is a not
        recommended. Is always better to create a setter method
    */
    void setNameCar(String aName) {
        nameCar = aName;  
    }

    void setSeatbelts(int num) {
        numSeatbelts = num;
    }

    // methods that are used to receive
    // the attributes of a class are called getters
    String getColor() {
        return color;
    }

    /* getting the attribute directly with
        var = firstCar.color; would work but,
        again, is not recommended
    */
    String getNameCar() {
        return nameCar;
    }

    int getNumSeatbelts() {
        return numSeatbelts;
    }

    void explainCar() {
        System.out.println("This car is a " + color + 
        " " + nameCar + " with " + 
        numSeatbelts + " seatbelts.");
    }
}
Enter fullscreen mode Exit fullscreen mode

What we are doing conceptually is creating an instance of a car with the data that we gave to it and the same function (methods) that we defined in the class.
uml like representation of a class and a instance
With OOP, once defined a class, we can create all the instances of it that we may need and refer only to the it when something goes wrong or we want to change something. By saving this code into a file called car.java and then compiling it with $ java car.java it would output:

This car is a black Toyota AE86 with 5 seatbelts.
Enter fullscreen mode Exit fullscreen mode

we can now use the same car class to create as many cars as we want.

public class First {
    public static void main(String[] args) {
        Car firstCar = new Car();
        Car secondCar = new Car();

        // setting attributes
        firstCar.setColor("black");
        firstCar.setNameCar("Toyota AE86");
        firstCar.setSeatbelts(5);

        secondCar.setColor("yellow");
        secondCar.setNameCar("Ford Mustang");
        secondCar.setSeatbelts(5);

        // outputting the two cars
        firstCar.explainCar();
        secondCar.explainCar();
    }
}
Enter fullscreen mode Exit fullscreen mode

output:

This car is a black Toyota AE86 with 5 seatbelts.
This car is a yellow Ford Mustang with 5 seatbelts.
Enter fullscreen mode Exit fullscreen mode

The reasons we use setters and getters is to make the code more secure and reliable. By how this code is wrote it would be legal to do something like

firstCar.seatbels = 0;
Enter fullscreen mode Exit fullscreen mode

we can't let something like this happen.

public and private

by adding the private keyword to the attributes of a class we can prevent undesired situations:

class Car {
    private String color;
    private String nameCar;
    private int numSeatbelts;
    ...
Enter fullscreen mode Exit fullscreen mode

now something like firstCar.seatbels = 0; would generate an error. Yet, it is still not enough:

firstCar.seatBelts = 0; // this would generate an error
// but this no
firstCar.setSeatbelts(0); 
Enter fullscreen mode Exit fullscreen mode

this is why it setter methods are so important. What we have wrote is very incomplete, something better would be

public void setSeatbelts(int num) {
    if (num < 1) {
        num = 1; // minimum seatbelts
    } else if (num > 6) {
        num = 6; // maximum seatbelts
    };
    numSeatbelts = num;
}
Enter fullscreen mode Exit fullscreen mode

as you may have noticed we have put public before the method declaration, this because we want our attributes to not be directly accessible but our setter and getter to be it. Other methods like explainCar do not need any private or public keyword in front of them. As a rule of thumb we put private in front of the attributes and public in front of the setter and the getters.

Arrays

Arrays in Java are nothing special. They begin from 0 and can be created very intuitively:

// initializing arrays
int[] nums = {0, 1, 2, 3, 4, 5};
String[] names = {"Mark", "John", "Elizabeth"};
// creating an array of a certain size
char[] letters = new char[2];
letters[0] = 'h';
letters[1] = 'i';
Enter fullscreen mode Exit fullscreen mode

in java defining an array without initializing it means that we are making space for that number of data. The same concept applies for objects.
What if we have so much objects that it would be futile to give a name to everyone of them? We can just use an array of objects:

public static void main(String[] args) {
    Car firstCar = new Car();
    Car secondCar = new Car();

    int size = 3;
    // right now we are not making space for 3 object
    // but for 3 references to that object
    Car[] cars = new Car[size];

    for(int i = 0; i < size; i++) {
        /*at every space of the array we
        have to create a new object */
        cars[i] = new Car(); // without this line we would get an error
        cars[i].setColor("black");
        cars[i].setNameCar("Audi Q3");
        cars[i].setSeatbelts(5);
        System.out.print((i+1) + ": ");
        cars[i].explainCar();
    }
}
Enter fullscreen mode Exit fullscreen mode

Primitive and reference

Data in Java is divided into two types: primitives and references.
Primitive are the basic data types that we already saw. An int is a primitive, a char is a primitive.
References are those data types that are more complicated and that would occupy a lot of memory,
they are called so because they are not the data, just a reference to it.
A String a reference to an array of char, an array
is a reference to references. When we create an array of 5 objects we are creating a reference
to where the actual objects are. The first item of an array is a reference to the reference of the object.
When we do something like cars[0].getColor()

  1. Refer to the space where the array is located
  2. Refer to the first item of such array
  3. This item is a reference to an object, so refer to it
  4. Get the data located in that place

this is incredibly efficient because instead of using and passing entire objects between methods we are working only with reference to them.

This way there is a twist while confronting two objects.
If we want to confront two primitives everything goes well would be enough:

int a = 5;
float b = 5.0F;
if (a == b) { // true }
Enter fullscreen mode Exit fullscreen mode

but if we would the same with two objects it would not confront the content of such objects but only their references:

public class First {
    public static void main(String[] args) {
        Car firstCar = new Car();
        Car secondCar = new Car();
        Car thirdCar = firstCar;

        firstCar.setColor("black");
        firstCar.setNameCar("Toyota AE86");
        firstCar.setSeatbelts(5);

        secondCar.setColor("yellow");
        secondCar.setNameCar("Ford Mustang");
        secondCar.setSeatbelts(5);

        if (firstCar == secondCar) { /* false */ 
            System.out.println("They refer to two different objects, you'll not see this message");
        }
        if (firstCar == thirdCar) {
            System.out.println("These two reference store the same object address");
        }

        firstCar.setColor("yellow");
        firstCar.setNameCar("Ford Mustang");
        firstCar.setSeatbelts(5);
        if (firstCar == secondCar) { 
            System.out.println("Those are two objects with the same data, but still two different objects"); 
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)