Jim H
Jim H
  • Home
  • Resume
  • Code Review-BestPractices
  • Java Best Practices
  • Kotlin Best Practices
  • Homophones in English
  • Personal
  • Blog

Date & Time

Back to Contents


Does anybody really know what time it is? (Does anybody really care? Is it 25 or 6 to 4?) 


If you are working with dates and times, please understand time zones and ZoneId. That class is in the package java.time; oh, by the way, since we are all on Java 8 or later, please use java.time in new work.  If you must work in Java 6 or 7, Joda Time is acceptable.  Please purge any use of java.util.Date and java.util.Calendar from your code as soon as practical.


As for writing your own date/time handling code, I have one word of advice: Don’t. It’s much, much harder than it looks.  (If only the engineers who developed java.util.Date had understood that simple fact…) Here’s an entertaining and educational video describing the issues. 


Note: ZoneId in Java corresponds to the zones defined in /usr/share/zoneinfo on Unix systems.

Stateless Objects

Back to Contents


  • In a multithreaded process, objects that do the work should not carry any state related to the thread being worked.  (They might carry state about themselves, such as the number of times they have been invoked.)
  • Any state of the work being done should be held in a “context” object.  The thread (or perhaps group of threads) owns the context, but the working class methods will consume and/or update the context.
  • Any state (in the working class, or the context) that might be affected by multiple threads should have atomic accessors.  The package java.util.concurrent.atomic provides such wrappers for primitive types (AtomicInteger, AtomicLong, etc.). If it is a collection, use Concurrent Collections to achieve thread safety.
  • Anything too complex to be locked by an atomic wrapper should be locked by a mutex. Java has a few different built-in ways to lock access. The simplest is introduced by the keyword synchronized. A method may be locked by adding the keyword to its definition:

private synchronized void threadSafeMethod() {

   <statements>

}

  • A block within a method may be locked by synchronizing on some object:

class FooBar {

  private Object mutex = new Object();


  public void methodWithLockedSection() {

    <statements>

    synchronized (mutex) { // waits for mutex to be unlocked if another block has locked it

      // mutex is now locked

      <locked statements>

    }

    // mutex is now unlocked

  }

}


Starting with Java 1.5, the package java.util.concurrent provides classes to give more control over locking. 

  • ReentrantLock is a simple mutex lock, best explained with an example:

class  HasLock {

  private ReentrantLock mutex = new ReentrantLock();

  public void lockingMethod() {

    mutex.lock();  // blocks until mutex is available

    try {

      <statements>

    } finally {

      mutex.unlock();

    }

  }

}

Always follow lock() with a try block; always unlock in the finally block. There are variants: ReentrantLock has two methods [tryLock(), tryLock(long timeOut, TimeUnit unit)] that will attempt to acquire the lock. The no-parameter version will return immediately if the lock is not available; the timed version will wait up to the specified duration. Both return true if the lock was acquired. (But see tryLock()'s warning about fairness.)

  • Semaphore is a lock counter. Its constructors take an int parameter called "permits."  A permit is controlled by methods acquire() and release(), and there are forms of tryAcquire(). Semaphore acts identically to ReentrantLock if permits is set to 1.

Encapsulation

Back to Contents


One of the key concepts of object-oriented programming is Encapsulation, and classes are the main structures used to encapsulate implementation details. Java allows several ways to encapsulate within classes.


Enclosed Classes

Local Classes

Anonymous Classes

Lambda Expressions

Enclosed Classes

Back to Contents

Back to top of section 


It is possible, and sometimes desirable, to enclose one class in another. Consider an object representation of a database record, that also defines a key from multiple fields. For example, here is a naive employee record:

class Person {

  String lastName;

  String firstName;

  String title;

  Person reportsTo;

  Set<Person> directReports;

  static class ID {

     String last;

     String first;

  } 

}

The inner class ID could define the primary key for the database table. (Of course, in the real world, one would probably use an identifier field, rather than people’s names; it’s possible for people to have the same name, or for names to change, especially after a major life event.)

All classes may have methods, including enclosed classes. Methods in the enclosed class have access to fields and methods in the enclosing class, including those with private access. Note that the fields in Person.ID have different names from those in Person. This was to avoid shadowing, where a name in the inner scope hides a field with the same name in the outer scope.


Also, note that the inner class is defined with the keyword static. This means that ID is not associated with an instance of Person, but with the class itself, just like any other static member. ID could also be instantiated without instantiating a Person. Without the static keyword, ID would be a member of an instance of Person.

Local Classes

Back to Contents

Back to top of section 


A class may be declared inside a method. This allows the programmer to take logic out of the parent class and encapsulate it.

class Foo {

  public void foo() {

  class Bar {

     doSomething() {

          // something wonderful

    } 

  }

       Bar baz = new Bar();

   baz.doSomething();

  } 

}

The object baz is, as expected, local to the method foo().  But so is its class, Bar. This prevents Bar from being used elsewhere, even in other methods of Foo.

Local classes have some access to their enclosing scope (subject to shadowing):

  • A local class has access to members of the enclosing class.
  • A local class can access local variables in the enclosing scope, but only if they are declared final or are effectively final (that is, they are not modified after initialization).

Anonymous Classes

Back to Contents

Back to top of section 


An anonymous class is an expression that implements an interface or extends a class. Consider the following trivial example:

class Main {

   interface BinaryOperation<T extends Number> {

      T doIt(T left, T right);

  }

  public void operations() {

    BinaryOperation<Float> fAdd = new BinaryOperation<>() {

      Float doIt(Float left, Float right) { return left + right; }

    }

    BinaryOperation<Integer> iMul = new BinaryOperation<>() {

       Integer doIt(Integer left, Integer right) { return left * right; }

    }

  System.out.println("π + e = " + fAdd.doIt(3.14, 2.718));

  System.out.println("3 * 2 = " + iMul.doIt(3, 2));

  } 

}

fAdd and iMul are objects of anonymous classes that implement BinaryOperation<>.

An anonymous class is an expression with the following syntax:

  • the new operator
  • the name of a class to extend or an interface to implement
  • parentheses that contain constructor arguments (for an interface, there is no constructor, so the parentheses must be empty)
  • a class declaration body (except that only method declarations are allowed, statements are not)

An anonymous class is a special case of a local class. Anonymous classes have the same access rules as other enclosed classes.

Lambda Expressions

Back to Contents

Back to top of section 


Starting with Java 8, lambda expressions were added to the language. A lambda takes one or more arguments and returns a value, similar to a method. The simplest lambda looks like this:

parameter -> expression

To create a lambda with multiple parameters, use parentheses:

(param1, param2) -> expression

To create a lambda with code that cannot be written in a single expression, use { curly braces }:

parameter -> { code block }


For example, consider a method to print all items in a list:

public <T> void printAll(List<T> list) {

  for (T elem : list) {

      System.out.println(elem);

  } 

}

This can be rewritten as:

public <T> void printAll(List<T> list) {

   list.forEach(elem -> System.out.println(elem)); 

}

If the lambda needs to return a value, the code block should have a return statement. (For the single expression lambda, the value of the expression is the returned value.)

Lambdas have the same access to the enclosing scope as local classes.


Consumer<T>, Predicate<T>

A lambda expression can be stored in a variable of type Consumer<T>, where T is the type returned by the lambda. 

Lambdas can be stored in other interface types, such as Predicate<T>. A Predicate is a function that examines each element of a stream and returns a boolean, which if true means the element is to be included. Example:

public Pair<List<String>, List<String>> getOddsAndEvens(List<String> titles) {

   List<String> odds = new ArrayList<>();

  for (String title : titles) {

           if ((title.length() & 1) != 0) {

         odds.add(title);

           }

   }

  List<String> evens = titles.stream()

           .filter(s -> (s.length() & 1) == 0)

           .collect(Collectors.toList());

  return new Pair(odds, evens);  

}

This method takes a list of strings, and splits them by whether the string length is odd or even. The odds are found in the for loop, while the evens are found with the predicate passed to filter(). (Of course, in the real world, we would use a single if and else to do this separation.)

To see examples of methods that takes a lambda, either in Consumer<T> or Predicate<T>, see the interface Stream<T>.

First PagePreviousNextHome

Copyright © 2019-2025 Jim Hamilton - All Rights Reserved.

Powered by

This website uses cookies.

We use cookies to analyze website traffic and optimize your website experience. By accepting our use of cookies, your data will be aggregated with all other user data.

DeclineAccept