Skip to main content

Java 8 highlights

Chapter 13. New I/O API (NIO.2)

NIO.2 was introduced with JDK 7 to provide enhanced file I/O support and access to the default filesystem. NIO.2 is supported by the java.nio.file andjava.nio.file.attribute packages. The NIO.2 API is also known as “JSR 203: More New I/O APIs for the Java Platform.” Popular interfaces that are used from the API arePathPathMatcherFileVisitor, and WatchService. Popular classes that are used from the API are Paths and Files.

The Path Interface

The Path interface can be used to operate on file and directory paths. This class is an upgraded version of the java.io.File class. The following code demonstrates the use of some of the methods of the Path interface and the Paths class for acquiring information:
Path p = Paths.get("\\opt\\jpgTools\\README.txt");
System.out.println(p.getParent()); // \opt\jpgTools
System.out.println(p.getRoot()); // \
System.out.println(p.getNameCount()); // 3
System.out.println(p.getName(0)); // opt
System.out.println(p.getName(1)); // jpgTools
System.out.println(p.getFileName()); // README.txt
System.out.println(p.toString()); // The full path
The Path class also provides additional features, some of which are detailed in Table 13-1.
Table 13-1. Path interface capabilities
Path methodCapability
path.toUri()
Converts a path to a URI object
path.resolve(Path)
Combines two paths together
path.relativize(Path)
Constructs a path from one location to another
path.compareTo(Path)
Compares two paths against each other

The Files Class

The Files class can be used to create, check, delete, copy, or move a file or directory. The following code demonstrates some commonly used methods of the Files class:
// Create Directory
Files.createDirectories("\\opt\\jpg");
// Intstantiate path objects
Path target1 = Paths.get("\\opt\\jpg\\README1.txt");
Path p1 = Files.createFile(target1);
Path target2 = Paths.get("\\opt\\jpg\\README2.txt");
Path p2 = Files.createFile(target2);
// Check file attributes
System.out.println(Files.isReadable(p1));
System.out.println(Files.isReadable(p2));
System.out.println(Files.isExecutable(p1));
System.out.println(Files.isSymbolicLink(p1));
System.out.println(Files.isWritable(p1));
System.out.println(Files.isHidden(p1));
System.out.println(Files.isSameFile(p1, p2));

// Delete, move, and copy examples
Files.delete(p2);
System.out.println(Files.move(p1, p2));
System.out.println(Files.copy(p2, p1));
Files.delete(p1);
Files.delete(p2);
The move method accepts the varargs enumeration using REPLACE_EXISTING or ATOMIC_MOVEREPLACE_EXISTING moves the file, even if it already exists. ATOMIC_MOVE ensures that any process watching the directory will be able to access the complete file.
The copy method accepts the varargs enumeration with REPLACE_EXISTINGCOPY_ATTRIBUTES, or NOFOLLOW_LINKSREPLACE_EXISTING copies the file, even if it already exists.COPY_ATTRIBUTES copies the file attributes. NOFOLLOW_LINKS copies the links, but not the targets.
The lineslistwalk, and find methods have been added to the Files class relative to the Stream API. The lines method lazily reads a stream of lines. The list method lazily lists directory entries and walk recursively traverses the entries. The find method lazily provides Path by searching for files in a file tree rooted at a given file node.

Additional Features

The NIO 2.0 API also provides the following features, which are good to know for the job. Questions about these features are also included on the Oracle Certified Professional Java SE 7 Programmer Exam. These items are not covered here as they are more suited to a tutorial style guide or resource:
  • The ability to watch a directory using the WatchService interface.
  • The ability to recursively access directory trees using the FileVisitor interface.
  • The ability to find files using the PathMatcher functional interface.
Since PathMatcher is a functional interface, it may be used with a Lambda Expression.
PathMatcher matcher = (Path p) -> {
  // returns boolean
  return (p.toString().contains("World"));
};
Path path =  FileSystems.getDefault().getPath(
  "\\opt\\jpg\\HelloWorld.java");
System.out.print("Matches: " +
matcher.matches(path));

$ Matches: true

Table 15-5. Algorithm efficiencies
AlgorithmsConcrete typeTime
getset
ArrayList
0 (1)
add, remove
ArrayList
0 (n)
contains, indexOf
ArrayList
0 (n)
get, put, remove, containsKey
HashMap
0 (1)
add, remove, contains
HashSet
0 (1)
add, remove, contains
LinkedHashSet
0 (1)
get, set, add, remove (from either end)
LinkedList
0 (1)
get, set, add, remove (from index)
LinkedList
0 (n)
contains, indexOf
LinkedList
0 (n)
peek
PriorityQueue
0 (1)
add, remove
PriorityQueue
0 (log n)
remove, get, put, containsKey
TreeMap
0 (log n)
add, remove, contains
TreeSet
0 (log n)
Table 16-1. Type parameters, bounds, and wildcards
Type parametersDescription
Unbounded type; same as 
Unbounded types;  and 
Upper bounded type; a specific type T that is a subtype of type P
Upper bounded type; a specific type T that is a subtype of type P and that implements type S
Lower bounded type; a specific type T that is a supertype of type P
Unbounded wildcard; any object type, same as 
Bounded wildcard; some unknown type that is a subtype of type P
Bounded wildcard; some unknown type that is a subtype of type P and that implements type S
Lower bounded wildcard; some unknown type that is a supertype of type P

Chapter 17. The Java Scripting API

The Java Scripting API, introduced in Java SE 6, provides support that allows Java applications and scripting languages to interact through a standard interface. This API is detailed in JSR 223, “Scripting for the Java Platform” and is contained in the javax.script package.

Scripting Languages

Several scripting languages have script engine implementations available that conform to JSR 223. See Scripting Languages Compatible with JSR-223 in Appendix B for a subset of these supported languages.

Script Engine Implementations

The ScriptEngine interface provides the fundamental methods for the API. The ScriptEngineManager class works in conjunction with this interface and provides a means to establish the desired scripting engines to be utilized.

Embedding Scripts into Java

The scripting API includes the ability to embed scripts and/or scripting components into Java applications.
The following example shows two ways to embed scripting components into a Java application: (1) the scripting engine’s eval method reads in the scripting language syntax directly, and (2) the scripting engine’s eval method reads the syntax in from a file.
import java.io.FileReader;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class HelloWorld {
  public static void main(String[] args) throws
      Exception {
    ScriptEngineManager m
        = new ScriptEngineManager();
    // Sets up Nashorn JavaScript Engine
    ScriptEngine e = m.getEngineByExtension("js");
    // Nashorn JavaScript syntax.
    e.eval("print ('Hello, ')");
    // world.js contents: print('World!\n');
    Path p1 = Paths.get("/opt/jpg2/world.js");
    e.eval(new FileReader(p1.toString()));
  }
}

$ Hello, World!

Invoking Methods of Scripting Languages

Scripting engines that implement the optional Invocable interface provide a means to invoke (execute) scripting language methods that the engine has already evaluated (interpreted).
The following Java-based invokeFunction() method calls the evaluated Nashorn scripting language function greet(), which we have created:
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByExtension("js");
e.eval("function greet(message)
  + "{" + "println(message)" + "}");
Invocable i = (Invocable) e;
i.invokeFunction("greet", "Greetings from Mars!");

$ Greetings from Mars!

Accessing and Controlling Java Resources from Scripts

The Java Scripting API provides the ability to access and control Java resources (objects) from within evaluated scripting language code. The script engines utilizing key-value bindings is one way this is accomplished.
Here, the evaluated Nashorn JavaScript makes use of the nameKey/world binding and reads in (and prints out) a Java data member from the evaluated scripting language:
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByExtension("js");
String world = "Gliese 581 c";
e.put("nameKey", world);
e.eval("var w = nameKey" );
e.eval("println(w)");

$ Gliese 581 c
By utilizing the key-value bindings, you can make modifications to the Java data members from the evaluated scripting language:
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByExtension("js");
List<String> worldList = new ArrayList<>();
worldList.add ("Earth");
worldList.add ("Mars");
e.put("nameKey", worldList);
e.eval("var w = nameKey.toArray();");
e.eval(" nameKey.add (\"Gliese 581 c\")");
System.out.println(worldList);

$ [Earth, Gliese 581 c]

Setting Up Scripting Languages and Engines

Before using the Scripting API, you must obtain and set up the desired script engine implementations. Many scripting languages include the JSR-223 scripting engine with their distribution, either in a separate JAR or in their main JAR, as in the case of JRuby.

Scripting Language Setup

Here are the steps for setting up the scripting language:
  1. Set up the scripting language on your system. Scripting Languages Compatible with JSR-223 in Appendix B contains a list of download sites for some supported scripting languages. Follow the associated installation instructions.
  2. Invoke the script interpreters to ensure that they function properly. There is normally a command-line interpreter, as well as one with a graphical user interface.
For JRuby (as an example), the following commands should be validated to ensure proper setup:
jruby [file.rb] //Command line file
jruby.bat //Windows batch file

Scripting Engine Setup

Here are the steps for setting up the scripting engine:
  1. Determine if your scripting language distribution includes the JSR-223 scripting API engine in its distribution. If it is included, steps 2 and 3 are not necessary.
  2. Find and download the scripting engine file from the external resource (e.g., website).
  3. Place the downloaded file into a directory and extract it to expose the necessary JAR. Note that the optional software (opt) directory is commonly used as an installation directory.

TIP

To install and configure certain scripting languages on a Windows machine, you may need a minimal POSIX-compliant shell, such as MSYS or Cygwin.

Scripting Engine Validation

Validate the scripting engine setup by compiling and/or interpreting the scripting language libraries and the scripting engine libraries. The following is an older version of JRuby where the engine was available externally:
javac -cp c:\opt\jruby-1.0\lib\jruby.jar;c:\opt\
jruby-engine.jar;. Engines
You can perform additional testing with short programs. The following application produces a list of the available scripting engine names, language version numbers, and extensions. Note that this updated version of JRuby includes JSR-223 support in its primary JAR file; therefore, the engine does not need to be separately called out on the class path:
$ java -cp c:\opt\jruby-1.6.7.2\lib\jruby.jar;.
  EngineReport

import java.util.List;
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngineFactory;

public class EngineReport {
  public static void main(String[] args) {
    ScriptEngineManager m =
        new ScriptEngineManager();
    List<ScriptEngineFactory> s =
        m.getEngineFactories();
    // Iterate through list of factories
    for (ScriptEngineFactory f: s) {
      // Release name and version
      String en = f.getEngineName();
      String ev = f.getEngineVersion();
      System.out.println("Engine: "
        + en + " " + ev);
      // Language name and version
      String ln = f.getLanguageName();
      String lv = f.getLanguageVersion();
      System.out.println("Language: "
        + ln + " " + lv);
      // Extensions
      List<String> l = f.getExtensions();
      for (String x: l) {
        System.out.println("Extensions: " + x);
      }
    }
  }
}

$ Engine: Oracle Nashorn 1.8.0
$ Language: ECMAScript ECMA - 262 Edition 5.1
$ Extensions: js

$ Engine: JSR 223 JRuby Engine 1.6.7.2
$ Language: ruby jruby 1.6.7.2
$ Extensions: rb

Chapter 19. Lambda Expressions

Lamda expressions (λEs), also known as closures, provide a means to represent anonymous methods. Supported by Project Lambda, λEs allow for the creation and use of single method classes. These methods have a basic syntax that provides for the omission of modifiers, the return type, and optional parameters. The specification for λEs is set out inJSR 335, which is divided into seven parts: functional interfaces, lambda expressions, method and constructor references, poly expressions, typing and evaluation, type inference, and default methods. This chapter focuses on the first two.

λEs Basics

λEs must have a functional interface (FI). An FI is an interface that has one abstract method and zero or more default methods. FIs provide target types for lambda expressions and method references, and ideally should be annotated with @FunctionalInterface to aid the developer and compiler with design intent.
@FunctionalInterface
public interface Comparator<T> {
  // Only one abstract method allowed
  int compare(T o1, T o2);
  // Overriding allowed
  boolean equals(Object obj);
  // Optional default methods allowed
}

λEs Syntax and Example

Lambda expressions typically include a parameter list, a return type, and a body.
(parameter list) -> { statements; }
Examples of λEs include:
() -> 66
(x,y) -> x + y
(Integer x, Integer y) -> x*y
(String s) -> { System.out.println(s); }
This simple JavaFX GUI application adds text to the title bar when the button is pressed. The code makes use of the EventHandler functional interface with the one abstract method, handle().
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class JavaFxApp extends Application {
  @Override
  public void start(Stage stage) {
    Button b = new Button();
    b.setText("Press Button");
    // Anonymous inner class usage
    b.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {
        stage.setTitle("λEs rock!");
      }
    });
    StackPane root = new StackPane();
    root.getChildren().add(b);
    Scene scene = new Scene(root, 200, 50);
    stage.setScene(scene);
    stage.show();
  }
  public static void main(String[] args) {
    launch();
  }
}
To refactor this anonymous inner class into a lambda expression, the parameter type needs to be either (ActionEvent event) or just (event) and the desired functionality needs to be provided as statements in the body.
// Lambda Expression usage
b.setOnAction((ActionEvent event) -> {
  stage.setTitle("λEs rock!");
});

TIP

Modern IDEs have features to convert anonymous inner classes to lambda expressions.
See Comparator Functional Interface for another example of lambda expressions with the Comparator functional interface.

Method and Constructor References

A method reference refers to an existing method without invoking it. Types include static method reference, instance method of particular object, super method of particular object, and instance method of arbitrary object of particular type. Method references also include class constructor reference and array constructor reference.
"some text"::length  // Get length of String
String::length // Get length of String
CheckAcct::compareByBalance  // Static method ref
myComparator::compareByName // Inst method part obj
super::toString // Super method part object
String::compareToIgnoreCase // Inst method arb obj
ArrayList<String>::new  // New ArrayList constructor
Arrays::sort  // Sort array elements

Specific Purpose Functional Interfaces

Annotated FIs listed in Table 19-1 have been established for specific purposes relative to the packages/APIs in which they reside. Not all functional interfaces in the Java SE API are annotated.
Table 19-1. Specific-purpose FIs
APIClassMethod
AWT
KeyEventDispacter
dispatchKeyEvent (KeyEvent e)
AWT
KeyEventPostProcessor
postProcessKeyEvent (KeyEvent e)
IO
FileFilter
accept(File pathname)
IO
FilenameFilter
accept(File dir, String name)
LANG
Runnable
run ()
NIO
DirectorStream
iterator ()
NIO
PathMatcher
matches (Path path)
TIME
TemporalAdjuster
adjustInto (Temporal temporal)
TIME
TemporalQuery
queryFrom (TemporalAccessor temporal)
UTIL
Comparator
compare (T o1, T o2)
CONC
Callable
call ()
LOG
Filter
isLoggable (LogRecord record)
PREF
PreferenceChangeListener
preferenceChange (PreferenceChangeEvent evt)

General Purpose Functional Interfaces

The java.util.function package is made up of general purpose FIs for the primary use of features of the JDK. Table 19-2 lists them all.
Table 19-2. Functional interfaces functional package
Consumeraccept (T t)
BiConsumer
accept (T t, U u)
ObjDoubleConsumer
accept (T t, double value)
ObjIntConsumer
accept (T t, int value)
ObjLongConsumer
accept (T t, long value)
DoubleConsumer
accept (double value)
IntConsumer
accept (int value)
LongConsumer
accept (long value)
Function
apply (T t)
BiFunction
apply (T t, U u)
DoubleFunction
apply (double value)
IntFunction
apply (int value)
LongFunction
apply (long value)
BinaryOperator
apply (Object, Object)
ToDoubleBiFunction
applyAsDouble (T t, U u)
ToDoubleFunction
applyAsDouble (T value)
IntToDoubleFunction
applyAsDouble (int value)
LongToDoubleFunction
applyAsDouble(long value)
DoubleBinaryOperator
applyAsDouble (double left, double right)
ToIntBiFunction
applyAsInt (T t, U u)
ToIntFunction
applyAsInt (T value)
LongToIntFunction
applyAsInt (long value)
DoubleToIntFunction
applyAsInt(double value)
IntBinaryOperator
applyAsInt (int left, int right)
ToLongBiFunction
applyAsLong (T t, U u)
ToLongFunction
applyAsLong (T value)
DoubleToLongFunction
applyAsLong (double value)
IntToLongFunction
applyAsLong (int value)
LongBinaryOperator
applyAsLong (long left, long right)
BiPredicate
test (T t, U u)
Predicate
test (T t)
DoublePredicate
test (double value)
IntPredicate
test (int value)
LongPredicate
test (long value)
Supplier
get()
BooleanSupplier
getAsBoolean()
DoubleSupplier
getAsDouble()
IntSupplier
getAsInt()
LongSupplier
getAsLong()
UnaryOperator
identity()
DoubleUnaryOperator
identity()
IntUnaryOperator
applyAsInt (int operand)
LongUnaryOperator
applyAsInt (long value)

Resources for λEs

This section provides links to tutorials and community resources about λEs.

Community Resources

Online bulletin boards, mailing lists, and instructional videos provide support for learning and using λEs:

Comments

Popular posts from this blog

JPA 2 new feature @ElementCollection explained

@ElementCollection is new annotation introduced in JPA 2.0, This will help us get rid of One-Many and Many-One shitty syntax. Example 1: Stores list of Strings in an Entity @Entity public class Users implements Serializable {     private static final long serialVersionUID = 1L;     @Id     @GeneratedValue(strategy = GenerationType.AUTO)     private Long id;     @ElementCollection     private List<String> certifications = new ArrayList <String> ();     public Long getId() {         return id;     }     public void setId(Long id) {         this.id = id;     }     public List <String> getCertifications() {         return certifications;     }     pub...

Validating CSV Files

What is CsvValidator ?   A Java framework which validates any CSV files something similar to XML validation using XSD. Why should I use this ?   You don't have to use this and in fact its easy to write something your own and also checkout its source code for reference. Why did I write this ?   Some of our projects integrate with third party application which exchanges information in CSV files so I thought of writing a generic validator which can be hooked in multiple projects or can be used by QA for integration testing. What is the license clause ?   GNU GPL v2 Are there any JUnit test cases for me checkout ?  Yes,  source How to integrate in my existing project ? Just add the Jar which can be downloaded from here  CsvValidator.jar  and you are good. Instantiate  CsvValidator c onstructor which takes these 3 arguements          // filename is the the file to be validated and here ...

Reuse JPA Entities as DTO

Note : Major design advantages of JPA Entities are they can detached and used across tiers and networks and later can by merged. Checkout this new way of querying entities in JPA 2.0 String ql = " SELECT new prepclass2.Employee (e.firstname, e.lastname) FROM Employee e "; List<Employee> dtos = em.createQuery(ql).getResultList(); The above query loads all Employee entities but with subset of data i.e. firstname, lastname. Employee entity looks like this. @Entity @Table(name="emp") public class Employee implements Serializable {     private static final long serialVersionUID = 1L;     @Id     @GeneratedValue(strategy = GenerationType.AUTO)     private Long id;     @Column     private String firstname;     @Column     private String lastname;     @Column     private String username;     @Column ...