https://www.gravatar.com/avatar/306d401b2a8c0efe0996fec60e0c90aa?s=240&d=mp

My coding journey

Disclaimer: it's just for fun

Modern Java in Action 6 - Time and Date

Reasons to abandon old API

java.util.Date

  • mutable
  • unintuitive constructor (days, months, minutes and seconds are 0-based, year represented as delta from 1900), values wrap-around
  • cannot be internationalized

java.util.Calendar

  • not thread safe
  • mutable (no clear semantics date change)
  • when to use which?

java.util.DateFormat

  • not thead-safe
  • can only parse Date, not Calendar

New API

/en/posts/modern-java-in-action-6/time.png

java.time package

Classes and interfaces in a new package java.time (modelled after Joda Time classes) provide better way of thinking about and working with time concepts. The most important classess in this package are: LocalDate, LocalTime, LocalDateTime, Instant, Duration, and Period .

Modern Java in Action 5 - Optional

Null problem

Reasons why null is problematic:

  • source of coding errors (missing checks)
  • does not correctly model absence of value (null has no meaning)
  • breaks Java philosophy of hiding pointers (null is a pointer which is NOT hidden)

Handling in other languages

Optional

Creating

Three static methods may create instances of Optional:

Modern Java in Action 4 - refactoring and testing

Refatoring

Here are three simple refactorings that can be used if you want to migrate your codebase to Java 8 (or higher). You may want to do so for many different reasons (readability, conciseness, code reuse, security).

  • Refactoring anonymous classes to lambda expressions
  • Refactoring lambda expressions to method references
  • Refactoring imperative-style data processing to streams

Recommended paper about automatic refactoing of pre-Java 8 codebases into Java8: Lambda Refactoring

Gotchas

  • different meaning of this and super (in lambda this refers to enclosing class, in inner class - to itself)
  • lambdas cannot (and anonymous inner classes can) shadow enclosing class variables

Code flexibility

Question: when to introduce functional interfaces?

Modern Java in Action 3 - collection API

New API (in Java 8)

Collection classes got a few nice additions.

Factory methods

They create immutable collection (if you try to add/remove elements, you get UnsupportedOperationException. There is no varargs variant - this variant would require additional array allocation, which non-varargs variants don’t have.

There are overloads from 1 to 10 elements.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
//static <E> List<E> of(E... elements)

static <E> List<E> of(E e1)
static <E> List<E> of(E e1, E e2)
static <E> List<E> of(E e1, E e2, E e3)
static <E> List<E> of(E e1, E e2, E e3, E e4)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5)
// ... other variants


static <E> Set<E> of(E e1)
static <E> Set<E> of(E e1, E e2)
//... etc, other variants up to 10 


static <K, V> Map<E> of(K k1, V v1)
static <K, V> Map<E> of(K k1, V v1, K k2, V v2)
// ... etc, variants up to 10 pairs
// or with entries
import static java.util.Map.entry;
static <K, V> Map<E> ofEntries(entry(k1, v1), entry(k2, v2))

lists: removeIf, replaceAll

On a list you can use removeIf and replaceAll

Modern Java in Action 2 - fork-join and spliterators

Second chapter shows how parallellization works with streams; explains what fork-join pool is (which is used by streams framework underneath), what data structures are decomposable, how to create your own spliterator for more effective splitting of source stream for parallel processing.

Parallel streams

  • created by a call to parallel() in a chain of stream operations
  • fork/join pool uses Runtime.getRuntime().available-Processors() number of threads by default, but you can change it by specifying java.util.concurrent.ForkJoinPool.common.parallelism system property:
    1
    
    System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "12");
    

Hints

  • measure (check Java Microbenchmark Harness (JMH))
  • beware boxing/unboxing operations (use IntStream, DoubleStream of FloatStream)
  • limit() and findFirst() are worse on parallel streams (they require order) than findAny() with unordered()
  • don’t use inherently sequential functions: instead of this one, which is not easily parallelisable:
    1
    
    Stream.iterate(1L, i -> i + 1).limit(N)
    
    you should rather use:
    1
    
    LongStream.rangeClosed(1, N)
    
    which works on long values (no boxing) and produces easliy splittable range ideal for parallelization.
  • know which data structures are easily decomposable (ArrayList is - it can be split without traversing it, LinkedList isn’t)
  • performance depends also on order of stream operations which may change stream characteristics (SIZED stream can be split, filtered stream has unknow number of elems)
  • note the cost of terminal operation (if high - parallel time gain can be smaller that time used for combining partial results)

Decomposability table

class composability
ArrayList 😄 Excellent
IntStream.range 😄 Excellent
HashSet 😐 Good
TreeSet 😐 God
LinkedList 😭 Bad
Stream.iterate 😭 Bad

Fork Join pool

  • ForkJoinPool is an implementation of ExecutorService
  • requires creation of a RecursiveTask subclass with protected abstract R compute();
  • to use it, use following algorithm:
1
2
3
4
5
6
7
8
if (task is small enough or no longer divisible) {
    compute task sequentially
} else {
    split task in two subtasks
    call this method recursively possibly further splitting each subtask
    wait for the completion of all subtasks
    combine the results of each subtask
}
  • remember: join() is blocking, so use it after results of subtasks are ready
  • as a RecursiveTask, use compute() and fork(), don’t use the invoke() on a pool
  • wisely decide the criteria if the task should be split further (see example in a javadoc for RecursiveAction class where getSurplusQueuedTaskCount() is used for the criteria)
  • subtasks should take longer than creation of a new task
  • it is hard to debug (as with all multithreaded programs)
  • it is hard to measure, due to the fact that fork-join should be warmed-up

Work stealing

  • goal: ensure even distribution of work between threads
  • each thread in the pool keeps doubly-linked list of tasks to execute, takes one by one from the head and executes
  • if no more tasks it thread’s onw queue, it randomly selects a thread with no-empty queue and steals a task from the tail of that queue

Important You don’t have to use fork-join if your datastructure is decomposable; you just use parallel data streams. Automatic way of traversing a source and splitting it is “spliterator” - the interface which standard collections implement in the default implementation.

Encrypted Directory With encfs

I would like to keep my secrets in encrypted directory. It seems that there already exists a nice solution to this problem and it is called encfs.

For reference, I found online manual with examples after visiting baeldung linux article first.

So, let’s do it.

Create a pair of directories

Here I’m creating two directories:

  • ~/.crypt is the source directory - here encrypted data are stored
  • ~/crypt directory which is the mountpoint - here I would see decrypted files to work with
1
[karma@tpd] mkdir ~/crypt ~/.crypt

Create encfs

Now, in order to start working with encsfs I issue following command: encfs source mountpoint:

JavaScript Canvas Easter Eggs

It’s snowy and rainy, although it is April already according to the calendar. A few days ago I’ve seen little yellow flowers growing in the snow (snowdrops and aconite). It’s also very windy today (I can hear howling in ventilation chimneys) and it was raining all night long.

I need some more colors to dissipate the unpeasant aura. I’ve decided to write a small graphics generator for easter eggs.

The code is available at GitLab, in snowflake project and the generator itself is available on kamilachyla.gitlab.io page.