Top 25 Java Tricks, Tips, and Best Practices

Top 25 Java Tricks, Tips, and Best Practices

Java Programming

Java Programming

This article will help you in Java programming practices to save time, optimize and improve code quality.

Java employs more than 3 billion devices and code more than 9 million developers. Count the number of applications is simply impossible. It is a powerful and reliable language, but sometimes Java programming can be time consuming.

Debugging, optimization, and improving code performance take a long time, so a good developer always uses the best programming practices.

In this article, we have selected a small collection of such practices, tricks and tips that will save you time.

If you are a novice Java programmer, then you can download Java on the official website.

Work organization

Clean code

In large projects, it is not the creation of new code that comes to the forefront, but the support for the existing one. Therefore, it is very important to organize it correctly from the very beginning. When designing a new application, always remember the three basic principles of clean and supported code:

  • rule 10-50-500. In one package cannot be more than 10 classes. Each method must be shorter than 50 lines of code, and each class must be shorter than 500 lines;
  • SOLID design principles ;
  • use of design patterns.

Work with errors

Stack trace

Catching bugs is perhaps the most time-consuming part of the Java development process. The stack trace allows you to track exactly where the project threw an exception.

import java.io.*; Exception e = …; java.io.StringWriter sw = new java.io.StringWriter(); e.printStackTrace(new java.io.PrintWriter(sw)); String trace = sw.getBuffer().toString();

NullPointer Exception

Null pointer exceptions occur in Java quite often when attempting to call a method of a nonexistent object.

Take for example the following line of code:

int noOfStudents = school.listStudents().count;

private int getListOfStudents(File[] files) { if (files == null) throw new NullPointerException("File list cannot be null"); }

Date and Time

System.currentTimeMillis vs System.nanoTime

In Java, there are two standard ways of conducting time-operations and it is not always clear which one should be chosen.

The method System.currentTimeMillis() returns the current number of milliseconds since the beginning of the Unix era in the format Long. Its accuracy ranges from 1 to 15 thousandths of a second, depending on the system.

long startTime = System.currentTimeMillis(); long estimatedTime = System.currentTimeMillis() - startTime;

The method System.nanoTimehas an accuracy of up to one-millionth of a second (nanoseconds) and returns the current value of the most accurate available system timer.

long startTime = System.nanoTime(); long estimatedTime = System.nanoTime() - startTime;

Thus, it is System.currentTimeMillisexcellent for displaying and synchronizing absolute time, and System.nanoTimefor measuring relative intervals.

Validity of the date line

If you need to get a date object from a regular string in Java, use this useful auxiliary class that will take care of all the complexities of validation and conversion.

Strings

Row optimization

When concatenating strings in Java using an operator +, for example, in a loop for, a new object is created each time String, which leads to memory loss and an increase in the running time of the program.

You should also avoid creating Java strings using the class constructor:

// slow instantiation String bad = new String ("Yet another string object");

// fast instantiation String good = "Yet another string object"

Single and double quotes

What do you expect to get from this code?

public class Haha { public static void main(String args[]) { System.out.print("H" + "a"); System.out.print('H' + 'a'); } }

It would seem that the string should return HaHa, but in reality it will be Ha169.

Double quotes treat characters as strings, but single quotes behave differently. They convert character operands ( 'H'and 'a') to integer values ​​through the extension of primitive types – it turns out 169.

Maths

Float vs double

Programmers often cannot select the precision they need for floating-point numbers. Float requires only 4 bytes, but it has only 7 significant digits, while Double is twice as accurate (15 digits), but twice as wasteful.

In fact, most processors are able to work with Float and Double equally effectively, so use the recommendation of Bjorn Stroustrup:

“Choosing the right accuracy in real-world problems requires a good understanding of the nature of machine computing. If you do not have it, either consult with someone, or study the problem yourself, or use double and hope for the best. ”

Oddness check

Is it possible to use this code to accurately determine the odd number?

public boolean oddOrNot(int num) { return num % 2 == 1; }

I hope you noticed a trick. If we decide to check a negative odd number in such a way (-5, for example), the remainder of the division will not be equal to one (what does it mean?) Therefore, use a more accurate method:

public boolean oddOrNot(int num) { return (num & 1) != 0; }

It not only solves the problem of negative numbers, but also works more productively than its predecessor. Arithmetic and logical operations are performed much faster than multiplication and division.

Degree calculation

You can raise the number to a power in two ways:

  • simple multiplication;
  • using the function Math.pow(double base, double exponent).

The use of the library function is recommended only when absolutely necessary, for example, in the case of a fractional or negative degree.

double result = Math.pow(625, 0.5); // 25.0

Simple multiplication in Java works 300-600 times more efficiently, besides it can be further optimized:

double square = double a * double a;

double cube = double a * double a * double a; // not optimized double cube = double a * double square; // optimized

double quad = double a * double a * double a * double a; // not optimized double quad = double square * double square; // optimized

Jit optimization

Java code is processed using JIT compilation: first it is translated into platform-independent byte code, and then after that into machine code. At the same time, everything that is possible is optimized, and the developer can help the compiler create the most efficient program.

As an example, take a look at two simple operations:

// 1 n += 2 * i * i;

// 2 n += 2 * (i * i);

Let’s measure the execution time of each of them:

// 1 long startTime1 = System.nanoTime(); int n1 = 0; for (int i = 0; i < 1000000000; i++) { n1 += 2 * i * i; } double resultTime1 = (double)(System.nanoTime() - startTime1) / 1000000000; System.out.println(resultTime1 + " s");

// 2 long startTime2 = System.nanoTime(); int n2 = 0; for (int i = 0; i < 1000000000; i++) { n2 += 2 * (i * i); } double resultTime2 = (double)(System.nanoTime() - startTime2) / 1000000000; System.out.println(resultTime2 + " s");

By running this code several times, we get something like this:

2*(i*i) | 2*i*i ----------+---------- 0.5183738 | 0.6246434 0.5298337 | 0.6049722 0.5308647 | 0.6603363 0.5133458 | 0.6243328 0.5003011 | 0.6541802 0.5366181 | 0.6312638 0.515149 | 0.6241105 0.5237389 | 0.627815 0.5249942 | 0.6114252 0.5641624 | 0.6781033 0.538412 | 0.6393969 0.5466744 | 0.6608845 0.531159 | 0.6201077 0.5048032 | 0.6511559 0.5232789 | 0.6544526

The pattern is obvious: grouping variables with parentheses speeds up the work of the program. This is due to the generation of a more efficient byte-code when multiplying the same values.

You can read more about this experiment here. And you can conduct your own test using the Java online compiler.

Data structures

Combining hash tables

Combining two hashes, iterating their values ​​manually, is very inefficient. Here is an alternative solution to this problem that you will definitely like:

import java.util.*; Map m1 = …; Map m2 = …; m2.putAll(m1); // adds to m2 all items from m1

Array vs ArrayList

The choice between Array and ArrayList depends on the specifics of the Java task you want to solve. Remember the following features of these types:

  • The array has a fixed size and memory for it is allocated at the time of the announcement, and the size of ArrayLists can be dynamically changed.
  • Java arrays are much faster, and in ArrayList, it is much easier to add/delete items.
  • When working with Array, it is likely to get an error ArrayIndexOutOfBoundsException.
  • ArrayList has only one dimension, but Java arrays can be multidimensional.

import java.util.ArrayList;

public class arrayVsArrayList {

public static void main(String[] args) {

// Add Array
int\[\] myArray = new int\[6\];

// reference to a nonexistent index
myArray\[7\]= 10; // ArrayIndexOutOfBoundsException

// announcement ArrayList
ArrayList<Integer> myArrayList = new ArrayList<>();

// simple addition and removal of elements
myArrayList.add(1);
myArrayList.add(2);
myArrayList.add(3);
myArrayList.add(4);
myArrayList.add(5);
myArrayList.remove(0);

// receiving items ArrayList 
for(int i = 0; i < myArrayList.size(); i++) {
  System.out.println("Element: " + myArrayList.get(i));
}

// multi-dimensional Array
  int\[\]\[\]\[\] multiArray = new int \[3\]\[3\]\[3\]; 
}

}

Json

Serialization and deserialization

JSON is an incredibly convenient and useful syntax for storing and sharing data. Java fully supports it.

You can serialize data like this:

import org.json.simple.JSONObject; import org.json.simple.JSONArray;

public class JsonEncodeDemo {

public static void main(String[] args) {

JSONObject obj = new JSONObject();
obj.put("Novel Name", "Godaan");
obj.put("Author", "Munshi Premchand");

JSONArray novelDetails = new JSONArray();
novelDetails.add("Language: Hindi");
novelDetails.add("Year of Publication: 1936");
novelDetails.add("Publisher: Lokmanya Press");

obj.put("Novel Details", novelDetails);
  System.out.print(obj);
}

}

It turns out this JSON string:

{"Novel Name":"Godaan","Novel Details":["Language: Hindi","Year of Publication: 1936","Publisher: Lokmanya Press"],"Author":"Munshi Premchand"}

Java deserialization looks like this:

import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.Iterator;

import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException;

public class JsonParseTest {

private static final String filePath = "//home//user//Documents//jsonDemoFile.json";

public static void main(String[] args) { try { // read json file FileReader reader = new FileReader(filePath); JSONParser jsonParser = new JSONParser(); JSONObject jsonObject = (JSONObject)jsonParser.parse(reader);

  // get data from json object
  Long id =  (Long) jsonObject.get("id");
  System.out.println("The id is: " + id);           

  String type = (String) jsonObject.get("type");
  System.out.println("The type is: " + type);

  String name = (String) jsonObject.get("name");
  System.out.println("The name is: " + name);

  Double ppu =  (Double) jsonObject.get("ppu");
  System.out.println("The PPU is: " + ppu);

  // get an array        
  System.out.println("Batters:");
  JSONArray batterArray= (JSONArray) jsonObject.get("batters");
  Iterator i = batterArray.iterator();
  // iterate over all elements of the array separately
  while (i.hasNext()) {
    JSONObject innerObj = (JSONObject) i.next();
    System.out.println("ID "+ innerObj.get("id") + 
        " type " + innerObj.get("type"));
  }

  System.out.println("Topping:");
  JSONArray toppingArray= (JSONArray) jsonObject.get("topping");
  Iterator j = toppingArray.iterator();
  while (j.hasNext()) {
    JSONObject innerObj = (JSONObject) j.next();
    System.out.println("ID "+ innerObj.get("id") + 
        " type " + innerObj.get("type"));
  }
} catch (FileNotFoundException ex) {
  ex.printStackTrace();
} catch (IOException ex) {
  ex.printStackTrace();
} catch (ParseException ex) {
  ex.printStackTrace();
} catch (NullPointerException ex) {
  ex.printStackTrace();
}

} }

JSON file used in the example (jsonDemoFile.json):

{ "id": 0001, "type": "donut", "name": "Cake", "ppu": 0.55, "batters": [ { "id": 1001, "type": "Regular" }, { "id": 1002, "type": "Chocolate" }, { "id": 1003, "type": "Blueberry" }, { "id": 1004, "type": "Devil's Food" } ], "topping": [ { "id": 5001, "type": "None" }, { "id": 5002, "type": "Glazed" }, { "id": 5005, "type": "Sugar" }, { "id": 5007, "type": "Powdered Sugar" }, { "id": 5006, "type": "Chocolate with Sprinkles" }, { "id": 5003, "type": "Chocolate" }, { "id": 5004, "type": "Maple" } ] }

Input Output

FileOutputStream vs. Filewriter

Writing files to Java is carried out in two ways: FileOutputStreamand FileWriter. Which method to choose depends on the specific task.

FileOutputStreamdesigned to write raw byte streams. This makes it an ideal solution for working with images, for example.

File foutput = new File(file_location_string); FileOutputStream fos = new FileOutputStream(foutput); BufferedWriter output = new BufferedWriter(new OutputStreamWriter(fos)); output.write("Buffered Content");

It has a FileWriterdifferent vocation: working with streams of characters. So if you are writing text files, choose this method.

FileWriter fstream = new FileWriter(file_location_string); BufferedWriter output = new BufferedWriter(fstream); output.write("Buffered Content");

Performance and best practices

Empty collection instead of Null

If your program can return a collection that does not contain any values, make sure that it is the empty collection that is returned, and not Null. It will save you time for various checks.

public class getLocationName { return (null==cityName ? "": cityName); }

Creating objects only when necessary

Creating objects is one of the most costly operations in Java. The best practice is to create them only when necessary when they are really needed.

import java.util.ArrayList; import java.util.List;

public class Employees {

private List Employees;

public List getEmployees() {

// initialization only if necessary
if(null == Employees) {
  Employees = new ArrayList();
}
return Employees;

} }

Deadlocks

Mutual blocking of threads can occur for many reasons, and it is very difficult to fully protect against them in Java 8. This most often occurs when one synchronized object waits for resources that are locked by another synchronized object.

Here is an example of this thread deadlock:

public class DeadlockDemo { public static Object addLock = new Object(); public static Object subLock = new Object();

public static void main(String args[]) { MyAdditionThread add = new MyAdditionThread(); MySubtractionThread sub = new MySubtractionThread(); add.start(); sub.start(); }

private static class MyAdditionThread extends Thread { public void run() { synchronized (addLock) { int a = 10, b = 3; int c = a + b; System.out.println("Addition Thread: " + c); System.out.println("Holding First Lock..."); try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println("Addition Thread: Waiting for AddLock..."); synchronized (subLock) { System.out.println("Threads: Holding Add and Sub Locks..."); } } } }

private static class MySubtractionThread extends Thread { public void run() { synchronized (subLock) { int a = 10, b = 3; int c = a - b; System.out.println("Subtraction Thread: " + c); System.out.println("Holding Second Lock..."); try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println("Subtraction Thread: Waiting for SubLock..."); synchronized (addLock) { System.out.println("Threads: Holding Add and Sub Locks..."); } } } }

}

The output of this program:

\===== Addition Thread: 13 Subtraction Thread: 7 Holding First Lock... Holding Second Lock... Addition Thread: Waiting for AddLock... Subtraction Thread: Waiting for SubLock...

Deadlocks can be avoided by changing the order in which threads are called:

private static class MySubtractionThread extends Thread { public void run() { synchronized (addLock) { int a = 10, b = 3; int c = a - b; System.out.println("Subtraction Thread: " + c); System.out.println("Holding Second Lock..."); try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println("Subtraction Thread: Waiting for SubLock..."); synchronized (subLock) { System.out.println("Threads: Holding Add and Sub Locks..."); } } } }

Conclusion:

\===== Addition Thread: 13 Holding First Lock... Addition Thread: Waiting for AddLock... Threads: Holding Add and Sub Locks... Subtraction Thread: 7 Holding Second Lock... Subtraction Thread: Waiting for SubLock... Threads: Holding Add and Sub Locks...

Memory reservation

Some Java applications are very resource intensive and can be slow. For better performance, you can allocate more RAM to your Java machine.

export JAVA_OPTS="$JAVA_OPTS -Xms5000m -Xmx6000m -XX:PermSize=1024m -XX:MaxPermSize=2048m"

  • Xms – the minimum pool of memory allocation;
  • Xmx – maximum memory allocation pool;
  • XX: PermSize – the initial size that will be allocated when starting the JVM;
  • XX: MaxPermSize – the maximum size that can be allocated when starting a JVM.

Solving common problems

Directory Content

Java allows you to get the names of all subdirectories and files in a folder as an array, which can then be sequentially viewed.

import java.io.*;

public class ListContents { public static void main(String[] args) { File file = new File("//home//user//Documents/"); String[] files = file.list();

System.out.println("Listing contents of " + file.getPath());
for(int i=0 ; i < files.length ; i++)
{
  System.out.println(files\[i\]);
}

} }

Execution of console commands

Java allows you to execute console commands directly from code using a class Runtime. It is very important not to forget about exception handling.

For example, let’s try to open a PDF file through a Java terminal:

import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader;

public class ShellCommandExec {

public static void main(String[] args) { String gnomeOpenCommand = "gnome-open //home//user//Documents//MyDoc.pdf";

try {
  Runtime rt = Runtime.getRuntime();
  Process processObj = rt.exec(gnomeOpenCommand);

  InputStream stdin = processObj.getErrorStream();
  InputStreamReader isr = new InputStreamReader(stdin);
  BufferedReader br = new BufferedReader(isr);

  String myoutput = "";

  while ((myoutput=br.readLine()) != null) {
    myoutput = myoutput+"\\n";
  }
  System.out.println(myoutput);
}
catch (Exception e) {
  e.printStackTrace();
}

} }

Sound reproduction

Sound is an important component of many applications, such as games. The Java programming language provides the means to work with it.

import java.io.*; import java.net.URL; import javax.sound.sampled.*; import javax.swing.*;

public class playSoundDemo extends JFrame {

// constructor public playSoundDemo() { this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setTitle("Play Sound Demo"); this.setSize(300, 200); this.setVisible(true);

  try {
     URL url = this.getClass().getResource("MyAudio.wav");
     AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
     Clip clip = AudioSystem.getClip();
     clip.open(audioIn);
     clip.start();
  } catch (UnsupportedAudioFileException e) {
     e.printStackTrace();
  } catch (IOException e) {
     e.printStackTrace();
  } catch (LineUnavailableException e) {
     e.printStackTrace();
  }

}

public static void main(String[] args) { new playSoundDemo(); } }

Sending email

Sending email to Java is very simple. You just need to install Java Mail and specify the path to it in the project classpath.

import java.util.*; import javax.mail.*; import javax.mail.internet.*;

public class SendEmail { public static void main(String [] args) {
String to = ""; String from = ""; String host = "localhost";

Properties properties = System.getProperties();
properties.setProperty("mail.smtp.host", host);
Session session = Session.getDefaultInstance(properties);

try{
  MimeMessage message = new MimeMessage(session);
  message.setFrom(new InternetAddress(from));

  message.addRecipient(Message.RecipientType.TO,new InternetAddress(to));

  message.setSubject("My Email Subject");
  message.setText("My Message Body");
  Transport.send(message);
  System.out.println("Sent successfully!");
}
catch (MessagingException ex) {
  ex.printStackTrace();
}

} }

Capture cursor coordinates

To capture mouse events, you need to implement an interface MouseMotionListener. When the cursor falls into a specific area, an event handler is triggered mouseMoved, from which you can get the exact coordinates.

import java.awt.event.*; import javax.swing.*;

public class MouseCaptureDemo extends JFrame implements MouseMotionListener { public JLabel mouseHoverStatus;

public static void main(String args[]) { new MouseCaptureDemo(); }

MouseCaptureDemo() { setSize(500, 500); setTitle("Frame displaying Coordinates of Mouse Motion");

mouseHoverStatus = new JLabel("No Mouse Hover Detected.", JLabel.CENTER);
add(mouseHoverStatus);
addMouseMotionListener(this);
setVisible(true);

}

public void mouseMoved(MouseEvent e) { mouseHoverStatus.setText("Mouse Cursor Coordinates => X:"+e.getX()+" | Y:"+e.getY()); }

public void mouseDragged(MouseEvent e) {} }

And a little about regular expressions in java.

The post Top 25 Java Tricks, Tips, and Best Practices appeared first on Creador.

Did you find this article valuable?

Support Pawan Kumar by becoming a sponsor. Any amount is appreciated!