📜 ⬆️ ⬇️

Little Java Tricks. Part 2

In the continuation of the first article I will add a few more strokes about the most common errors and just bad code that you often have to deal with when working with already written projects. I could not stand it in the first part, as these situations are much less common, but since the first part caused a lot of positive feedback, I decided to continue. Thanks to all the commentators, feedback and comments. I will try to avoid mistakes. So let's continue:

Buffered Streams

// InputStream is = new FileInputStream(file); int val; while ((val = is.read()) != -1) { } // InputStream is = new BufferedInputStream(new FileInputStream(file)); int val; while ((val = is.read()) != -1) { } 

It would seem - an obvious truth, is not it? But as someone else's code and experience of interviewing candidates showed, some of the developers definitely do not understand the advantage of buffered streams. Who hasn't figured it out yet - the read () method of the FileInputStream class:
 public native int read() throws IOException; 

Agree, every time to make a system call to count one byte is somewhat wasteful. Actually, in order to avoid this problem, shell buffers were created. All that they do is the first time the system call read () is read, it is slightly larger (depending on the specified buffer size, which is 8 kb by default) and the next time that read () is read, the data is already read from the buffer. Productivity gains - by an order. System calls, in fact, are not always bad, for example:
 System.arraycopy(src, srcPos, dest, destPos, length); 

In the case of copying an array, the system method will be much faster implemented in java. And yet - read the data in portions, rather than bytes, it also allows you to decently save.

Enum vs string

 // String status = plan.getStatus(); if (status.equals("draft")) { //do stuff } else if (status.equals("submitted")) { //do stuff } // PlanStatus status = plan.getStatus(); if (status == PlanStatus.DRAFT) { //do stuff } else if (status == PlanStatus.SUBMITTED) { //do stuff } 

Use Enum for predefined model states where possible. This not only simplifies the understanding of the code, but also speeds up the process of comparing these states. Comparison by reference is definitely an order of magnitude faster than aligning strings or other objects. However, in this case there is one big minus - the cost of supporting the application increases, this becomes especially noticeable when you need to add, delete or change one of the existing states. But if this is unchanged properties, like the month of the year, then feel free to use the listing.

ArrayList vs HashSet

Carefully approach the issue of data storage in collections. Very often, Set is used where the list can be dispensed with, and the list is where the array can be dispensed with. For example, in classes that are mapped on database tables. Avoid this, build the right dependencies and correct queries. This will allow you to save some memory, because it is not a secret to anyone that HashSet is implemented on a HashMap, and HashMap in turn uses the internal class Entry, which in addition to the key and value also stores the hash and a link to the next Entry object. In addition, the hash is constantly calculated as it is added, which can be expensive for complex objects.
')
Data reading

 // byte[] fileBinaryData = readFile(filepath); // InputStream fileStream = readFile(filepath); 

What is wrong with these innocent lines? Yes, in general, nothing, except for the fact that we do not know the size of the file that we read. Instead of a file, there can be anything — an open socket that accepts data, data from a post request, everything ... In general, try not to read everything into an array of bytes, you simply may not have enough memory. Therefore, be careful with the size of any data. Try to process and forward the data in parts. And always keep track of the size of user data and, if possible, limit it.

Log field

 // private Logger logger = Logger.getLogger(Plan.class); // private static final Logger logger = Logger.getLogger(Plan.class); 

Using log in class? Always define the log variable as static final. First: you will never have problems when trying to serialize and deserialize an object. Secondly: initialization occurs only 1 time, instead of constant initialization when creating objects of a class.

Fields initialization

 // class Plan { private String name = null; private Boolean isNew = false; private Set<Document> documents = new HashSet<Document>(); } // class Plan { private String name; private Boolean isNew; private Set<Document> documents; } 

Try not to initialize the class fields prematurely, except when you are very confident about this. Still, for these purposes you have a constructor. In case of explicitly specifying values ​​for class fields, they will be initialized before calling the constructor, which incurs additional costs in cases where you do not need to use initialized values, for example, when you immediately set up other values ​​for initialized fields after creating the object. Well, do not forget that the class fields are always initialized with default values.

Empty String

 // if (name.equals("")) { // if (name.isEmpty()) { 

If you need to check if a string contains an empty value, use the isEmpty () method. Why not equals ()? It is corny slower. If you look at its implementation for the string, you will immediately understand everything. Do not be surprised, many developers still do not know about this method.

Object [] vs custom Class

 // Object[] data = new Object[3]; data[0] = row.getUserCount(); data[1] = row.getOwnerCount(); data[2] = row.getLocations(); return data; // RowResult data = new RowResult(); data.setUserCount(row.getUserCount()); data.setOwnerCount(row.getOwnerCount()); data.setLocations(row.getLocations()); return data; 

The code with Object is completely unreadable when you have to work with the return value in another place. Ie, in order to understand what the return value holds in itself, you need to return to the call class and read the comments to the method, if, of course, they exist, and if you don’t have a good look at the code, that is not very effective. Actually, I myself sometimes sin when I am in a hurry. This can be reconciled if it is very rare, but, nevertheless, in such situations it is better to create a new class. Make life easier for those who come after you.

Anonymous Classes

Anonymous classes are a great feature, but don't push them into all places of your application just because it will save you a minute of time. The code with anonymous classes is read much more difficult and difficult for perception. It is better, of course, to make it into separate classes, except when an anonymous class is very appropriate.

Comparison order

 // if (name.equals("broadcast")) { // if ("broadcast".equals(name)) { 

This method allows you to get rid of unnecessary null checks. But if you follow the rules from the first article, then there is no need for this method.

findings

Yes, much of what is written is more obvious than the obvious. But if so, where does all this come from project to project? This article is by no means a guide to improving the performance of your application. This is just a good, correct style. Hope this helps you.

Source: https://habr.com/ru/post/132374/


All Articles