Summary of classic usage of Java

  • 2020-05-05 11:14:05
  • OfStack

In Java programming, there are some things you can't just learn from the language specification or the standard API documentation.

One, implement

1, now equals()  


class Person {

 String name;

 int birthYear;

 byte[] raw;

 

 public boolean equals(Object obj) {

  if (!obj instanceof Person)

   return false;

 

  Person other = (Person)obj;

  return name.equals(other.name)

    && birthYear == other.birthYear

    && Arrays.equals(raw, other.raw);

 }

 

 public int hashCode() { ... }

}

The parameter must be of type Object, not a peripheral class. foo.equals(null) must return false, not NullPointerException. (note that null instanceof any class always returns false, so the code above can run.) Comparison of primitive type fields (e.g., int) USES ==, and comparison of array fields of primitive types USES Arrays.equals (). When overwrites equals(), remember to overwrite hashCode() accordingly, consistent with equals().

2, now hashCode()


class Person {

 String a;

 Object b;

 byte c;

 int[] d;

 

 public int hashCode() {

  return a.hashCode() + b.hashCode() + c + Arrays.hashCode(d);

 }

 

 public boolean equals(Object o) { ... }

}

When x and y have x.equals (y) == true, you must ensure that x.hashCode () == y.hashCode (). according to the converse statement, if x.hashCode()! = y.hashCode (), then x.equals (y) == false must be true. You don't need to guarantee that when x.equals (y) == false, x.hashCode ()! = y. hashCode (). However, if you can make it as valid as possible, this will improve the performance of the hash table. The simplest legal implementation of hashCode() is simply return 0; While this implementation is correct, it causes the HashMap data structures to run slowly.

3, compareTo()  


class Person implements Comparable<Person> {

 String firstName;

 String lastName;

 int birthdate;

 

 // Compare by firstName, break ties by lastName, finally break ties by birthdate

 public int compareTo(Person other) {

  if (firstName.compareTo(other.firstName) != 0)

   return firstName.compareTo(other.firstName);

  else if (lastName.compareTo(other.lastName) != 0)

   return lastName.compareTo(other.lastName);

  else if (birthdate < other.birthdate)

   return -1;

  else if (birthdate > other.birthdate)

   return 1;

  else

   return 0;

 }

}

Always implement the generic version Comparable instead of the original type Comparable. Because this can save code and reduce unnecessary trouble.
I only care about the plus and minus signs (negative/zero/positive) that return the results. Their size doesn't matter.
The implementation of Comparator.compare() is similar to this.

4, clone()


 class Values implements Cloneable {

 String abc;

 double foo;

 int[] bars;

 Date hired;

 

 public Values clone() {

  try {

   Values result = (Values)super.clone();

   result.bars = result.bars.clone();

   result.hired = result.hired.clone();

   return result;

  } catch (CloneNotSupportedException e) { // Impossible

   throw new AssertionError(e);

  }

 }

}

USES super.clone () to make the Object class responsible for creating new objects. The base type fields have been copied correctly. Again, we don't need to clone immutable types like String and BigInteger. manually makes a deep copy of all non-primitive type fields (objects and arrays) (deep copy). implements Cloneable's class, and the clone() method should never discard CloneNotSupportedException. Therefore, you need to catch the exception and ignore it, or wrap it with an undetected exception (unchecked exception). It is both possible and legal for to manually implement the clone() method without using the Object.clone () method.

Ii. Preventive testing

1. preventive test (Defensive checking


int factorial(int n) {

 if (n < 0)

  throw new IllegalArgumentException("Undefined");

 else if (n >= 13)

  throw new ArithmeticException("Result overflow");

 else if (n == 0)

  return 1;

 else

  return n * factorial(n - 1);

}

do not assume that input values are positive, small enough, and so on. These conditions are explicitly detected. A well-designed function should perform correctly for all possible input values. Make sure that all situations are taken into account and that there is no incorrect output (such as an overflow).

2. Preventive detection object


int findIndex(List<String> list, String target) {

 if (list == null || target == null)

  throw new NullPointerException();

 ...

}

do not assume that the object parameter will not be null (null). Explicitly detect this condition.

3, preventive detection array index  


void frob(byte[] b, int index) {

 if (b == null)

  throw new NullPointerException();

 if (index < 0 || index >= b.length)

  throw new IndexOutOfBoundsException();

 ...

}

Don't think that all the array indexes you give won't cross the line. You want to explicitly detect it.

4. Preventive detection array interval


void frob(byte[] b, int off, int len) {

 if (b == null)

  throw new NullPointerException();

 if (off < 0 || off > b.length

  || len < 0 || b.length - off < len)

  throw new IndexOutOfBoundsException();

 ...

}

Do not think that the given array interval (for example, starting with off and reading len elements) is not overstepping the bounds. You want to explicitly detect it.

array

1, fill the array element
cycle:  


// Fill each element of array 'a' with 123

byte[] a = (...);

for (int i = 0; i < a.length; i++)

 a[i] = 123;

 (preferred) ways to use the standard library: 

Arrays.fill(a, (byte)123);

2, copy a range of array elements
usage cycle:


// Copy 8 elements from array 'a' starting at offset 3

// to array 'b' starting at offset 6,

// assuming 'a' and 'b' are distinct arrays

byte[] a = (...);

byte[] b = (...);

for (int i = 0; i < 8; i++)

 b[6 + i] = a[3 + i];

 (preferred) ways to use the standard library: 

System.arraycopy(a, 3, b, 6, 8);

3, resize the array
usage cycle (scale up) :  


class Person {

 String a;

 Object b;

 byte c;

 int[] d;

 

 public int hashCode() {

  return a.hashCode() + b.hashCode() + c + Arrays.hashCode(d);

 }

 

 public boolean equals(Object o) { ... }

}

0

Use cycle (reduce size) :


class Person {

 String a;

 Object b;

 byte c;

 int[] d;

 

 public int hashCode() {

  return a.hashCode() + b.hashCode() + c + Arrays.hashCode(d);

 }

 

 public boolean equals(Object o) { ... }

}

1

(preferred) way to use the standard library:


class Person {

 String a;

 Object b;

 byte c;

 int[] d;

 

 public int hashCode() {

  return a.hashCode() + b.hashCode() + c + Arrays.hashCode(d);

 }

 

 public boolean equals(Object o) { ... }

}

2

4. Wrap four bytes (packing) into one int


int packBigEndian(byte[] b) {

 return (b[0] & 0xFF) << 24

    | (b[1] & 0xFF) << 16

    | (b[2] & 0xFF) << 8

    | (b[3] & 0xFF) << 0;

}

 

int packLittleEndian(byte[] b) {

 return (b[0] & 0xFF) << 0

    | (b[1] & 0xFF) << 8

    | (b[2] & 0xFF) << 16

    | (b[3] & 0xFF) << 24;

}

5, decompose int (Unpacking) into 4 bytes  


class Person {

 String a;

 Object b;

 byte c;

 int[] d;

 

 public int hashCode() {

  return a.hashCode() + b.hashCode() + c + Arrays.hashCode(d);

 }

 

 public boolean equals(Object o) { ... }

}

4

Always use the unsigned right shift operator (>) > > ) wrap bits (packing), do not use the arithmetic shift operator (>) > ).

The above is the entire content of this article, I hope to help you with your study.


Related articles: