📜 ⬆️ ⬇️

Java for every day and not only. Recommendations for use

Hello!

Your attention is invited to the translation of the article already known in Habré author. This time, he shares his own vision of how often you need to apply certain features of the Java language in your daily development.



image
Java is a language with powerful standard features, but "Big power imposes a lot of responsibility . " I saw a lot of java-code, in which the “rare” properties of the language were excessively (and often incorrectly) used, while the fundamentals of the fundamentals were almost completely ignored. These observations and stimulated the writing of the article.
')
This is not a list of required features of a language by every programmer. Quite the contrary. I divided them into 3 groups: " for everyday use ", " for occasional use " and " only for frameworks and libraries! ". The rule is simple: if you understand that you use these properties more often than recommended, then most likely your code is developing in the wrong way. If, on the contrary, you rarely use any properties than I recommend, it means that you miss some interesting and important features of the language.

Please note that I’m talking about developing typical server-side business applications (JVM, JDK, that's all) and I don’t give recommendations on any frameworks.

For everyday use


Classes, interfaces, packages
Yes, place your code in classes. Ever since your studies, you probably remember that a class is data and methods for working with this data. A class that contains only data is called a "structure." A class in which only methods essentially logically unites some functionality. Use interfaces where necessary. But think twice before creating an interface with a single implementation. Maybe we should get rid of the middleman? Finally, place the classes and interfaces in packages, remembering to follow the naming conventions .

Static methods
Do not be afraid of them, but use them only as utility methods that do not imply the presence of a state. No business logic in static methods!

ExecutorService, thread pool
It is necessary to understand and properly use pools of threads , queues and objects of the type Future <T> Do not reinvent the wheel by implementing your own pools. They should come to your head first when you hear about Producer-Consumer

Atomic family- *
Do not use synchronized to read / modify counters and references. The Atomic-* family is very efficiently implemented on the basis of “comparison with exchange”. Make sure that you understand the guarantees that these classes provide.

Design Patterns
Technically, they are not part of the Java language, but I must mention them in view of their importance. You should know, understand and use them freely, but within reasonable limits. (As well as interfaces, by the way). Gangs of four and corporate applications should be widely represented in your code. But their use should be subject to the needs of your application, and not vice versa.

Standard collections, including multi-threaded
You absolutely need to know and use the built-in collections, to understand the difference between List , Map and Set . Using thread safe implementations should also not be a problem. You need to know the basic characteristics of performance and have an idea of ​​the details of implementations. Add to this the knowledge of various implementations of BlockingQueue . Parallel computations are already complicated, you need to use the existing means of the language, and not reinvent your bikes.

Embedded annotations
They are already here and it is for a long time, so feel free to use @Override and do not forget about @Deprecated

Exceptions
Use unchecked exceptions ( RuntimeExceptions ) to report errors and abnormal system conditions when an explicit response to what is required is required. Learn to live with checked exceptions. Learn to read stack traces.

try-with-resources
Get to know this wonderful design . Implement AutoCloseable if your class needs to free up resources after completing its work.

Blocking I / O
Use the classes Reader / Writer , InputStream / OutputStream . Understand the differences between them, feel free to use buffering and other decorators.

This list "for every day" ends. If you have not heard about something at all, or have heard the edge of the ear - study, you will definitely need it.

For occasional use


The following Java properties can and should be used, but without fanaticism. If you have time to apply something from this section before lunch every day, there is definitely something wrong with the architecture of your application. I repeat - from the point of view of the development of the back-end, these things are useful, but rarely.

Inheritance and abstract classes
Honestly, I rarely use inheritance and will not say that I miss him a lot. Polymorphism is very flexible implemented on the basis of interfaces, especially with all the shortcomings of abstraction in Java ( * ). I also prefer composition to inheritance . Too large hierarchies generate hard-to-maintain code.
image

Regular expressions
Some programmers, when they encounter a problem, think, “Oh, I will use regular expressions!” And they get two problems. A world without regular expressions would be much more boring and cumbersome. They are great for parsing regular sets ( other than HTML ), but then again - it's very easy to overdo with them. If you use regular expressions all day, you have chosen the wrong tool. Hit of all time:
 public static boolean isNegative(int x) { return Integer.toString(x).matches("-[0-9]+"); } 

Semaphore , CountDownLatch , CyclicBarrier , etc.
These classes, of course, are an order of magnitude more useful than the notorious wait()/notify() couple. But they also do not protect you from errors when using multithreading. If you often use this mechanism for synchronization - it's time to look in the direction of thread-safe collections or specialized frameworks.

Parameterized types (generics) in user code
In general, using built-in collections and other data types that support parameterization is commonplace for a programmer. But here I am talking about using parameterization in your own code when your methods accept or return generic types. For example:
 public <T, F> ContractValidator<T extends Contract> T validate(Validator<T>, F object) 

Sometimes it is necessary, but again - it is important not to bend the stick. Static typing and safe type conversion will always be at the forefront, but over parameterization is best avoided.

Script languages ​​in JVM
Did you know that the JDK has a built-in javascript interpreter ? And that you can connect other languages ​​on the fly, like Groovy and JRuby? In an age of rapidly changing markets, sometimes there is not enough time even to redeploy an application, and introducing a small script with the ability to edit it by the end user is a good idea. But remember that if the number of scripts exceeds 1% of the total number of lines in the system, you need to be prepared for support difficulties.

Java nio
It is difficult to use it properly and even harder to really benefit from it. Sometimes you have to use it to get the most out of performance and scaling. But it is better to use specialized libraries, all the more so in most cases, normal I / O is sufficient.

synchronized
No need to abuse it for a simple reason - the more such blocks, the more often they are executed and the lower the performance. Plus, you always have to be sure that the object is a mutex. Better use thread-safe collections and Atomic-* .

So, I consider the properties of the language listed in this section to be important and useful, but not necessary for everyday use. If you use them all the time, this is a sign of an overloaded architecture ... or an inexperienced developer. The ability to simplify comes with experience. But if your system has any special requirements, then it's time to move on to the third group.

Only for developers of frameworks and libraries!


To use frameworks and libraries effectively, you need to understand the principles of the following language properties. StackOverflow is filled with questions, the answers to which can be easily found in the source code of the frameworks themselves. But “understanding” does not necessarily mean “using.” All these things are quite low-level and complex, and even in small quantities can cause a considerable headache.

sockets
Yes, yes, you heard right, namely sockets. You need to understand how the TCP / IP stack, sessions, and streams work, to be able to correctly interpret data. But avoid direct work at the network level. There are hundreds of high-level libraries for HTTP, FTP, NTP, SMB, e-mail ... take the same Apache Commons net . You hardly suspect how difficult it is to write a decent HTTP client or server. And if you need a server for some kind of proprietary protocol, I recommend reading Netty

reflection
In the application code there is no place to work at the level of the internal structure of classes and methods. It is vital for frameworks, but I absolutely do not need it. Reflection makes your code low-level, insecure, and just ... unpleasant. AOR solves most problems. I would even say that simple work with instances of type Class<?> Already “smells bad”.

dynamic proxies and bytecode
Proxy is great, but, like reflection, it’s better to leave work with it to frameworks and libraries. Proxy is the basis for building lightweight AOR. If your business application works directly with bytecode ( ** ) (for example, through ASM or CGLIB ), you only need to pray for you.

classloaders
... and everything connected with them - into the furnace! again - you need to understand how they work, hierarchy, bytecode, etc. But if you write your bootloader, this is the road to hell. Not that it was so difficult, but why? Let the application server do this.

Object.clone ()
I do not remember if I have ever used this method in my entire practice. And, I remembered, I definitely never used it! And I can't even think of why I might need it. I prefer explicit copy constructors, and even better - immutable objects. Do you need exactly clone? Looks like someone stuck in the nineties ...

native methods
In the JDK, you can find several of these, in particular, the function of calculating the sine. But Java has long been not that sluggish as before, quite the opposite. And I cannot think of which tasks standard or third-party libraries cannot solve. Plus, native methods are difficult in their own right, generate a lot of low-level errors, especially in terms of working with memory.

handwritten collections
correctly implement the collection in accordance with all contracts of the original JavaDoc (suddenly) is not an easy task Hibernate uses its own implementations, but why you may need them - I don't know.

Threadlocal
The frameworks and libraries use this technique quite often, but you should avoid it for two reasons. The first is that a kind of semi-global variable is often hidden under the mask of ThreadLocal. This makes it difficult to understand and test the code. The second - ThreadLocal causes a memory leak in case of incorrect cleaning. For example, we read here , here , here and here, and so on ...

WeakReference and SoftReference
These classes are fairly low-level and are well suited for implementing caches that are tightly integrated with the garbage collector. Fortunately, there are many open-source libraries for similar caches, so there is no need to write one more on your own. It is enough to know that there are such classes and imagine how they work.

Packages com.sun.* And sun.* , Especially sun.misc.Unsafe
Stay away from the peat bogs of these packages, because ... yes, just away and all! These are purely special, undocumented classes with no guarantee of future backward compatibility. Just imagine that they are not. And why would you need Unsafe ?

Actually, that's all. Of course, all this is my absolute IMHO. If you feel that something is not in its place, or I have forgotten about something significant, I ask you in the comments so that in the future I can compile some kind of reference guide for conducting a code-review or for help in evaluating a project.




(*) a more accurate translation of the expression " a painful lack of traits in Java " is welcome
(**) I didn’t master the passage about Mockito either

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


All Articles