20のJavaベストプラクティス

Mar 09 2023
コードの品質を向上させるのに役立つ Java のベスト プラクティスのいくつか。1 - 可能な場合は、プリミティブ ラッパーよりもプリミティブを優先します。

コードの品質を向上させるのに役立つ Java のベスト プラクティスのいくつか。

1 - 可能な場合は、プリミティブ ラッパーよりもプリミティブを優先します。

Long idNumber;
long idNumber; // long takes less memory than Long

int birthYear;
short birthYear; // better because birth year can not be more than 32767


int personRunningSpeedKmHour;
byte personRunningSpeedKmHour; // better because a person can not have
// more than 127 km/h as speed

public boolean isOdd(int num) {
return (num & 1) != 0;
} 
// best way to check the oddity of a number

String name = null; // redundant
int speed = 0; // redundant
boolean isOpen = false; // redundant


String name; 
int speed;
boolean isOpen;
// same values in a cleaner way

public int age; // very bad
int age; // bad
private int age; // good

String s1 = new String("AnyString") ; // bad : low instantiation
// The constructor creates a new object, and adds the literal to the heap


String s2 = "AnyString" ; // good: fast instantiation
// This shortcut refers to the item in the String pool 
// and creates a new object only if the literal is not in the String pool.

String address = streetNumber +" "+ streetName +" "
+cityName+" "+cityNumber+" "+ countryName; // bad


StringBuilder address = new StringBuilder(streetNumber).append(" ")
.append(streetName).append(" ").append(cityName).append(" ")
.append(cityNumber).append(" ").append(countryName); // good

8-数値リテラルでのアンダースコアの使用。

int myMoneyInBank = 58356823;
int myMoneyInBank = 58_356_823; // more readable

long billsToPay = 1000000000L;
long billsToPay = 1_000_000_000L; // more readable

for (int i = 0; i < names.length; i++) 
{ saveInDb(names[i]); }


for (String name : names) 
{ saveInDb(name); } // cleaner

Scanner scanner = null;
try
{scanner = new Scanner(new File("test.txt"));
while (scanner.hasNext())
{System.out.println(scanner.nextLine());}} 
catch (FileNotFoundException e) 
{e.printStackTrace();} 
finally 
{if (scanner != null) 
{scanner.close();}}
// error-prone as we can forget to close the scanner in the finally block



try (Scanner scanner = new Scanner(new File("test.txt"))) 
{while (scanner.hasNext()) 
{System.out.println(scanner.nextLine());}} 
catch (FileNotFoundException fnfe) 
{fnfe.printStackTrace();} 
// cleaner and more succinct

try
{ productPrice = Integer.parseInt(integer); } 
catch (NumberFormatException ex)
{ } 
// fail silently without giving any feedback


try 
{ productPrice = Integer.parseInt(integer); } 
catch (NumberFormatException ex) 
{unreadablePrices.add(productPrice); // handle error
log.error("Cannot read price : ", productPrice );// proper and meaningful message
}

  • Null 要素を返す代わりに空のコレクションを返す
  • Optionalできる限り使ってください
  • requireNonNullの方法java.utils.Objects
  • NotNull、NotEmpty、NotBlank注釈
  • Objects::nonNullのStreams
  • requireNonNullのメソッドjava.util.Objects

14 - 同等性をチェックするには、==参照とequalsオブジェクトに使用します

// prerequisite:  the person class overrides equals() and hashCode()
Person p1 = new Person("John","Doe");
Person p2 = new Person("John","Doe");

System.out.println(p1 == p2); // false
System.out.println(p1.equals(p2)); // true

15-equals を実装するときは、常に hashCode を実装します。
「契約違反」をしないように、hashCodeオーバーライドする場合は必ずオーバーライドすることを忘れないでください。API に従って、2 つのオブジェクトのメソッドが同等であることを示した場合、そのメソッドから返される結果は同じでなければなりません。逆は必ずしも真ではありません。equals
hashCode()equals

不変データの 16 優先レコード (java14 以降)

public final class Person {
    private final String name;
    private final long idNumber;

    public Person(String name, long idNumber) {
        this.name = name;
        this.idNumber = idNumber;
    }

    public boolean equals(Object other) {
        if (other == this) return true;
        if (other == null) return false;
        if (other.getClass() != this.getClass()) return false;
        Person that = (Person) other;
        return (this.name.equals(that.name)) && (this.idNumber == that.idNumber);
    }

    public String toString() {
        return name + " " + idNumber;
    }

    public int hashCode() {
        return Objects.hash(idNumber, name);
    }
}



// this class can be transformed to a record:
record Person(String name, long idNumber) { } // cleaner and less verbose

public final class MyValues {
  private MyValues() {
    // No need to instantiate the class, we can hide its constructor
  }
  public static final String VALUE1 = "foo";
  public static final String VALUE2 = "bar";
}

// <-- empty line
@Repository
public class ...

20-For date 型の処理はjava.handling.java.localDateTimeJava 8 以降推奨されます。

Java のベスト プラクティスをさらに詳しく知りたい場合は、 「Clean code」と「Effective Java」という優れた書籍をお勧めします。