30 października 2011

java.util.Objects w Java 7

Jutro, w poniedziałek, 31.10 o 17:24 Maksymowi "stukną" 4 tygodnie! Chłopisko coraz bardziej roztropne i zaczynam zapominać pomału, że to jeszcze niemowlę. Podczas kąpieli przerzucam go w przód, tył, ale delikatnie, bo bardzo wrażliwy. Zauważyłem, że wystarczy zbyt gwałtownie wkładać do wanienki, a już zaczyna się krzywienie miny i krzyk. Na razie o płaczu nie ma mowy, ale potrafi krzyknąć, więc po co go denerwować i okolicę. Jak tak dalej pójdzie, zanim się obejrzę, a już będzie siadał.


On śpi, ja czytam i tak trafiłem dzisiaj na artykuł Guava's Objects Class: Equals, HashCode, and ToString, a w zasadzie kopię wpisu jako artykuł, w którym poznałem com.google.common.base.Objects z Google Guava oraz java.util.Objects z Java SE 7. Wspomina się w nim również o projekcie Apache Commons, w którym istnieją klasy, na których można oprzeć tworzenie metod toString() (klasa org.apache.commons.lang3.builder.ToStringBuilder), equals() (klasa org.apache.commons.lang3.builder.EqualsBuilder) oraz hashCode() (klasa org.apache.commons.lang3.builder.HashCodeBuilder). Co jednak zrobiło na mnie największe wrażenie, to fakt wciągnięcie ich odpowiedników do Java 7.

W ten sposób zwrócono moją uwagę na java.util.Objects.

Poniższa klasa testująca pokazuje działanie większości (poza jedną) metod java.util.Objects.
package pl.japila.java7;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.Objects;

import org.junit.Test;

public class ObjectsTest {

 class Customer {
  String name;

  public Customer(String name) {
   this.name = name;
  }
 }

 @Test
 public void testObjectsMethods() {
  Customer jacek = new Customer("Jacek");
  Customer agatka = new Customer("Agatka");

  Customer[] customers = { jacek, agatka };

  assertTrue("Agatka jest Agatką", Objects.equals(agatka, agatka));
  assertFalse("Jacek nie jest Agatką", Objects.equals(jacek, agatka));
  assertFalse(Objects.deepEquals(customers, new Customer[0]));
  assertEquals(jacek.hashCode(), Objects.hashCode(jacek));
  assertEquals(0, Objects.hashCode(null));
  assertEquals("null", Objects.toString(null));

  final String nullDefaultToString = "mój toString()";
  assertEquals(nullDefaultToString, Objects.toString(null, nullDefaultToString));

  final String exceptionMsg = "Zostanie zgłoszony wyjątek NPE";
  try {
   Objects.requireNonNull(null, exceptionMsg);
   fail("Powinien zostać zgłoszony wyjątek NPE");
  } catch (NullPointerException npe) {
   assertEquals("Wyjątek jest oczekiwany", exceptionMsg, npe.getMessage());
  }
 }

}
Nie mniej zaskoczyło mnie bogactwo Apache Commons, kiedy przeczytałem komentarz Craig'a Ringer'a do wpisu JDK 7: The New Objects Class:

"I'd actually love to see much of Apache Commons Lang (and Apache Commons IO) pulled into Java. Certainly StringUtils (as static methods on String), IOUtils for the static stream copying methods, FileUtils, ObjectUtils (which sounds like the conceptual origin of much of the new Objects class), CompareToBuilder, HashCodeBuilder, EqualsBuilder, ToStringBuilder, ExceptionUtils.getRootCause as a method of Throwable, etc. The JDK has been focusing on adding huge new and fancy codebases, and really neglecting the usability of the core library."

Słyszałem o tej różnorodności, ale jakoś nie dane mi było spróbować jej. Wiedza uskrzydla, a praktyka pozwala utrzymać poziom, więc raz przeczytawszy (wchodząc na odpowiedni pułap przelotowy) należy przekuć wiedzę w czyn, aby...nie spaść (jak niejednokrotnie zwraca się uwagę w wątku CV po Warsjawa 2011 na forum Warszawskiego JUGa).

Nie pamiętam również, abym wiedział o istnieniu java.lang.String.isEmpty(), która pojawiła się w Java 6 (!) Teraz już wiem.

Przy okazji, Groovy importuje automatycznie klasy z java.util, więc i Objects (podobnie jak Java importuje java.lang).