Introduction
Java in typed language, we all know that. It requires JVM (java virtual machine) to execute the Java programs. Java needs a compiler which converts a java code into bytecode (fileName.class) file. This fileName.class is used by the JVM to execute the programs. To execute a Java program we need a main method, no matter how many java files we have we only need one main method to execute.
Variables
They are two types:
- Primitive
- Reference
Primitive
All the basic types int, boolean, float, short , byte, long, double come under primitive. When you use a primitive variable you are actually storing the value of that variable in the bit form in the memory. So when you compare two primitive variable if there are the same value the result will be true which is not the case for the reference variable.
double > float > long > int > short > byte > boolean
When you assign a higher primitive variable to a lower primitive variable java gives you an error you can’t do that unless you do explicit casting.
Reference
These are used to refer to a object, you can’t store an object in a variable in java you only get the reference to that object in other words you can control that object but can’t have the actual object. So when two reference variable refer to a objects which are equal you can’t compare them using the == operator, but you can use equals() method.
If a object doesn’t have any references then that object is eligible for garbage collection. Arrays are objects in java even if they hold primitive values.
Wrappers
In java you can only use objects in collections, which means using primitive variables gives an error, but the compiler uses Wrapper classes when you pass a primitive variable. Wrapper classes wrappers around primitive variables with some static methods.
Optional Wrapper
There is a special Wrapper Optional, when we can’t guarantee method returns something we use optional wrapper to check whether it’s present or not
Objects
In Java everything is an object and we should think in that way. We need classes to create objects. Classes are blueprints which tells how a object should be. An object contains two things behaviour (methods) and state (instance variables). A class is not an object it is used to construct an object. We access the state of object using dot operator.
Encapsulation
This just means protecting your instance variables. Your instance variables can’t be open they can be changed by the user how ever they want. YOU HAVE TO PROTECT THEM. The way you do that is have the keyword private in-front of instance variables. Then how to actually change or access them? By using getters and setter methods. By the way instance variables always have a default value if though you didn’t initialize them.
Encapsulation gives you control over who changes the data in your class and how.
Stack and Heap
Java has two places stack and heap to store things. Stack is for the local variables. Heap for instance variables. When you call a another method from inside a method, one more stack gets added to the stack. All objects live on the heap regardless of where they are instantiated but references to those objects live with respect to their scope (local or instance).
Constructors
Every class has a constructor, if you don’t write one the compiler will create one for you. Constructor are used to construct an object. They don’t have return types unlike methods. You can overload constructors for a single class. A constructor is called when you use new keyword to initialize an object. Constructors have the same name has class name.
Inner Classes
Inner classes are used to implement the same interface more than once. They have access to all variables and methods of the outer class including the private ones. They can initialized from outside the class but it’s a bit tricky.
Methods
Methods can have parameters, which you have to have while calling that method, also they can have return types. A method has parameters and user passes arguments to the method. Java is a pass-by-value which mean pass-by-copy. Whenever you pass an argument to a method the bits of the arguments are copied into the parameters of the method. So when you pass primitives they are copied one-to-one by bit-by-bit, which means you change that variable inside the method the original primitive value doesn’t change. When you pass a reference variable the method parameter gets the copy of reference to a object so when you change something in the object, the actual object changes.
You can use enhanced for loop for collections You can also declare more than one variable inside a for-loop
OverLoading
When can multiple methods with the same name in the same class but we need to have different parameters. This only works if the parameters are in different order or the number of parameters are different
Libraries
In java by default java.lang is imported, all the default things we use such as (Strings, System) are part of java.lang package. We import packages to use already existing code so that we can focus on important things. Java includes many predefined packages. The main package we use is java.util which contains all the collections.
In the above code we used parameterized type (angle brackets) to indicate which type of objects the ArrayList hold, we left angle brackets on the right side empty because compiler can figure out based on the left hand side that ArrayList is of type String. Instead of importing the package we can use the full name of ArrayList everywhere in the code.
Inheritance
Java’s main feature is to reuse the code everywhere we can. Inheritance can help us achieve that. When a class inherits another class it gains all the functionality of that super class. For example if class B inherits class A then class B gets all the features of class A and class B can have extra functionality and also if class C inherits class B then class C all functionality of both class A and B. But a class can have only one superclass.
If a class has private methods or variables then they don’t get inherited to the subclasses.
If a subclass wan’t a different behaviour from a method inherited from the superclass then the subclass can override the method and it’s own functionality.
Java doesn’t support multiple inheritance (we use interfaces for that). You can invoke a superclass method by using super.methodName(). When a subclass is instantiated all the superclass constructors are called.
Polymorphism
In java you can reference a subclass object using a superclass reference variable this is polymorphism, which means many forms.
Abstract and Concrete Classes
When you don’t a class to initialized by itself unless it’s extended then we use abstract keyword in-front of the class to mark it (obviously) abstract. You can also mark a method abstract, abstract methods don’t contain any body and you must override the abstract method to implement it.
Concrete classes are classes which can be initialized.
Every class in java extends Object class.
Some methods of Object class are:
- equals()
- getClass()
- toString()
- hashCode()
If you use polymorphism to refer to objects you can only call methods of the referred type rather then the actual object.
Interface
It is used to solve the problem of multiple inheritance. Interfaces lets us treat the objects by the role it plays rather than by the class type from which it was instantiated. All methods in an interface should be abstract. We use implements keyword to implement an interface.
You can implement multiple interfaces for a single class.
Keywords
Static
In java everything is an object but sometimes we want global methods and instance variables, static keyword lets us do that.
Static variables are per class rather than per object Static methods don’t require an instance to run them
Static methods can only use and refer to another static methods and static variables, it can’t have non-static things in it. All static variables in class are initialized before any object is created.
Final
When you use a final keyword, it means it can’t be changed. You can’t change the value of variable declared with final keyword. You can’t override a method declared with final. You can’t have a class has a superclass if it is final.
In general final static variables are used as global constants (Ex: PI)
Data Structures
Most of the data structures we are in java.util package and most of directly or indirectly extends Collections class.
graph TD Collection["Collection (interface)"] Set["Set (interface)"] List["List (interface)"] SortedSet["SortedSet (interface)"] Collection --> Set Collection --> List Set --> SortedSet Set -.-> LinkedHashSet Set -.-> HashSet SortedSet -.-> TreeSet List -.-> ArrayList List -.-> LinkedList List -.-> Vector class Collection,Set,List,SortedSet interface;
graph TB Map["Map (interface)"] SortedMap["SortedMap (interface)"] Map --> SortedMap Map -.-> HashMap Map -.-> LinkedHashMap Map -.-> Hashtable SortedMap -.-> TreeMap class Map,SortedMap interface;
We use some helpful static methods from Collections to make our life a bit more efficient, we use Collections.sort() to sort a List, but to use it a class must implement Comparable.
We can also use Comparator which is an interface with a compare method.
Streams and Lamdas
Streams
A Streams API is a set of operations we can perform on collections. A steam as three things:
- Source
- Intermediate Operations
- Terminal Operation We call this stream pipeline When we add operations to stream pipeline it doesn’t change the original collection and also it doesn’t store the result of each operation, only when the terminal operation is used it gives the result.
Lamdas
They make the code shorter. If an interface has only Single Abstract Method (SAM) also known as FunctionalInterface we can use lamda expressions.
Exceptions
Exceptions are objects which extends the class Exception. When you have risky behaviour in your method like server crashing down you want to alert the user that there are getting into danger zone. So the user has to handle those exceptions. Exceptions are two types:
- Checked
- Unchecked Checked exceptions are thrown by the compiler. We use the keyword throws to specify a class can throw an exception. we throw a new exception use throw new keywords.
Unchecked exceptions are thrown at runtime so they don’t have to be handled. We handle a exception by using try and catch blocks
We will also use finally keyword to perform something in the end no matter what.
You can have multiple catch blocks for a single try Exceptions are polymorphic If you are not prepared to handle the exception you can duck it by throwing the same exception.
Serialization
It is saving the state of an object (instance variables). If your instance variables contains references to objects then those objects will also be serialized. If you want a class to be serialized they should implement Serializable. Every object inside a class also must implement Serializable for it to be serialized. In java data moves in streams from one place to another. Java I/O API has connection streams which connect source and destination.
We can use transient keyword to skip a instance variable from being serialized.
Threads
Threads are way to run different parts of the program simultaneously, but we can’t guarantee which part runs when. This behaviour leads to unexpected behaviour. There are several ways to solve this, we can use Atomic variables with compareAndSet() or synchronized keyword. Threads leads to Concurrency issues so we use synchronized keyword to ensure only a single thread can access that part at a time, other threads have to wait. If two threads are waiting for the other thread to complete, this leads to DEADLOCK.
Instead of using Threads directly we use Executors and ExecutorService to manage threads. To make a job for your thread it needs to implement runnable.
Extras
Strings are Wrapper classes are immutable
Using StringBuilder instead of Strings to manipulate strings
TWR (Try with Resource), when you use this you don’t have explicitly close the things you have opened
Varags lets us take has many parameters has we want.
Annotations give compiler extra info about the topic and helps the IDE to better understand the code.
You can use Streams parallelly, but only do that for large data things.
Enums are replacement for global constants.
We can use var in java in some places.
There are records in java which are used to store data instead of using a class we use records.