About This Book
The Definitive Guide to Java Platform Best Practices—Updated for Java 9
Java has changed dramatically since the previous edition of Effective Java was published shortly after the release of Java 6. This Jolt award-winning classic has now been thoroughly updated to take full advantage of the latest language and library features. The support in modern Java for multiple paradigms increases the need for specific best-practices advice, and this book delivers.
As in previous editions, each chapter of Effective Java, Third Edition, consists of several “items,” each presented in the form of a short, stand-alone essay that provides specific advice, insight into Java platform subtleties, and updated code examples. The comprehensive descriptions and explanations for each item illuminate what to do, what not to do, and why.
The third edition covers language and library features added in Java 7, 8, and 9, including the functional programming constructs that were added to its object-oriented roots. Many new items have been added, including a chapter devoted to lambdas and streams.
New coverage includes
- Functional interfaces, lambda expressions, method references, and streams
- Default and static methods in interfaces
- Type inference, including the diamond operator for generic types
- The @SafeVarargs annotation
- The try-with-resources statement
- New library features such as the Optional<T> interface, java.time, and the convenience factory methods for collections
- Think Java (programming, foundational; free) https://greenteapress.com/wp/think-java/
- Think Data Structures (programming, foundational; free) https://greenteapress.com/wp/think-data-structures/
- Effective Java (classic) https://www.amazon.co.uk/Effective-Java-Joshua-Bloch/dp/0134...
- Java Concurrency in Practice (classic) https://www.amazon.co.uk/Java-Concurrency-Practice-Brian-Goe...
- Continuous Delivery in Java (essential) https://www.amazon.co.uk/Continuous-Delivery-Java-Daniel-Bry...
* https://www.amazon.com/Effective-Java-Joshua-Bloch/dp/0134685997/ref=sr_1_1?keywords=effective+java&qid=1556330445&s=gateway&sr=8-1
Yeah, or if not just play around on your own with it for a weekend, it's pretty simple to pick up.
Something else I'd add to that list is dependency injection (which again might be covered under MVC-frameworks if they tell you about Spring).
Also, this is a useful tool for getting to grips with design patterns, and I can't recommend this book enough
Try to follow SOLID principles, from your code focus on Dependency Inversion Principle: Try to depend on abstractions (for example interface Database) and not your current implementation of Database.
I suppose that you should have some enums as unit type for Unit, I suppose you have different kind of Units. I suppose Unit should be abstract or even an interface because always you should have an specific unit (soldier, tank, ...), each kind of Unit should implement some kind of interface with actions (methods) as move, attack. Is not the same to move a soldier than to move a tank.
FileOfUnits.game as other configuration values that you will have I would use a configuration.properties file
Do not forget to test, TDD will do your classes easier to test and you will understand what you want to do before than implementing It.
Use some Control Version and commit/push with useful comments, will be easier to see why you have done some changes, in some days you will not remember why you have written these lines.
I recommend you to read and check in the following order the books: Effective Java and Clean Code
The comments on the question are right: if you only access
value
within thesynchronized
method, then you don't need it to bevolatile
as well. However, in some cases, you may be able to improve performance with double-checked locking.This code is based on some examples shown in Effective Java and Java Concurrency in Practice. Note that this code checks twice to see if
result
isnull
, once outside thesynchronized
block, and once inside. The advantage to this is that you won't need to synchronize if the value already exists. Note that with this strategy,value
must bevolatile
because it is being accessed outside of thesynchronized
block.Rectification on the checked answer:
The
ResultSet
is not a data mapper, from whose link we can easily figure out that the concept data mapper was coined in the context of enterprise application architecture in 2003. Whereas theResultSet
already existed in the late 1990s. One can search for the keyword "since", by means of which one can infer that the earliest version when new features were added is since 1.2(in 1998. Refer to Java version history), meaning most of the old features such as those getters are already in this class before 1998Class list of JDK 1.1.8 is here, where there is already
ResultSet
Moreover, from the aspect of
DriverManager
,Connection
andDriver
, JDBC is not only an application of static factory method but more precisely a standard application of service provider framework, a design pattern introduced in Item 1: consider static factory methods instead of constructors in the book Effective Java:Connection
is the service interfaceDriverManager.registerDriver
is the provider registration APIDriverManager.getConnection
is the service access APIjava.sql.Driver
is the service provider interfaceIt's up to your use-case, as you have already implied. Making your components immutable brings many advantages such as better encapsulation, thread safety, avoiding having invalid state etc.. Of course, in this way you implement a performance hit. But someone with great experience wrote a chapter about this, which I can only recommend:
Effective Java -
Item 50: Make defensive copies when needed.
There he recommends:
and also:
Introduce static factory methods.
Make a call to a proper
super
constructor. Don't pass anynull
s.Don't use
Optional
as a field.this.original = Optional.ofNullable(li);
Consider the Builder Pattern if you have 3+ parameters.
A constructor is supposed to provide initial values. You aren't passing initial values, you are just indicating their absence.
By default,
null
is the initial value for reference types. So, there is no need to reassign a field if the value for it hasn't been given.Readability, maintenance.
I would recommend reading Effective Java by Joshua Bloch:
Creating and Destroying Objects
Item 10: Obey the general contract when overriding equals
Each instance of the class is inherently unique. This is true for classes such as Thread that represent active entities rather than values. The equals implementation provided by Object has exactly the right behavior for these classes.
There is no need for the class to provide a “logical equality” test. For example, java.util.regex.Pattern could have overridden equals to check whether two Pattern instances represented exactly the same regular expression, but the designers didn’t think that clients would need or want this functionality. Under these circumstances, the equals implementation inherited from Object is ideal.
A superclass has already overridden equals, and the superclass behavior is appropriate for this class. For example, most Set implementations inherit their equals implementation from AbstractSet, List implementations from AbstractList, and Map implementations from AbstractMap.
The class is private or package-private, and you are certain that its equals method will never be invoked. If you are extremely risk-averse, you can override the equals method to ensure that it isn’t invoked accidentally:
The
equals
method implements an equivalence relation. It has these properties:Reflexive: For any non-null reference value
x
,x.equals(x)
must return true.Symmetric: For any non-null reference values
x
andy
,x.equals(y)
must return true if and only if y.equals(x) returns true.Transitive: For any non-null reference values
x
,y
,z
, ifx.equals(y)
returnstrue
andy.equals(z)
returnstrue
, thenx.equals(z)
must returntrue
.Consistent: For any non-null reference values
x
andy
, multiple invocations ofx.equals(y)
must consistently returntrue
or consistently returnfalse
, provided no information used in equals comparisons is modified.For any non-null reference value
x
,x.equals(null)
must returnfalse
.Here’s a recipe for a high-quality equals method:
Use the
==
operator to check if the argument is a reference to this object. If so, return true. This is just a performance optimization but one that is worth doing if the comparison is potentially expensive.Use the
instanceof
operator to check if the argument has the correct type. If not, return false. Typically, the correct type is the class in which the method occurs. Occasionally, it is some interface implemented by this class. Use an interface if the class implements an interface that refines the equals contract to permit comparisons across classes that implement the interface. Collection interfaces such as Set, List, Map, and Map.Entry have this property.Cast the argument to the correct type. Because this cast was preceded by an instanceof test, it is guaranteed to succeed.
For each “significant” field in the class, check if that field of the argument matches the corresponding field of this object. If all these tests succeed, return true; otherwise, return false. If the type in Step 2 is an interface, you must access the argument’s fields via interface methods; if the type is a class, you may be able to access the fields directly, depending on their accessibility.
For primitive fields whose type is not
float
ordouble
, use the==
operator for comparisons; for object reference fields, call theequals
method recursively; forfloat
fields, use the staticFloat.compare(float, float)
method; and fordouble
fields, useDouble.compare(double, double)
. The special treatment of float and double fields is made necessary by the existence ofFloat.NaN
,-0.0f
and the analogous double values; While you could comparefloat
anddouble
fields with the static methodsFloat.equals
andDouble.equals
, this would entail autoboxing on every comparison, which would have poor performance. Forarray
fields, apply these guidelines to each element. If every element in an array field is significant, use one of theArrays.equals
methods.Some object reference fields may legitimately contain
null
. To avoid the possibility of aNullPointerException
, check such fields for equality using the static methodObjects.equals(Object, Object)
.Effective Java by Joshua Bloch
Written by someone who worked directly on the language's development. :)
Out of all the Java books I've read over the past 20 years, these probably stuck with me the most:
Edit: Apparently there's a second edition of the refactoring book: [https://toptalkedbooks.com/amzn/0134757599)
Be hungry for and appreciative of feedback.
Get code reviews early and often.
Make small changes with accompanying unit tests.
Favor readability over clever tricks.
Work your way through Effective Java: https://toptalkedbooks.com/amzn/0134685997
Work your way through Concurrency In Practice: https://toptalkedbooks.com/amzn/0321349601
Have fun and keep learning! :)
I don't think there is.
That said, you should think twice before throwing a checked exception. The standard usage for checked exceptions is to signal abnormal conditions that are out of the caller's control, such as:
The rationale being that if the caller can prevent the abnormal condition, it shouldn't be forced to handle it.
You can find more info in the classic Effective Java book (the 3rd edition just came out, btw), especially Item 71 ("Avoid unnecessary use of checked exceptions").
It's rather a design matter and depends on your architecture.
If you have classes with static factory methods, why should you add unnecessary constructors breaking the design just to fit a DI framework?
It's inflexible, thus Spring supports both ways.
Excerpt from Joshua Bloch “Effective Java”:
means "A class/interface that extends
HasWord
." In other words,HasWord
itself or any of its children... basically anything that would work withinstanceof HasWord
plusnull
.In more technical terms,
? extends HasWord
is a bounded wildcard, covered in Item 31 of Effective Java 3rd Edition, starting on page 139. The same chapter from the 2nd Edition is available online as a PDF; the part on bounded wildcards is Item 28 starting on page 134.Update: PDF link was updated since Oracle removed it a while back. It now points to the copy hosted by the Queen Mary University of London's School of Electronic Engineering and Computer Science.
Update 2: Lets go into a bit more detail as to why you'd want to use wildcards.
If you declare a method whose signature expect you to pass in
List<HasWord>
, then the only thing you can pass in is aList<HasWord>
.However, if said signature was
List<? extends HasWord>
then you could pass in aList<ChildOfHasWord>
instead.Note that there is a subtle difference between
List<? extends HasWord>
andList<? super HasWord>
. As Joshua Bloch put it: PECS = producer-extends, consumer-super.What this means is that if you are passing in a collection that your method pulls data out from (i.e. the collection is producing elements for your method to use), you should use
extends
. If you're passing in a collection that your method adds data to (i.e. the collection is consuming elements your method creates), it should usesuper
.This may sound confusing. However, you can see it in
List
'ssort
command (which is just a shortcut to the two-arg version of Collections.sort). Instead of taking aComparator<T>
, it actually takes aComparator<? super T>
. In this case, the Comparator is consuming the elements of theList
in order to reorder the List itself.Writing wrapper classes for every single parameter, just to ensure that someone doesn't make confusion about the order of parameters sounds pretty extreme, and it is cumbersome to use.
If
clientCode
ordataVersion
can fit into smaller datatypes such asbyte
orshort
, you can use that for distinction. If some of these values have a specified value range (e.g. from 1 to 100.000), use a compile-time check within a method and throw an exception if the supplied value doesn't fit (which can happen in case when the caller misplaced parameters).In case that you add more
int
parameters, your concern becomes more justified. In that case write only a single wrapper class that will hold all parameters:By using explicit getters and setters, you are forcing caller to take care about the supplied values. Bonus - you can add default values to some of the parameters, if needed. Method signature is now
int generateId(Input input)
.This is a good practice documented in Joshua Bloch's Effective Java.
https://www.amazon.co.uk/Effective-Java-Joshua-Bloch/dp/0134...