Last article: Effective.Java

49. Make defensive copies if necessary

If the client will try to destroy the security of the class, defensive copy is any client wind and rain, I yiyi immovable efforts

 
public final class Period {
	private final Date start;
	private final Date end;
	public Period(Date start,Date end) {
		if(start.compareTo(end) > 0) {throw new IllegalArgumentException(start + " after " + end);
		}
		this.start = start;
		this.end = end;
	}
	
	public Date start(a){
		return start;
	}
	
	public Date end(a){
		return end;
	}
	//remainder omitted
}
Copy the code

In the example above time is immutable. The Date class itself, however, is mutable

Date start = new Date();
Date end = new Date();
Period period = new Period(start, end);
end.setYear(78);
System.out.println(period.end());							
Copy the code

We can modify the constructor

 // With the new constructor, the previous attack will not affect the Period instance
public Period(Date start, Date end) {
	this.start = new Date(start.getTime());
	this.end = new Date(end.getTime());
	if (this.start.compareTo(this.end) > 0)
		throw new IllegalArgumentException(this.start + " after " + this.end);
}
Copy the code

Although the replacement constructor successfully defended against the previous attack, the Period instance can still be modified because its accessor provides access to its mutable internal structure

// Second attack on the internals of a Period instance
Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
p.end().setYear(78); // Modifies internals of p
Copy the code

To defend against the second attack, simply modify the accessor to return a defensive copy of the mutable internal word property:

public Date start(a) {
return new Date(start.getTime());
}
public Date end(a) {
return new Date(end.getTime());
}
Copy the code

In summary, if a class has mutable components that are retrieved or returned from its clients, the class must copy those components defensively. If the cost of copying is too high and the class trusts its clients not to improperly modify the component, the defensive copy can be replaced with a document that Outlines the client’s responsibility not to modify the affected component

Race Condtions

According to the insecure class above, the method competition conditions are generally divided into two kinds of vulnerabilities

  • Time of Check Versus Time of Use (TOCTOU)

The interval between the check and the actual write is a Race Condition that can be exploited. Malware can replace the files that the user is checking with its own files, thus compromising data.

  • Signal Handling

In the process of signal processing, it can be interrupted by the processing of another signal at any time. If another signal arrives in the process of processing a signal, the process will be immediately interrupted, so that the system will be in an unknown state.

50. Carefully design method signatures

  • Choose method names carefully, likefangfa1.fangfa2That’s the kind of name you shouldn’t have
  • Too many methods are also bad, especially in interfaces
  • Avoid long parameter lists, usually four or less

There are three techniques to avoid excessively long parameters. One is to split a method into multiple methods, each of which requires only a subset of the parameters. Another is to create helper classes to hold the array of parameters, which are usually static member classes

  • The interface is preferred to the class for the type of the parameter
  • Use two elements to enumerate types in preference to Boolean arguments

51. Use overloads wisely and judiciously

The choice between the overloaded method is static, while the choice between the overridden method is dynamic. Method overloading cannot be automatically scheduled to the appropriate method based on the runtime type, as shown in the article

public class CollectionClassifier {
	public static String classify(Set
        s) {
		return "Set";
	}

	public static String classify(List
        lst) {
		return "List";
	}

	public static String classify(Collection
        c) {
		return "Unknown Collection";
	}

	public static void main(String[] args) { Collection<? >[] collections = {new HashSet<String>(), new ArrayList<BigInteger>(),
				new HashMap<String, String>().values() };
		for (Collection<?> c : collections)
			System.out.println(classify(c));
	}
}

// The program prints the Unknown Collection three times. In fact, we want to print the Set, then the List and the Unknown Collection string
Copy the code

After modifying this program

public static String classify(Collection
        c) {
     return c instanceof Set ? "Set" :
     c instanceof List ? "List" : "Unknown Collection";
}
Copy the code

A safe and conservative policy is to never export two overloads with the same number of arguments, for example, consider the ObjectOutputStream class. It has a variation of its write method for each base type and several reference types. These variants have different names, such as writeBoolean(Boolean), writeInt(int), and writeLong(long), instead of overloading the write method. Another advantage of this naming scheme over overloading is that you can provide names for read methods, such as readBoolean(), readInt(), and readLong(). The ObjectInputStream class actually provides such a reading method.

52. Use variables wisely and judiciously

A variable argument can accept zero or more arguments of a specified type, usually with… said

// Takes a list of int types and returns their sum
static int sum(int. args) {
int sum = 0;
for (int arg : args)
sum += arg;
return sum;
}

Copy the code

53. Return an empty array or collection. Do not return NULL

If the method returns NULL, the client must include special case code to handle the possibility of a NULL return, unless we can prove that a NULL return is impossible, and if the client ignores the possibility of a NullPointerException

54. Be wise and prudent to return Optional

An Optional container that represents an immutable class. A non-empty containing value is called present

There may be some cases where you can’t return T, but you can declare it as an Optional return. This allows the method to return an empty result, indicating that it cannot return a valid result. Methods that return Optional are more flexible, easier to use than methods that throw exceptions, and less error-prone than methods that return NULL.

public static <E extends Comparable<E>> E max(Collection<E> c) {
		if (c.isEmpty())
			throw new IllegalArgumentException("Empty collection");
		E result = null;
		for (E e : c)
			if (result == null || e.compareTo(result) > 0)
				result = Objects.requireNonNull(e);
		return result;
	}
Copy the code

The above example throws an exception if the set is empty. We can replace it with Optional

.

public static <E extends Comparable<E>> Optional<E> max(Collection<E> c) {
		if (c.isEmpty())
			return Optional.empty();
		E result = null;
		for (E e : c)
			if (result == null || e.compareTo(result) > 0)
				result = Objects.requireNonNull(e);
		return Optional.of(result);
	}
Copy the code

Option.empty () returns an empty Optional, option.of (value) returns an Optional containing the given non-null value. Passing NULL to optional. of(value) is a programming error, and this method throws an exception

Matters needing attention
  • Never return a null value by returning Optional
  • Container types, including collections, maps, streams, arrays, and Optional, should not be wrapped in Optional
  • Optional of the base type of boxing should never be returned.
When to use Optional

Methods that return Optional should be declared in cases where the result may not be returned and where the client must perform special processing without returning the result. (Returning Optional is not cost-free. Optional is the object that must be allocated and initialized, and reading values from Optional requires additional circuitry.

55. Document all exposed API elements

The Java programming environment simplifies this task by using the Javadoc utility. Javadoc automatically generates API documentation from source code using a special format of documentation annotations (often called DOC annotations).

Swagger now automatically generates documentation that Maven relies on


<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.61.</version>    
</dependency>    

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.61.</version>
</dependency>    
Copy the code

56. Minimize the scope of local variables

By minimizing the scope of local variables, you improve the readability and maintainability of your code and reduce the likelihood of errors

use

The most powerful technique for minimizing the scope of a local variable is to re-declare it where it is first used. It means use it there and declare it there

Almost every local variable declaration should contain an initializer

If the contents of the loop variable are not needed after the loop terminates, the for loop is preferred over the while loop.

57. For-each loops are superior to traditional for-loops

For-each loops (officially called “enhanced for statements”) eliminate clutter and error opportunities by hiding iterators or index variables

You can’t usefor-eachwhen
  • Destructive filtering — If you need to traverse a collection and remove selected elements, you need to use an explicit iterator so that its remove method can be called. You can usually avoid explicit traversal by using the removeIf method in the Collection class added in Java 8.
  • Conversion – If you need to iterate through a list or array and replace some or all of its elements’ values, you need a list iterator or array index to replace the elements’ values.
  • Parallel iteration — If multiple collections need to be traversed in parallel, then iterators or index variables need to be explicitly controlled so that all iterators or index variables can be synchronized (as inadvertently illustrated in the faulty Card and DICE example above).

58. Know and use libraries

By using the standard library, you can leverage the knowledge of the experts who wrote it and the experience of those who have used it before.

With each major release, many features are added to the library, and it’s worth learning about these new features.

ThreadLocalRandom

JDK 7 provides concurrent generation of random numbers, which can solve multiple threads contention. ThreadLocalRandom is not instantiated directly with new, but uses its static method current() for the first time

ThreadLocalRandom t=ThreadLocalRandom.current(); System.out.println(t.nextInt(50)); // Generate random numbers from 0 to 50, excluding 50 system.out.println (t.nextint (30, 50)); // Generate random numbers ranging from 30 to 50, excluding 50Copy the code

Random: generates a pseudorandom number (with the same seed, the same Random number is generated

59. Avoid using float and double classes if precise answers are required

type

The float and double types are primarily used for scientific and engineering calculations. They perform binary floating point arithmetic, which is carefully designed to provide accurate approximations quickly over a wide range. However, they do not provide accurate results and should not be used where accurate results are required. The float and double types are particularly unsuitable for monetary calculations because it is impossible to accurately represent 0.1 (or any negative power of 10) as float or double.

Money operations are generally calculated using BigDecimal,int, and long, but there are two problems with using BigDecimal. One is that the computation is inconvenient compared to the original arithmetic type, and finally, it is slow. However, it has complete rounding control, and when performing operations that require rounding, you can choose from eight rounding modes

60. Primitive data types are superior to wrapper classes

Java has a two-part type system consisting of primitive types (such as int, double, and Boolean) and reference types (such as String and List). Each base type has a corresponding reference type, called a wrapper type.

The difference between the base type and the wrapper type

  • Primitive types only know their values, and wrapper types have different identifiers than their values
  • The package type can containnullThe basic type does not work
  • The basic type saves more time and space than the wrapper type

You cannot use == for wrapper types

// The following program will report an error. Fixing this problem is as simple as declaring I as int instead of Integer.
public class Unbelievable {
  static Integer i;
  public static void main(String[] args) {
     if (i == 42)
      System.out.println("Unbelievable"); }}Copy the code

It throws a NullPointerException when it evaluates the expression I ==42. The reason for this exception is that I is an Integer, not an int, and, like all nonscalar object reference fields, its initial value is NULL. When the program evaluates the expression I ==42, it is comparing an Integer with an int. When you mix primitive and wrapper types in an operation, the wrapper type is unpacked automatically, and a null pointer exception is reported if an empty object is unpacked automatically

When to use wrapper classes

  • The first is as an element, key, and value in a collection. Primitive types cannot be placed in collections
  • Use the wrapper type as the type parameter
  • The wrapper type must be used when the reflection method is called
To be continued…