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.

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, packagesYes, 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 methodsDo 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 poolIt 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 PatternsTechnically, 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-threadedYou 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 annotationsThey are already here and it is for a long time, so feel free to use
@Override
and do not forget about
@Deprecated
ExceptionsUse 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-resourcesGet to know
this wonderful design . Implement
AutoCloseable if your class needs to free up resources after completing its work.
Blocking I / OUse 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 classesHonestly, 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.
Regular expressionsSome 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 codeIn 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 JVMDid 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 nioIt 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.
socketsYes, 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
NettyreflectionIn 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 bytecodeProxy 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 methodsIn 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 collectionscorrectly 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.
ThreadlocalThe 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
SoftReferenceThese 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