Effective JavaJava is a must read. If you follow the principles of this article to the letter and judge your code by the quality of your API, you will greatly improve your code quality.
The following content only records the things I sorted out myself, or I suggest reading the original. Some instructions have been deliberately omitted to focus the point. It’s kind of a summary.
1. Consider using static factory methods instead of constructors
Example:
ValueOf (" 1 "), Boolean. ValueOf (" true "), and so on.Copy the code
Advantage:
-
Readable (method name)
-
Performance (not necessarily object creation)
-
Flexibility is high
Here’s a look at the three advantages.
readable
New Point(x,y) and point.at (x,y), point.origin (). The constructor sees only two parameters, which are easier to understand.
performance
In some cases, you can instantiate some objects beforehand and call them without changing them. For example, Boolean.
public final class Boolean implements Serializable, Comparable<Boolean> {public static final Boolean TRUE = new Boolean(TRUE); public static final Boolean FALSE = new Boolean(false); public Boolean(boolean var1) { this.value = var1; } public Boolean(String var1) { this(parseBoolean(var1)); } public static Boolean valueOf(Boolean var0) {return var0? TRUE:FALSE; Public static Boolean valueOf(String var0) {return parseBoolean(var0)? TRUE:FALSE; } / /... other code }Copy the code
Flexibility is high
Subclasses can be returned, depending on the case. The equivalent of a more powerful factory. Get the subclass directly from the parent class. This is especially true for utility classes (which provide various apis). Example: Collections.
Public class Collections {// private, typical factory Private Collections() {} public static final List EMPTY_LIST = new EmptyList<>(); Public static final <T> List<T> emptyList() {return (List<T>) EMPTY_LIST; } private static class EmptyList<E> extends AbstractList<E> implements RandomAccess, Serializable {// code} // factory method public static <E> List<E> checkedList(List<E> List, Class<E> type) { Return (List instanceof RandomAccess? new CheckedRandomAccessList<>(list, type) : new CheckedList<>(list, type)); } // subclass 1 static class CheckedRandomAccessList<E> extends CheckedList<E> implements RandomAccess { CheckedRandomAccessList(List<E> list, Class<E> type) { super(list, type); } public List<E> subList(int fromIndex, int toIndex) { return new CheckedRandomAccessList<>( list.subList(fromIndex, toIndex), type); Static class CheckedList<E> extends CheckedCollection<E> implements List<E> {// code}}Copy the code
2. Consider using constructors when there are multiple constructors
This is especially true with Android development. Usually an object with multiple member variables may need to be initialized, and conventional methods need to provide a large number of constructors. Such as:
Public class AlertDialog {private int width; private int height; private String title; private String confirmText; private String denyText; Private AlertDialog(){} public AlertDialog(int width, int height){// } public AlertDialog(int width, int height, String title){ "Sure"); } // Warning box with title, Public AlertDialog(int width, int height, String title, String confirm){width, height, title, confirm, null); } // Header warning box with ok button, Public AlertDialog(int width, int height, String title, String confirm, String denyText){// Set every thing.}}Copy the code
There are multiple styles of warning boxes, and multiple constructors must be provided for ease of call. Otherwise, the user can only use the full constructor when calling, which is error-prone and unreadable. Very inflexible. If you take a different approach, you can solve it, but it takes a lot of experience to handle concurrent cases:
Public class AlertDialog {private int width; private int height; private String title; private String confirmText; private String denyText; Public void setWidth(int width){this.width = width; } // Other set methods}Copy the code
When called, set by calling the set method of each parameter. Here’s the question:
-
concurrent
-
Parameter verification cannot be performed. For example, creating an object with a title but no size is equivalent to creating a warning box with no size.
In Android, a large number of controls use the constructor.
Public class AlertDialog {private int width; private int height; private String title; private String confirmText; private String denyText; // private private AlertDialog(Builder B){width = b.width; height = b.height; / /... if(width==0||height==0) throws new Exception("size must be set"); } public static class Builder {private int width; private int height; private String title; private String confirmText; private String denyText; // Note: return Builder. public Builder setTitle(String title) { this.title = title; return this; } // Other set... public AlertDialog build(){ return AlertDialog(this); }}}Copy the code
You can then set the parameters according to your requirements and verify them when an AlertDialog is actually constructed. Something like this:
New alertdialog.builder ().setTitle(" prompt ").build();Copy the code
In the example above, the exception is successfully thrown.
3. Enhance Singleton with privatized constructors or enumerations.
A Singleton is a class that will be instantiated at most once. Usually, the old way is fine. However, in some advanced cases, Singleton can be broken by using reflection knowledge to access the private constructor.
Public class Elvis{public static final Elvis INSTANCE = new Elvis(); private Elvis(){} }Copy the code
Alternatively, during serialization, the deserialized object is no longer the same object as before (breaking the Singleton), in which case single-element enumerations can be handled.
public enum Elvis{
INSTANCE;
// some methods
}
Copy the code
4. Enhance non-instantiation capabilities with privatized constructors
Some utility classes simply provide capabilities and do not have any properties of their own, so it is not appropriate to provide constructors. However, the missing constructor compiler automatically adds a constructor with no arguments. Therefore, you need to provide a private constructor. A safeguard and comment are added to prevent misuse within the class.
Public class Util{private Util(){// Throw new AssertionError(); }}Copy the code
The downside is that you can’t inherit from this class (subclasses call super()).
5. Avoid creating unnecessary objects
-
Reuse of objects
-
For expensive objects, use object pools
-
Cheap objects, careful use of object pools. Modern JVMS create and destroy cheap objects very quickly, and object pooling is not appropriate at this point.
6. Eliminate expired object references
There are three things that can cause memory leaks:
-
Self-managed memory (when the array size is reduced, pop objects are prone to memory leaks)
-
The cache
-
Listening and callbacks
Self-managed memory
Be careful with the memory you manage, such as:
public class Stack{ private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack(){ elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e){ ensureCapacity(); elements[size++]=e; Public Object pop(){if(size==0) throw new EmptyStackException(); return element[--size]; // Pop out element[size], the object is no longer valid. Cause of memory leak. } private void ensureCapacity(){ if(elements.length==size) elements = Arrays.copyOf(elements, 2*size+1); }}Copy the code
The object that pops up is no longer valid, but the JVM doesn’t know it, so it holds on forever, causing a memory leak.
Solution:
public Object pop(){ if(size==0) throw new EmptyStackException(); elements[size] = null; // Wait for return element[--size]; }Copy the code
The cache
Cached objects are easily forgotten by programmers, and mechanisms need to be put in place to maintain the cache, such as irregularly collecting the cache that is no longer in use (using timers). In some cases, cache reclamation can be achieved using WeakHashMap. Note that WeakHashMap works only if the cache is dependent on the external environment, not the value.
Listen or call back
When using listeners and callbacks, remember to unregister. The best implementation to ensure recycling is to use weak references, for example, saving them only as WeakHashMap keys.
7. Avoid displaying calls to GC
The Java GC has a powerful collection mechanism, so it’s easy to remember: Do not display the call to Finalizer. It can be interpreted as follows:
The JVM is designed for specific hardware, while the program is not designed for specific hardware, so Java code does not solve gc problems well (because it is platform differentiated). Finalizer also has a high performance overhead and should not be used in this regard.
Override equals by following the general convention
-
Reflexivity. x.equals(x) == true
-
Symmetry. Currently, x.equals(y)==true only when y.equals(x)==true
-
Transitivity. If (x.equals (y) && y.e quals (z)), y.e quals (z) = = true
-
Consistency.
-
Is not empty. x.equals(null)==false
Always override hashCode when overriding equals
To ensure that hash-based collections use this class (HashMap, HashSet, HashTable), which is also the general convention for Object.hashcode, hashCode must be overridden when overriding equals.
10. Always override toString
The general convention for the toString method of Object is the description of the Object. Notice When overwriting, if there is a format, please make a comment or return the format strictly.
11. Carefully cover Clone
Consider implementing the Comparable interface
13. Minimize accessibility of classes and members
The goal is decoupling. In simple terms, the priority of the modifier is from large to small, private>protected>default >public. If you design as a private modifier at the beginning of the design, you should check if you have to extend it later in the coding process.
Subclasses override the superclass and do not allow access below the superclass’s access level. (Protected superclass, cannot change to default if subclass overrides.)
Member variables are never allowed to be public. Once set to public, you give up the ability to handle it. This class is not thread-safe. Even if it’s final, it’s not allowed. Unless you want to expose constants through public static final. Member variables always need to be maintained using setters and getters. There is one exception: arrays of non-zero length. This is a source of security breaches.
// Security hole! Public static final Thing[] VALUES = {... public static final Thing[] VALUES = {... }Copy the code
Improvement:
private static final Thing[] PRIVATE_VALUES = {... } / / get at this time is a "constant" public static final List < Thing > VALUS = Collections. UnmodifiableList (arrays.aslist (PRIVATE_VALUES))Copy the code
Another:
private static final Thing[] PRIVATE_VALUES = {... Public static final Thing[] values(){return private_values.clone (); }Copy the code
Use access methods in public classes instead of public member variables (similar to 13)
15. Minimize variability
Composition takes precedence over inheritance
Inheritance is good for code reuse, but avoid cross-package inheritance if possible. In-package inheritance is good design, with files in a package under the control of the same programmer. But inheritance has its limitations: subclasses depend on superclasses. Changes to a superclass can break subclasses. Also, if the superclass is defective, the subclass can suffer from “genetic disease”.
Composition, that is, not extending an existing class, but adding an existing class to the class. The existing class exists as a component in a new class. In this way, only what is needed will be used instead of representing all the methods and member variables of the existing class. The new class can also be called a “wrapper class,” which is the Class design pattern.
17. Either design for inheritance and document it, or forbid it
Interfaces are better than abstract classes
19. Interfaces are only used to define types
Class hierarchy takes precedence over tag classes
21. Use function objects to represent policies
Function arguments can be passed in an object similar to a Listener to use the methods in the Listener. If anonymous arguments are used, a new object is created with each call. You can declare the Listener as a member variable, reuse the same object each time, and use static fields (static variables). Such as the CASE_INSENSITIVE_ORDER field of the String class.
Pay attention to the public number [programmer Bai Nannan] to obtain the end of 2020 summary interview data a set!
22. Give priority to static class members
The purpose of a nested class should be to serve its peripheral classes only, and if it is possible to use it in other environments later, it should be designed as a top-level class. A static class is equivalent to a normal external class that happens to be declared inside a class. Usually the user is: the Calculator. Operation. PLUS, etc. The only difference is that there are two prefixes before “PLUS” to indicate their meaning. A non-static class must exist in an external class object. Do not manually create an internal non-static class object externally: instance.new MemberClass(). It’s very strange.
If the member class does not need to access the enclosing class, add static to make it static, otherwise each instance will contain an extra reference to the enclosing object. This will affect the garbage collection mechanism.
23. Specify the concrete type of a generic type rather than using a native type directly.
For example, you should specify a List rather than recommend using a List directly.
24. Eliminate non-first check warnings
When coding with an IDE, powerful ides will give you warnings while you’re coding. You need to eliminate them as much as possible, or at the very least, be careful about them. Use SuppresWarning with caution. If the IDE tells you that you can resolve the warning by adding this annotation, do not do so. If you must use it, add a comment explaining why.
25. Lists take precedence over arrays
Like generics, arrays have certain drawbacks. List is unrelated to List, and Sub[] is a subclass of Super[].
// Fails at runtime
Object[] objectArray = new Long[1];
objectArray[0] = "I don't fit in"; // throw exception
// won't compile
List<Object> ol = new ArrayList<Long>(); // Incompatible types
ol.add("I don't fit in");
Copy the code
As you can see from the code, with generics, errors are found ahead of time.
26. Give priority to generics
27. Give preference to generic methods
28. Use restricted wildcards to increase API flexibility
PECS, producer-extends, consumer-super.
//public class Stack<E>{ // public Stack(); // public void push(E e); // public E pop(); // public boolean isEmpty(); //} public void pushAll(Iterator<? extends E> src){ for(E e : src) push(e); } public void popAll(Collection<? super E> dst){ while(! isEmpty()){ dst.add(pop()); } } // Get and Put PrincipleCopy the code
All Comparable and Comparators are consumers.
29. Prioritize heterogeneous containers that are type safe
30, Use enum instead of int constant
public enum Apple { FUJI, PIPPIN, GRANNY_SMITH }
public enum Orange { NAVEL, TEMPLE, BLOOD }
Copy the code
Enumerations are very powerful in Java, and when you need a fixed set of constants, enum is much better than int. Code readability, security, etc.
31, Enum uses instance domain instead of ordinal number
// bad solution public enum Ensemble { SOLO, DUET, TRIO, QUARTET, QUINTET, SEXTET, SEPTET, OCTET, NONET, DECTET; public int numberOfMusicians() { return ordinal() + 1; } } // // improvement public enum Ensemble { SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5), SEXTET(6), SEPTET(7), OCTET(8), NONET(9), DECTET(10), TRIPLE_QUARTET(12); private final int numberOfMusicians; Ensemble(int size) { this.numberOfMusicians = size; } public int numberOfMusicians() { return numberOfMusicians; }}Copy the code
Never use Ordinal Numbers to access enums as in the first way; you need to initialize them with arguments in the constructor.
32, replace bitfields with EnumSet
public class Text{
public static final int STYLE_BOLD = 1 << 0; // 1
public static final int STYLE_ITALIC = 1 << 1; // 2
public static final int STYLE_UNDERLINE = 1 << 2; // 4
public static final int STYLE_STRIKETHROUGH = 1 << 3; // 8
public void applyStyles(int styles){
// ...
}
}
//
text.applyStyles(STYLE_BOLD | STYLE_ITALIC);
Copy the code
This is called bitmapping, but there is a better way to pass multiple sets of constants — Enumsets.
Public class Text{public enum Style {BOLD, ITALIC, UNDERLINE, STRIKETHROUGH} Public void applyStyles(Set<Style> styles){//... } } // text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));Copy the code
Use EnumMap instead of ordinal indexes
Do not use the ordinal() method of enum at any time.
Use interfaces to simulate scalable enumerations
35. Annotations take precedence over naming patterns
36. Stick to the Override annotation
37. Check the validity of the parameters
Public methods check parameters and run Exception for parameter exceptions. Private methods check parameters with an assertion assertion.
38. Make protective copies if necessary
Assume that the client of the class will do everything in its power to break the constraints of the class, so you must protect your design. Here is the design of an immutable class.
public Period(Date start, Date end){ this.start = new Date(start); This.end = new Date(end); this.end = new Date(end); if(this.start.compareTo(this.end)>0) throw new IllegalArgumentException(start + " after " + end) }Copy the code
Note: The protective copy is done before checking the parameters to prevent multithreading. Do not use the Clone method for protective copies.
The above method protects against changes to the parameters passed in, but objects obtained by the GET method can still be modified. You can use the following methods to prevent such attacks.
public Date start(){
return new Date(start);
}
public Date end(){
return new Date(end);
}
Copy the code
39. Carefully design method signatures
Be careful with heavy loading
41. Be careful with variable parameters
42, Return a zero-length array or collection instead of null
Null is generally used to indicate that it has not been initialized or processed, and if a method returns NULL, more processing needs to be done on top to prevent NPE.
43. Document all exported API elements
Proper Javadoc documentation requires documentation comments to precede each exported class, interface, constructor, method, and domain. Annotations should be transparent to the implementation and simply describe the conventions between them and the client. Also, side effects of the method should be included.
44. Minimize the scope of local variables
45. For-each takes precedence over for-loops
For-each avoids references to the index variable in the for loop, which is generally unnecessary — increasing the risk of introducing errors and making them difficult to detect once they occur. However, there are three cases where for-each cannot be used (note: these issues are well addressed in JDK1.8).
-
filter
-
conversion
-
Parallel iterative
46. Avoid float and double if you need an exact answer
Floats and doubles are binary floating-point operations that are performed and are designed to use accurate fast approximations over a wide range of values. However, they do not provide a completely accurate calculation (in practical application, results such as X. 99999 are often encountered). In particular, they do not apply to monetary calculations. Such as:
System. The out. Println (1.03-42);Copy the code
The result will be 0.610000000001.
To solve this problem, you need to use BigDecimal. However, there are some problems with this. It is much more cumbersome and slower than normal arithmetic. The latter is usually negligible, but the former can be very uncomfortable. One way to do this is to take the number you need to deal with *10(or more) and use ints, but you need to handle rounding and so on yourself.
47. Basic type takes precedence over basic type of packing
-
Base types have only values, and boxed classes have identities that differ from their values.
-
Base types have only fully functional values, and boxed classes also have non-functional values: NULL. So you might run into an NPE
-
Basic types save space and time
48. Avoid strings if there is a more precise type
-
A string is not a suitable substitute for another value type. For example: int, Boolean, etc
-
Not an appropriate substitute for enumeration types (rule 30)
-
Not suitable for aggregation type
Beware of string concatenation performance
The + operator concatenates multiple strings. But in the case of mass +, the overhead of concatenating n strings is n bungalow time. This is due to the immutability of the string. Use StringBuilder to connect in this case.
50. Reference objects through interfaces
conclusion
Finally, the 2020 interview questions are summarized. The interview questions are divided into 19 modules, which are as follows: Java Basics, Containers, multithreading, reflection, object copy, Java Web, exceptions, Networking, Design patterns, Spring/Spring MVC, Spring Boot/Spring Cloud, Hibernate, MyBatis, RabbitMQ, Kafka, Zookeeper, MySQL, Redis, JVM.
Pay attention to my public number: programmer Bai Nannan, access to the above information.