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 arePath
, PathMatcher
, FileVisitor
, 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 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_MOVE
. REPLACE_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_EXISTING
, COPY_ATTRIBUTES
, or NOFOLLOW_LINKS
. REPLACE_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
lines
, list
, walk
, 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:
PathMatcher
matcher
=
(
Path
p
)
->
{
// returns boolean
return
(
p
.
toString
().
contains
(
"World"
));
};
Path
path
=
FileSystems
.
getDefault
().
getPath
(
"\\opt\\jpg\\HelloWorld.java"
);
System
.
out
.
(
"Matches: "
+
matcher
.
matches
(
path
));
$
Matches:
true
Table 15-5. Algorithm efficiencies
Algorithms Concrete type Time
get
, set
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 parameters Description
Unbounded types;
and
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
and that implements type S
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
- 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.
- 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.
jruby
[
file
.
rb
]
//Command line file
jruby
.
bat
//Windows batch file
Scripting Engine Setup
- 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.
- Find and download the scripting engine file from the external resource (e.g., website).
- 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.
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
(
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!"
);
});
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
API Class Method
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
Consumer
accept (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)
Comments