Discontinued. Java has long since evolved past the necessity for this.
A shot of liveliness for Java syntax.
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) )
Examples
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.
- Download Espresso4J (JDK 1.6 compliant)
- Download Espresso4J Source
- Download Espresso4J Javadoc
How to integrate Espresso4J
- Add espresso4j.jar to your classpath
- Add the following imports to your code
import planetjon.espresso4j.*;
import static planetjon.espresso4j.Constructs.
- Use the pseudo-constructs in your code