.::. Hendra Jaya .::.

June 23, 2009

Quiz : Tampilkan Kata Demi Kata

Filed under: Java — hjaya @ 2:48 pm

Dengan hanya menggunakan

  1. Method indexOf(int) pada String atau overload-nya
  2. Method substring(int) pada String atau overload-nya…
  3. Satu dan hanya satu kali iterasi, yaitu via while(boolean);

Tampilkan sebuah string kata per kata.

Contoh :

public class TampilPerKata {
  public static void main(String[] args) {
    String kalimat = "mari kita pergi berlibur";
    while (/*code*/) {
      /*code*/
    }
  }
}


Dan output yang dihasilkan adalah :
mari
kita
pergi
berlibur

Catatan : String yang diberikan pasti dalam format yang benar, sehingga tidak perlu validasi lanjut.

Dan inilah jawaban terbaik yang bisa saya berikan :

public class TampilPerKata {
  public static void main(String... args){
    String kalimat = "mari kita pergi berlibur";

    boolean lanjut = true;
    while (lanjut){
      int i = kalimat.indexOf(" ");
      lanjut = i != -1;
      System.out.println(lanjut ? kalimat.substring(0, i) : kalimat);
      kalimat = kalimat.substring(i + 1);
    }
  }
}

June 20, 2009

BigDecimal, BigInteger dan BigMistake

Filed under: Java — hjaya @ 11:41 pm

Harus diakui, judul post kali ini tidak orisinil. Tetapi, judulnya tetap saja menarik dan mungkin post kali ini akan bisa menjelaskan tentang BigMistake ketika kita memakai BigDecimal.

1. BigMistake pertama dalam memakai BigDecimal dan BigInteger adalah : runtime!! No doubt about it. Salah satu pelajaran yang bisa dipetik dari BigMistake ini adalah : Gunakan BigDecimal dan BigInteger hanya jika diperlukan, sebisa mungkin gunakan double atau float. Tetapi, satu yang pasti, untuk perkara duit gunakan BigDecimal.

2. MathContext adalah wajib
Kode program berikut ini akan mengalikan 0.1 dengan 10. Hasil yang seharusnya keluar adalah 1. Tetapi, coba tebak output apa yang akan anda terima?

public static void main(String[] args) {
  BigDecimal _ZeroPointOne = new BigDecimal(0.1);
  System.out.println(_ZeroPointOne.multiply(BigDecimal.TEN));
}

Alih-alih mendapatkan output 1 atau 1.000 atau yang sejenis, anda akan memperoleh output 1.0000000000000000555111512312578270211815834045410156250.. mengejutkan…tentu saja.

Untuk mengatasi hal ini, Java sebenarnya sudah menyiapkan solusi, yaitu MathContext. Secara sederhana, MathContext adalah sebuah object yang menentukan setting-setting yang akan dipakai dalam kalkulasi, seperti presisi dan mode pembulatan.

Mari kita lihat output apa yang akan diterima jika kita menggunakan MathContext :

public static void main(String[] args) {
  MathContext ctx = new MathContext(10, RoundingMode.HALF_UP);
  BigDecimal _ZeroPointOne = new BigDecimal(0.1, ctx);
  System.out.println(_ZeroPointOne.multiply(BigDecimal.TEN, ctx));
}

Yap.. ternyata hasil yang diperoleh adalah 1.000000000 .. hasil yang diharapkan tentunya.

Sekarang, apakah kita harus menyediakan sebuah MathContext dalam setiap operasi di BigDecimal. Sebaiknya iya dan sebaiknya MathContext yang dipakai dari awal sampai akhir penggunaan BigDecimal menggunakan context yang sama.

Agar tidak terlalu bingung mempelajari MathContext mungkin ada baiknya kita menggunakan MathContext standard yang sudah disediakan oleh Java. Ada empat buah MathContext yang sudah disediakan, yaitu UNLIMITED, DECIMAL32, DECIMAL64 dan DECIMAL128. Sebagai permulaan, gunakanlah MathContext.DECIMAL64

Lantas, bagaimana output yang akan kita peroleh dengan kode program di atas jika menggunakan MathContext DECIMAL64?

public static void main(String[] args) {
  MathContext ctx = MathContext.DECIMAL64;
  BigDecimal _ZeroPointOne = new BigDecimal(0.1, ctx);
  System.out.println(_ZeroPointOne.multiply(BigDecimal.TEN, ctx));
}

Hore, kita mendapatkan output 1.000000000000000.. hasil yang diharapkan dengan jumlah angka di belakang koma yang cukup panjang.

Sebagai best practice, gunakan selalu MathContext dalam operasi-operasi perhitungan yang melibatkan BigDecimal dan untuk kebanyakan perhitungan, MathContext.DECIMAL64 sudah sangat mumpuni.

Method isPowerOfTwo(long number)

Filed under: Java — hjaya @ 9:16 am

1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024…

Di atas itu adalah barisan bilangan yang berada dalam bentuk 2n, dimana n = 0, 1, 2, 3.. ; n ε bilangan cacah.

Dan dibawah ini adalah method static untuk memeriksa apakah sebuah bilangan (long) merupakan bilangan 2n :

public static boolean isPowerOfTwo(long number) throws ArithmeticException{
  if (number < 1) throw new ArithmeticException("number must be greater than 0");
  return (number & (number - 1)) == 0;
}

June 19, 2009

Toleransi Pattern Pada Kelas DateFormat..

Filed under: Java — hjaya @ 10:06 am

Di Java, kita mengenal kelas DateFormat. Kelas ini berfungsi untuk mem-parsing String (dalam pattern tertentu) menjadi Date dan juga sebaliknya.

Secara singkat, kita biasa menggunakan kelas DateFormat seperti ini :

  public class Main {
    public static void
main(String... args) {
      String pattern = "yyyyMMdd";
      DateFormat dateFormatter = new SimpleDateFormat(pattern);
      String _17_Juni_09 = "20090617";

      try {
        System.out.println(dateFormatter.parse(_17_Juni_09));
      } catch (ParseException e) {
        e.printStackTrace();
      }
    }
  }

Ada satu hal menarik yang akan kita bahas dalam kode program di atas. Yaitu ParseException. Secara default, DateFormat akan berusaha sebaik-baiknya untuk mem-parsing parameter yang dikirimkan. Hal ini bisa berakibat baik dan bisa juga berakibat buruk. Sebagai best practice, sebaiknya kita mempelajari keburukan dari toleransi dari DateFormat.

Contoh 1 : Sebuah String “20090617″ akan diterjemahkan sebagai 17 Juni 2009 (benar)

Parameter yang dikirim logically dan physically benar. Logically benar karena tanggal 17 Juni 2009 memang benar-benar ‘ada’ dan physically benar karena mengikuti kaedah penulisan tanggal yang benar

Contoh 2 : Sebuah String “20090635″ akan diterjemahkan sebagai 5 Juli 2009 (bisa benar, bisa salah)

Parameter yang dikirim logically salah namun physically benar. Logically salah karena tanggal 35 Juni 2009 sebenarnya tidak ‘ada’ tetapi physically benar karena mengikuti kaedah penulisan tanggal yang benar.

Contoh 3 : Sebuah String “200906a7″ akan menghasilkan ParseException (benar)

Parameter yang dikirim logically salah dan physically salah.

Pada contoh ke-2, mengapa DateFormat tidak melempar exception?? Karena memang secara default, DateFormat akan mentolerir kesalahan logic dan akan tetap berusaha mem-parsing input yang diberikan.

Pada contoh ke-3, mengapa DateFormat melempar exception?? Karena input yang dikirim memang tidak bisa diparsing.

Kesimpulan yang bisa kita tarik sampai saat ini adalah DateFormat secara default hanya akan melempar exception jika data physically salah sehingga proses parsing pasti gagal. Tetapi, bagaimana dengan data yang logically salah?

Secara default, DateFormat akan mentolerir hal ini dan dengan senang hati mencoba ‘membenarkan’ input yang diterima. Pada contoh di atas, tanggal 35 Juni 2009 akan diterjemahkan menjadi 5 Juli 2009. Hal inilah yang bisa berakibat baik dan juga bisa berakibat buruk. Berakibat baik kalau programmer sudah mengerti akan perilaku ini dan memang sengaja membiarkan DateFormat melakukannya.

Tetapi, kebanyakan coder (bukan programmer) akan terjebak dengan feature ini dan mengira bahwa input yang dikirim tidak bermasalah dan aplikasi berjalan baik-baik saja. Well, memang benar bahwa aplikasi berjalan baik-baik saja… tetapi ketidak-aware-an para coder akan berakibat fatal pada Business Process.

Contoh mudah yang bisa kita karang : Misalkan sebuah aplikasi perbankan menjanjikan pembayaran bunga pada tanggal 25 setiap bulannya. Tetapi karena kesalahan ketik, user memasukkan tanggal 35. Karena aplikasi tidak mengeluarkan Exception, data tersebut tersimpan dengan mulus di database dan akibatnya pembayaran bunga molor 10 hari dari yang sudah dijanjikan. Satu atau dua nasabah dengan rekening yang kecil mungkin tidak terlalu ambil pusing. Tetapi bagaimana dengan nasabah dengan rekening yang besar yang memang setiap bulannya menanti-nanti tanggal 25??

Untuk mengantisipasi hal ini, kita dapat ‘meminta’ DateFormat untuk menghilangkan rasa toleransinya. Yaitu dengan menambahkan setLenient(false). Dengan tidak adanya toleransi dari DateFormat maka input “20090635″ akan ditolak dan aplikasi akan mengeluarkan Exception dan Business Error pun dapat dihindari. Di bawah ini adalah contoh kode program yang menghilangkan rasa toleransi dari DateFormat :

  public class Main {
    public static void
main(String... args) {
      String pattern = "yyyyMMdd";
      DateFormat dateFormatter = new SimpleDateFormat(pattern);
      dateFormatter.setLenient(
false);
      String _35_Juni_09 = "20090635";

      try {
        System.out.println(dateFormatter.parse(_35_Juni_09));
      } catch (ParseException e) {
        e.printStackTrace();
      }
    }
  }

Blog at WordPress.com.