Discontinued. Java has long since evolved past the necessity for this.

A shot of liveliness for Java syntax” – Jonathan Weatherhead, developer

Create staple data-types such as arrays, lists, sets, and maps with unprecedented ease using inline language pseudo-constructs – A feature Java should have had a long time ago.


What is Espresso4J

Espresso4J is a package designed to augment the Java language with various pseudo-constructs for creating staple data structures such as arrays, lists, sets, and maps. Completely implemented through Java Generics and static import, no configuration is required to use the constructs beyond including the package in the classpath and importing the necessary resources. As consequence of being Generics-based, the types are inferred, but allow for hinting when necessary (see Complications). Furthermore, the constructs are fully compatible with any existing Class, an added benefit of being a “natural Java” brew.

It’s a simple as List<String> list = list("Lets", "start", "now!");

How to integrate Espresso4J

All you need to to set up Espresso4J is include the Espresso4J jar in your classpath. To use the pseudo-constructs, the Espresso4J package must be imported in your code, and the static methods of the Constructs class must be statically imported.

import planetjon.espresso4j.*;
import static planetjon.espresso4j.Constructs.*;

Overview of Espresso4J pseudo-constructs

Espresso4J introduces the following constructs:

  • Set set(v1, v2, …, vn)
  • Pair pair(h, t)
  • [] array(v1, v2, …, vn)
  • List list(v1, v2, …, vn)
  • Map map( pair(k1, v1), pair(k2, v2), …, pair(kn, vn) )


For the following examples, we will assume the following classes:

class A{}
class B extends A{}
class C{}

Set examples

//Homogeneous arguments. The inferred type is obvious.
Set<B> set = set( new B(), new B(), new B() );

//Heterogeneous arguments. The inferred type is as wide as necessary.
Set<A> set = set( new A(), new A(), new B() );

Pair example

//The inferred types are always exactly those of the arguments provided.
Pair<A, B> pair = pair( new A(), new B() );

Array examples

//Homogeneous arguments. The inferred type is obvious.
B[] array = array( new B(), new B(), new B() );

//Heterogeneous arguments. The inferred type is as wide as necessary.
A[] array = array( new A(), new A(), new B() );

List examples

//Homogeneous arguments. The inferred type is obvious.
List<B> list = list( new B(), new B(), new B() );

//Heterogeneous arguments. The inferred type is as wide as necessary.
List<A> list = list( new A(), new A(), new B() );

Map examples

//Homogenous values. The inferred type is obvious.
Map<C, B> map = map( pair( new C(), new B() ), pair( new C(), new B() ) );

//Heterogeneous values. The inferred type is as wide as necessary
Map<C, A> map = map( pair( new C(), new A() ), pair( new C(), new B() ) );

Advanced Topics

Zero-argument Initialization

When no arguments are provided in the pseudo-constructs, the type inference mechanism will automatically create the structure parametrized to the type that the structure is being assigned to.

//Create an empty list of Integers
List<Integer> list = list();

//Create an empty list of Strings
List<String> list = list();

Manual type selection

Espresso4J allows for type coercion rather than inference when more control is necessary. This can be done through either formal parameter, or type hinting.

//Type hinting
List<Number> list = list((Number)1, 2, 3);

//Formal parameter
List<Number> list = Constructs.<Number>list(1, 2, 3);

It is an unfortunate shortcoming of the Java language that forces the use of a calling object when parameterizing a statically imported method. Type hinting is the recommended technique for type coercion in most cases (see Arrays as arguments). With type hinting, it suffices to cast one of the arguments, preferably the first for aesthetic reasons.

Unintuitive type inference

Type inference may decide on a surprising choice of widened type to use when working with heterogeneous argument types, sometimes of the form parent & interface1 & interface2... and the way to handle this is to either widen the generic parameter’s range, parametrize the type, or hint the type. Type hinting is the recommended method in most cases.

List<Number> list = list(1, 2, 3.5); //ERROR

//Type hinting
List<Number> list = list( (Number) 1, 2, 3.5 );

//Type parametrization
List<Number> list = Constructs<Number>.list(1, 2, 3.5);

//Widened generic parameter range
List<? extends Number> list = list(1, 2, 3.5);

Arrays as arguments

Due to the way that variable length arguments are implemented, all of the pseudo-constructs with variable length arguments are compatible with an array of values as argument as an alternative.

Integer[] array = {1, 2, 3};

//Create a list from an array
List<Integer> list = list(array);

A consequence to beware of, providing a single array with the intent of creating a structure of type T[] will not be inferred as such. The type inference mechanism will understand this as the case of the previous example. Type hinting will not help in this situation – the correct way is to coerce the type through formal parameter.

Integer[] array = {1, 2, 3};

//Create a list of Integer arrays
List<Integer[]> list = Construct.<Integer[]>list(array);

Release History

Espresso4J 1.3:

  • Lowered Pair constructor visibility to default/package to enforce usage of the pair() construct over the constructor.

Espresso4J 1.2:

  • Added a pretty format toString() to the Pair class. Credit to Itsme213
  • Removed unnecessary @SafeVarargs annotation from the pair() construct

Espresso4J 1.1:

  • Fixed the list() construct to now create a mutable list

Espresso4J 1.0:

  • First cup brewed

Download and Setup

Espresso4J is distributed “As Is” under the Modified Free BSD license.

How to integrate Espresso4J

  1. Add espresso4j.jar to your classpath
  2. Add the following imports to your code
    import planetjon.espresso4j.*;
    import static planetjon.espresso4j.Constructs.
  3. Use the pseudo-constructs in your code