Skip to content

Defining Your Own Class

Info

Semua file yang ada pada contoh pada catatan ini ada pada package Ch4/J4_3_Defining_Your_Own_Class

An Employee Class

Info

Semua file yang ada pada contoh pada catatan ini ada pada package Ch4/J4_3_Defining_Your_Own_Class/J_1_An_Employee_Class

Mari kita buat class dengan nama Employee.

Code

package Ch4.J4_3_Defining_Your_Own_Class.J_1_An_Employee_Class;

import java.math.BigDecimal;
import java.time.LocalDate;

public class EmployeeTest {
    public static void main(String[] args) {
        Employee[] employees = new Employee[4];
        employees[0] = new Employee("Employee 1",new BigDecimal("7800000"),LocalDate.of(2023,6,5));
        employees[1] = new Employee("Employee 2",new BigDecimal("7800000"),LocalDate.of(2023,6,5));
        employees[2] = new Employee("Employee 3",new BigDecimal("7800000"),LocalDate.of(2023,6,5));
        employees[3] = new Employee("Employee 4",new BigDecimal("7800000"),LocalDate.of(2023,6,5));

    }
}


class Employee{
    // instance
    private String name;
    private BigDecimal salary;

    private LocalDate hireDay;

    public Employee(String name, BigDecimal salary, LocalDate hireDay){
        this.name = name;
        this.salary = salary;
        this.hireDay = hireDay;
    }

    public String getName() {
        return name;
    }

    // Cutted, there is another method here
}

File diatas terdiri dari dua class, EmployeeTest dan Employee. Pada sebuah file, kita hanya boleh memiliki satu public class dan class yang di public harus memiliki nama yang sama dengan nama file.

Use of Multiple Source Files

Info

Semua file yang ada pada contoh pada catatan ini ada pada package Ch4/J4_3_Defining_Your_Own_Class/J_2_Use_Of_Multiple_Source_Files

Java programmer umumnya lebih memiliki membuat class kedalam source file masing-masing. Contoh, Employee Class ada pada Employe.java dan EmployeeTest class ada di EmployeeTest.java.

Code

package Ch4.J4_3_Defining_Your_Own_Class.J_2_Use_Of_Multiple_Source_Files;

import java.math.BigDecimal;
import java.time.LocalDate;

public class EmployeeTest {
    public static void main(String[] args) {
        Employee employee = new Employee("Farras",new BigDecimal("11000000"), LocalDate.of(2023,6,5));

        System.out.printf("Nama\t: %s\nSalaray\t: %,.2f\nTanggal masuk\t: %s",
                employee.getName(),
                employee.getSalary(),
                employee.getHireDay().toString());
    }
}
Output
Nama    : Farras
Salaray : 11,000,000.00
Tanggal masuk   : 2023-06-05
package Ch4.J4_3_Defining_Your_Own_Class.J_2_Use_Of_Multiple_Source_Files;

import java.math.BigDecimal;
import java.time.LocalDate;
class Employee{
    // instance
    private String name;
    private BigDecimal salary;

    private LocalDate hireDay;

    public Employee(String name, BigDecimal salary, LocalDate hireDay){
        this.name = name;
        this.salary = salary;
        this.hireDay = hireDay;
    }

    public String getName() {
        return name;
    }

    // Cutted, there is another method here
}

Declaring Local Variables with var

Semenjak Java 10, kita dapat mendeklarasi (wajib inisiasi juga) local variable menggunakan keyword var sebagai spesifikasi type data variabel.

Warning

var hanya bisa digunakan pada local variables didalam sebauh method.

Code

package Ch4.J4_3_Defining_Your_Own_Class;

import Ch4.J4_3_Defining_Your_Own_Class.J_2_Use_Of_Multiple_Source_Files.Employee;

import java.math.BigDecimal;
import java.time.LocalDate;

public class J_3_Declaring_Variable_Using_var {
    public static void main(String[] args) {

        Employee employeeOld = new Employee("Muhammad Farras",new BigDecimal(12000000),
                LocalDate.of(2023,5,6));

        var employee = new Employee("Muhammad Farras",new BigDecimal(12000000),
                LocalDate.of(2023,5,6));

    }
}

Working with null References

Info

Semua file yang ada pada contoh pada catatan ini ada pada package Ch4/J4_3_Defining_Your_Own_Class/J_4_Working_With_null_Reference

Object variable menampung sebuah referensi ke sebuah objek atau special value null yang mengidikasi bahwa variable tersebut belum merujuk ke objek apapun itu.

Kita harus berhati-hati dengan nilai null. Karena jika kita memanggil method dari sebauh variable object yang bernilai null akan menyebabkan !#java NullPointerException.

try {
    Employee employee1 = null;
    System.out.println(employee1.getName());
    // Without catch this exception, the app will terminate
}
catch (NullPointerException ex){
    System.out.println(ex.getMessage());
}
Error tersebut sangat fatal, mirip dengan exception index out of bounds jika program kita tidak menangkap exception tersebut maka program akan berhenti terminate.

Ketika kita mendefinisikan sebauh class, sangat baik jika kita menetahui field mana yang bisa menerima nilai null dan mana yang tidak. Pada contoh ini, kita tidak ingin properties name, salary dan hireDay menerima nilai null.

Ada dua solusi untuk mengubah null kedalam non-null value.

Pertama
Menggunakan cara primitive
if (n == null) name = "Unknown name" else name = n; 
Kedua
Menggunakan statick fungsi dari class Object.
name = Objects.requireNonNullElse(n,"Unknown name");

Namun ada cara yang lebih baik adalah menolak nilai null. Gunakan Objects.requireNonNull().

hireDay = Objects.requireNonNull(hireDay,"Hire day is require");

Jika seseorang membuat objek Employee dengan memberikan parameter hireDay nilai null, maka NullPointerException akan terjadi. pertama memang terlihat tidak berguna, namun ternyata ada dua manfaat.:

  1. Laporan exception akan terpampang deskripsi masalahnya
  2. Expcetion akan melaporkan lokasi persis masalah terjadi padakode. Karena, NullPointerException bisa terjadi dimana saja dan sulit untuk melacaknya, denga menggunakan method Objects.requireNonNull() kita dapat dengan mudah (alhamdulillah) melacak error akibat NullPonterException yang terjadi.

All Code

package Ch4.J4_3_Defining_Your_Own_Class.J_4_Working_With_null_Reference;

import java.math.BigDecimal;
import java.time.LocalDate;

public class EmployeeTest {
    public static void main(String[] args) {

        try {
            Employee employee1 = null;
            System.out.println(employee1.getName());
            // Without catch this exception, the app will terminate
        }
        catch (NullPointerException ex){
            System.out.println(ex.getMessage());
        }

        var employee2 = new Employee(null,new BigDecimal(2500000), LocalDate.now());
        System.out.println(employee2);

        var employee3 = new Employee(null,null, LocalDate.now());
        System.out.println(employee3);

        var employee4 = new Employee(null,null, null);
        System.out.println(employee4);
    }
}
Output
Cannot invoke "Ch4.J4_2_Predefined_Class.J_8_Working_With_null_Reference.Employee.getName()" because "employee1" is null
Name        : Unknown Name
Salary      : 2,500,000.00
Hire Day    : 2023-08-18
Name        : Unknown Name
Salary      : 0.00
Hire Day    : 2023-08-18
Exception in thread "main" java.lang.NullPointerException: Hire day is require
    at java.base/java.util.Objects.requireNonNull(Objects.java:259)
    at Ch4.J4_2_Predefined_Class.J_8_Working_With_null_Reference.Employee.<init>(Employee.java:19)
    at Ch4.J4_2_Predefined_Class.J_8_Working_With_null_Reference.EmployeeTest.main(EmployeeTest.java:24)
package Ch4.J4_3_Defining_Your_Own_Class.J_4_Working_With_null_Reference;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Objects;

public class Employee {
    // instance
    private String name;
    private BigDecimal salary;

    private LocalDate hireDay;

    public Employee(String name, BigDecimal salary, LocalDate hireDay){
        this.name = Objects.requireNonNullElse(name,"Unknown Name");

        this.salary = (salary ==null)? new BigDecimal(0) : salary;

        this.hireDay = Objects.requireNonNull(hireDay,"Hire day is require");
    }

    @Override
    public String toString() {
        return "Name\t\t: %s\nSalary\t\t: %,.2f\nHire Day\t: %s".
                formatted(this.name,this.salary,this.hireDay.toString());
    }

    public String getName() {
        return this.name;
    }
}

Private Method

Info

Semua file yang ada pada contoh pada catatan ini ada pada package Ch4/J4_3_Defining_Your_Own_Class/J_5_Private_Method

Ketika mengimplementasi sebuah class, kita membuat semua instance fileds (Properties) menjadi private karena `#!java public`` data sangat rawan (berbahaya, dapat dirubah secara langsung). Namun bagaimana dengan private method? kebanyakan method diset sebagai public, private method biasanya digunakan untuk beberapa keadaan saja. Misalnya, terkadang kita ingin memecah kode untuk perhitungan kedalam beberapa method. Dimana method yang dipecah tersebut sebagai pembantu komputasi dari method utama yang diset sebagai public. Dengan demikian methode helper tersebut tidak hanya digunakan pada method utama dan tidak dapat dipanggil mada method instance utamanya.

All Code

package Ch4.J4_3_Defining_Your_Own_Class.J_5_Private_Method;

import java.math.BigDecimal;
import java.time.LocalDate;

public class EmployeeTest {
    public static void main(String[] args) {
        var employee1 = new Employee(null,new BigDecimal(13000000), LocalDate.now());
        System.out.println(employee1.nicePrint()); // java: nicePrint() has private access
    }

}
package Ch4.J4_3_Defining_Your_Own_Class.J_5_Private_Method;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Objects;

public class Employee {
    // instance
    private String name;
    private BigDecimal salary;

    private LocalDate hireDay;

    public Employee(String name, BigDecimal salary, LocalDate hireDay){
        this.name = Objects.requireNonNullElse(name,"Unknown Name");

        this.salary = (salary ==null)? new BigDecimal(0) : salary;

        this.hireDay = Objects.requireNonNull(hireDay,"Hire day is require");
    }

    private String nicePrint(){
        return "Name\t\t: %s\nSalary\t\t: %,.2f\nHire Day\t: %s".
                formatted(this.name,this.salary,this.hireDay.toString());
    }

    @Override
    public String toString() {
        return this.nicePrint();
    }
}

Final Instance Fields

Kita dapat mendifinisikan instance field sebagai final. Denga demikian, field tersebut akan tetap memiliki nilai yang sama dari awal objek tersebut dibuat hinggai dihancurkan. Nilai pada field yang ditetapkan menjadi final tidak akan pernah beruha nilainya dan tidak dapat di assign dengan nilai apapun.

public class Employee {
    // instance
    private final String name;
    ...
}

Modifier final berguna untuk fields dengan tipe primitive atau final immutable class. (Class immutable adalah class yang tidak dapat berubah nilainya, seperti String).

Namun untuk mutable class, penggunaan final sedikit membingungkan, contoh dibawah ini kita menggunakan saah satu mutable class, StringBuilder.

Code

package Ch4.J4_3_Defining_Your_Own_Class;

import java.time.LocalTime;

public class J_6_Final_Instance_Field {
    public static void main(String[] args) {
        var thisLog = new Logger();

        thisLog.setNewDataLog("%s Update hase confirm".formatted(LocalTime.now()));
        thisLog.setNewDataLog("%s Another confirmation is accepted".formatted(LocalTime.now()));

        System.out.println(thisLog.getLog());
    }
}

class Logger{
    private final StringBuilder log;

    public Logger(){
        this.log = new StringBuilder();
    }

    public void setNewDataLog(String information){
        this.log.append(information).append("\n");
    }

    public String getLog(){
        return this.log.toString();
    }
}
Output
10:16:23.868176100 Update hase confirm
10:16:23.872176600 Another confirmation is accepted

Kode diatas kita membuat properties log menjadi final, namun mengapa kita masih menggunakan append() pada fields tersebut yang notabenya menambah isi dari fields tersebut. Jawabannya adalah, Keyword final fungsinya adalah agar reference objek yang telah tersimpan pada variable object (log) tidak akan pernah merujuk ke objek StringBuilder lainnya. Namun objek tersebut tetap dapat berubah, mutate