Merge branch 'master' of https://ggregory@gitbox.apache.org/repos/asf/commons-io.git
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 47f575b..0fd55aa 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -103,6 +103,8 @@
       <action dev="ggregory" type="fix"                due-to="Elliotte Rusty Harold, Gary Gregory">Clarify and correct EndianUtils and SwappedDataInputStream API doc #566.</action>
       <action dev="ggregory" type="fix"                due-to="Elliotte Rusty Harold">Add characterization test for copying a symlinked directory #570.</action>
       <action dev="ggregory" type="fix"                due-to="Gary Gregory">RandomAccessFileInputStream.builder().get() now throws ISE instead of NPE.</action>
+      <action dev="ggregory" type="fix" issue="IO-845" due-to="Elliotte Rusty Harold">Test links to targets outside the source directory #571.</action>
+      <action dev="ggregory" type="fix"                due-to="Elliotte Rusty Harold">Focus Javadoc on current version rather than past versions #573, #574.</action>
       <!-- Add -->
       <action dev="ggregory" type="add"                due-to="Gary Gregory">Add and use PathUtils.getFileName(Path, Function&lt;Path, R&gt;).</action>
       <action dev="ggregory" type="add"                due-to="Gary Gregory">Add and use PathUtils.getFileNameString().</action>
diff --git a/src/main/java/org/apache/commons/io/DirectoryWalker.java b/src/main/java/org/apache/commons/io/DirectoryWalker.java
index 55dfe90..6995ccf 100644
--- a/src/main/java/org/apache/commons/io/DirectoryWalker.java
+++ b/src/main/java/org/apache/commons/io/DirectoryWalker.java
@@ -186,11 +186,11 @@
  *
  * <p>
  * This example provides a public {@code cancel()} method that can be called by another thread to stop the
- * processing. A typical example use-case would be a cancel button on a GUI. Calling this method sets a
- * <a href="https://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#36930"> volatile</a> flag to ensure
- * it will work properly in a multi-threaded environment. The flag is returned by the {@code handleIsCancelled()}
- * method, which will cause the walk to stop immediately. The {@code handleCancelled()} method will be the next,
- * and last, callback method received once cancellation has occurred.
+ * processing. A typical example use-case is a cancel button on a GUI. Calling this method sets a
+ * <a href='https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#d5e12277'>(@code volatile}</a>
+ * flag to ensure it works properly in a multi-threaded environment.
+ * The flag is returned by the {@code handleIsCancelled()} method, which causes the walk to stop
+ * immediately. The {@code handleCancelled()} method will be the next, and last, callback method received once cancellation has occurred.
  * </p>
  *
  * <pre>
diff --git a/src/main/java/org/apache/commons/io/FileSystemUtils.java b/src/main/java/org/apache/commons/io/FileSystemUtils.java
index 91c2008..1284285 100644
--- a/src/main/java/org/apache/commons/io/FileSystemUtils.java
+++ b/src/main/java/org/apache/commons/io/FileSystemUtils.java
@@ -473,11 +473,10 @@
         //
         // This method does what it can to avoid the 'Too many open files' error
         // based on trial and error and these links:
-        // https://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4784692
-        // https://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4801027
-        // https://forum.java.sun.com/thread.jspa?threadID=533029&messageID=2572018
-        // however, it's still not perfect as the JDK support is so poor
-        // (see commons-exec or Ant for a better multithreaded multi-OS solution)
+        // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4784692
+        // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4801027
+        // However, it's still not perfect as the JDK support is so poor.
+        // (See commons-exec or Ant for a better multithreaded multi-OS solution.)
         //
         final Process proc = openProcess(cmdAttribs);
         final Thread monitor = ThreadMonitor.start(timeout);
diff --git a/src/main/java/org/apache/commons/io/FileUtils.java b/src/main/java/org/apache/commons/io/FileUtils.java
index c7bbbdf..623af97 100644
--- a/src/main/java/org/apache/commons/io/FileUtils.java
+++ b/src/main/java/org/apache/commons/io/FileUtils.java
@@ -1184,7 +1184,7 @@
                             i += 3;
                         } while (i < n && url.charAt(i) == '%');
                         continue;
-                    } catch (final RuntimeException ignored) {
+                    } catch (final IndexOutOfBoundsException | NumberFormatException ignored) {
                         // malformed percent-encoded octet, fall through and
                         // append characters literally
                     } finally {
@@ -2690,8 +2690,7 @@
      * @throws NullPointerException if file is {@code null}.
      * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a
      *         regular file, or for some other reason why the file cannot be opened for reading.
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     * .UnsupportedEncodingException} in version 2.2 if the named charset is unavailable.
+     * @throws java.nio.charset.UnsupportedCharsetException if the named charset is unavailable.
      * @since 2.3
      */
     public static String readFileToString(final File file, final String charsetName) throws IOException {
@@ -2740,8 +2739,7 @@
      * @throws NullPointerException if file is {@code null}.
      * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a
      *         regular file, or for some other reason why the file cannot be opened for reading.
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     * .UnsupportedEncodingException} in version 2.2 if the named charset is unavailable.
+     * @throws java.nio.charset.UnsupportedCharsetException if the named charset is unavailable.
      * @since 1.1
      */
     public static List<String> readLines(final File file, final String charsetName) throws IOException {
@@ -3058,11 +3056,8 @@
 
     /**
      * Implements behavior similar to the Unix "touch" utility. Creates a new file with size 0, or, if the file exists, just
-     * updates the file's modified time.
-     * <p>
-     * NOTE: As from v1.3, this method throws an IOException if the last modified date of the file cannot be set. Also, as
-     * from v1.3 this method creates parent directories if they do not exist.
-     * </p>
+     * updates the file's modified time. This method throws an IOException if the last modified date
+     * of the file cannot be set. It creates parent directories if they do not exist.
      *
      * @param file the File to touch.
      * @throws NullPointerException if the parameter is {@code null}.
@@ -3211,8 +3206,7 @@
      * @param append   if {@code true}, then the data will be added to the
      *                 end of the file rather than overwriting
      * @throws IOException                 in case of an I/O error
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported by the VM
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported by the VM
      * @since 2.1
      */
     public static void write(final File file, final CharSequence data, final String charsetName, final boolean append) throws IOException {
@@ -3223,10 +3217,7 @@
 
     /**
      * Writes a byte array to a file creating the file if it does not exist.
-     * <p>
-     * NOTE: As from v1.3, the parent directories of the file will be created
-     * if they do not exist.
-     * </p>
+     * The parent directories of the file will be created if they do not exist.
      *
      * @param file the file to write to
      * @param data the content to write to the file
@@ -3353,10 +3344,7 @@
      * Writes the {@code toString()} value of each item in a collection to
      * the specified {@link File} line by line.
      * The specified character encoding and the default line ending will be used.
-     * <p>
-     * NOTE: As from v1.3, the parent directories of the file will be created
-     * if they do not exist.
-     * </p>
+     * The parent directories of the file will be created if they do not exist.
      *
      * @param file     the file to write to
      * @param charsetName the name of the requested charset, {@code null} means platform default
@@ -3391,10 +3379,7 @@
      * Writes the {@code toString()} value of each item in a collection to
      * the specified {@link File} line by line.
      * The specified character encoding and the line ending will be used.
-     * <p>
-     * NOTE: As from v1.3, the parent directories of the file will be created
-     * if they do not exist.
-     * </p>
+     * The parent directories of the file will be created if they do not exist.
      *
      * @param file       the file to write to
      * @param charsetName   the name of the requested charset, {@code null} means platform default
@@ -3461,10 +3446,7 @@
 
     /**
      * Writes a String to a file creating the file if it does not exist.
-     * <p>
-     * NOTE: As from v1.3, the parent directories of the file will be created
-     * if they do not exist.
-     * </p>
+     * The parent directories of the file will be created if they do not exist.
      *
      * @param file     the file to write
      * @param data     the content to write to the file
@@ -3478,7 +3460,8 @@
     }
 
     /**
-     * Writes a String to a file creating the file if it does not exist.
+     * Writes a String to a file, creating the file if it does not exist.
+     * The parent directories of the file are created if they do not exist.
      *
      * @param file     the file to write
      * @param data     the content to write to the file
@@ -3495,11 +3478,8 @@
     }
 
     /**
-     * Writes a String to a file creating the file if it does not exist.
-     * <p>
-     * NOTE: As from v1.3, the parent directories of the file will be created
-     * if they do not exist.
-     * </p>
+     * Writes a String to a file, creating the file if it does not exist.
+     * The parent directories of the file are created if they do not exist.
      *
      * @param file     the file to write
      * @param data     the content to write to the file
@@ -3512,7 +3492,8 @@
     }
 
     /**
-     * Writes a String to a file creating the file if it does not exist.
+     * Writes a String to a file, creating the file if it does not exist.
+     * The parent directories of the file are created if they do not exist.
      *
      * @param file     the file to write
      * @param data     the content to write to the file
@@ -3520,8 +3501,7 @@
      * @param append   if {@code true}, then the String will be added to the
      *                 end of the file rather than overwriting
      * @throws IOException                 in case of an I/O error
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported by the VM
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported by the VM
      * @since 2.1
      */
     public static void writeStringToFile(final File file, final String data, final String charsetName, final boolean append) throws IOException {
diff --git a/src/main/java/org/apache/commons/io/IOUtils.java b/src/main/java/org/apache/commons/io/IOUtils.java
index 03a2bc2..e12a1b9 100644
--- a/src/main/java/org/apache/commons/io/IOUtils.java
+++ b/src/main/java/org/apache/commons/io/IOUtils.java
@@ -1164,7 +1164,7 @@
      * </p>
      * <p>
      * Character encoding names can be found at
-     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
+     * <a href="https://www.iana.org/assignments/character-sets">IANA</a>.
      * </p>
      * <p>
      * This method uses {@link InputStreamReader}.
@@ -1175,9 +1175,7 @@
      * @param inputCharsetName the name of the requested charset for the InputStream, null means platform default
      * @throws NullPointerException                         if the input or output is null
      * @throws IOException                                  if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     *                                                      .UnsupportedEncodingException} in version 2.2 if the
-     *                                                      encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 1.1
      */
     public static void copy(final InputStream input, final Writer writer, final String inputCharsetName)
@@ -1352,9 +1350,7 @@
      * @param outputCharsetName the name of the requested charset for the OutputStream, null means platform default
      * @throws NullPointerException                         if the input or output is null
      * @throws IOException                                  if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     *                                                      .UnsupportedEncodingException} in version 2.2 if the
-     *                                                      encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 1.1
      */
     public static void copy(final Reader reader, final OutputStream output, final String outputCharsetName)
@@ -1853,9 +1849,7 @@
      * @param charsetName the encoding to use, null means platform default
      * @return an Iterator of the lines in the reader, never null
      * @throws IllegalArgumentException                     if the input is null
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     *                                                      .UnsupportedEncodingException} in version 2.2 if the
-     *                                                      encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 1.2
      */
     public static LineIterator lineIterator(final InputStream input, final String charsetName) {
@@ -2221,9 +2215,7 @@
      * @return the list of Strings, never null
      * @throws NullPointerException                         if the input is null
      * @throws UncheckedIOException                         if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     *                                                      .UnsupportedEncodingException} in version 2.2 if the
-     *                                                      encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 1.1
      */
     public static List<String> readLines(final InputStream input, final String charsetName) throws UncheckedIOException {
@@ -2845,9 +2837,7 @@
      * @return the requested byte array
      * @throws NullPointerException                         if the input is null
      * @throws IOException                                  if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     *                                                      .UnsupportedEncodingException} in version 2.2 if the
-     *                                                      encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 1.1
      */
     public static byte[] toByteArray(final Reader reader, final String charsetName) throws IOException {
@@ -2974,9 +2964,7 @@
      * @return the requested character array
      * @throws NullPointerException                         if the input is null
      * @throws IOException                                  if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     *                                                      .UnsupportedEncodingException} in version 2.2 if the
-     *                                                      encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 1.1
      */
     public static char[] toCharArray(final InputStream inputStream, final String charsetName) throws IOException {
@@ -3040,9 +3028,7 @@
      * @param input the CharSequence to convert
      * @param charsetName the name of the requested charset, null means platform default
      * @return an input stream
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     *                                                      .UnsupportedEncodingException} in version 2.2 if the
-     *                                                      encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 2.0
      */
     public static InputStream toInputStream(final CharSequence input, final String charsetName) {
@@ -3087,9 +3073,7 @@
      * @param input the string to convert
      * @param charsetName the name of the requested charset, null means platform default
      * @return an input stream
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     *                                                      .UnsupportedEncodingException} in version 2.2 if the
-     *                                                      encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 1.1
      */
     public static InputStream toInputStream(final String input, final String charsetName) {
@@ -3186,9 +3170,7 @@
      * @return the requested String
      * @throws NullPointerException                         if the input is null
      * @throws IOException                                  if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     *                                                      .UnsupportedEncodingException} in version 2.2 if the
-     *                                                      encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      */
     public static String toString(final InputStream input, final String charsetName)
             throws IOException {
@@ -3294,9 +3276,7 @@
      * @param charsetName The encoding name for the URL contents.
      * @return The contents of the URL as a String.
      * @throws IOException                                  if an I/O exception occurs.
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     *                                                      .UnsupportedEncodingException} in version 2.2 if the
-     *                                                      encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 2.1
      */
     public static String toString(final URI uri, final String charsetName) throws IOException {
@@ -3337,9 +3317,7 @@
      * @param charsetName The encoding name for the URL contents.
      * @return The contents of the URL as a String.
      * @throws IOException                                  if an I/O exception occurs.
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     *                                                      .UnsupportedEncodingException} in version 2.2 if the
-     *                                                      encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 2.1
      */
     public static String toString(final URL url, final String charsetName) throws IOException {
@@ -3421,9 +3399,7 @@
      * @param charsetName the name of the requested charset, null means platform default
      * @throws NullPointerException                         if output is null
      * @throws IOException                                  if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     *                                                      .UnsupportedEncodingException} in version 2.2 if the
-     *                                                      encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 1.1
      */
     public static void write(final byte[] data, final Writer writer, final String charsetName) throws IOException {
@@ -3492,8 +3468,7 @@
      * @param charsetName the name of the requested charset, null means platform default
      * @throws NullPointerException                         if output is null
      * @throws IOException                                  if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 1.1
      */
     public static void write(final char[] data, final OutputStream output, final String charsetName)
@@ -3575,8 +3550,7 @@
      * @param charsetName the name of the requested charset, null means platform default
      * @throws NullPointerException        if output is null
      * @throws IOException                 if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 2.0
      */
     public static void write(final CharSequence data, final OutputStream output, final String charsetName)
@@ -3660,8 +3634,7 @@
      * @param charsetName the name of the requested charset, null means platform default
      * @throws NullPointerException        if output is null
      * @throws IOException                 if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 1.1
      */
     public static void write(final String data, final OutputStream output, final String charsetName)
@@ -3721,8 +3694,7 @@
      * @param charsetName the name of the requested charset, null means platform default
      * @throws NullPointerException        if output is null
      * @throws IOException                 if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 1.1
      * @deprecated Use {@link #write(CharSequence, OutputStream, String)}.
      */
@@ -3876,9 +3848,7 @@
      * @param charsetName the name of the requested charset, null means platform default
      * @throws NullPointerException                         if the output is null
      * @throws IOException                                  if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io
-     *                                                      .UnsupportedEncodingException} in version 2.2 if the
-     *                                                      encoding is not supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 1.1
      */
     public static void writeLines(final Collection<?> lines, final String lineEnding,
diff --git a/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java b/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java
index 8fb7ca9..cd883af 100644
--- a/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java
+++ b/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java
@@ -343,11 +343,7 @@
      *                  system).
      * @param charsetName  the encoding of the file, null uses the default Charset.
      * @throws IOException                                  if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of
-     *                                                      {@link UnsupportedEncodingException}
-     *                                                      in version 2.2 if the
-     *                                                      encoding is not
-     *                                                      supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}
      */
     @Deprecated
@@ -448,11 +444,7 @@
      *                    system).
      * @param charsetName the encoding of the file, null uses the default Charset.
      * @throws IOException                                  if an I/O error occurs
-     * @throws java.nio.charset.UnsupportedCharsetException thrown instead of
-     *                                                      {@link UnsupportedEncodingException}
-     *                                                      in version 2.2 if the
-     *                                                      encoding is not
-     *                                                      supported.
+     * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported
      * @since 2.7
      * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}
      */
diff --git a/src/main/java/org/apache/commons/io/monitor/FileAlterationObserver.java b/src/main/java/org/apache/commons/io/monitor/FileAlterationObserver.java
index a99368f..9021778 100644
--- a/src/main/java/org/apache/commons/io/monitor/FileAlterationObserver.java
+++ b/src/main/java/org/apache/commons/io/monitor/FileAlterationObserver.java
@@ -33,30 +33,26 @@
 import org.apache.commons.io.filefilter.TrueFileFilter;
 
 /**
- * FileAlterationObserver represents the state of files below a root directory,
- * checking the file system and notifying listeners of create, change or
- * delete events.
+ * FileAlterationObserver represents the state of files below a root directory, checking the file system and notifying listeners of create, change or delete
+ * events.
  * <p>
  * To use this implementation:
+ * </p>
  * <ul>
- *   <li>Create {@link FileAlterationListener} implementation(s) that process
- *      the file/directory create, change and delete events</li>
- *   <li>Register the listener(s) with a {@link FileAlterationObserver} for
- *       the appropriate directory.</li>
- *   <li>Either register the observer(s) with a {@link FileAlterationMonitor} or
- *       run manually.</li>
+ * <li>Create {@link FileAlterationListener} implementation(s) that process the file/directory create, change and delete events</li>
+ * <li>Register the listener(s) with a {@link FileAlterationObserver} for the appropriate directory.</li>
+ * <li>Either register the observer(s) with a {@link FileAlterationMonitor} or run manually.</li>
  * </ul>
- *
- * <h2>Basic Usage</h2>
- * Create a {@link FileAlterationObserver} for the directory and register the listeners:
+ * <h2>Basic Usage</h2> Create a {@link FileAlterationObserver} for the directory and register the listeners:
  * <pre>
  *      File directory = new File(FileUtils.current(), "src");
  *      FileAlterationObserver observer = new FileAlterationObserver(directory);
  *      observer.addListener(...);
  *      observer.addListener(...);
  * </pre>
- * To manually observe a directory, initialize the observer and invoked the
- * {@link #checkAndNotify()} method as required:
+ * <p>
+ * To manually observe a directory, initialize the observer and invoked the {@link #checkAndNotify()} method as required:
+ * </p>
  * <pre>
  *      // initialize
  *      observer.init();
@@ -69,8 +65,9 @@
  *      // finished
  *      observer.finish();
  * </pre>
- * Alternatively, register the observer(s) with a {@link FileAlterationMonitor},
- * which creates a new thread, invoking the observer at the specified interval:
+ * <p>
+ * Alternatively, register the observer(s) with a {@link FileAlterationMonitor}, which creates a new thread, invoking the observer at the specified interval:
+ * </p>
  * <pre>
  *      long interval = ...
  *      FileAlterationMonitor monitor = new FileAlterationMonitor(interval);
@@ -79,21 +76,16 @@
  *      ...
  *      monitor.stop();
  * </pre>
- *
- * <h2>File Filters</h2>
- * This implementation can monitor portions of the file system
- * by using {@link FileFilter}s to observe only the files and/or directories
- * that are of interest. This makes it more efficient and reduces the
- * noise from <i>unwanted</i> file system events.
+ * <h2>File Filters</h2> This implementation can monitor portions of the file system by using {@link FileFilter}s to observe only the files and/or directories
+ * that are of interest. This makes it more efficient and reduces the noise from <i>unwanted</i> file system events.
  * <p>
- * <a href="https://commons.apache.org/io/">Commons IO</a> has a good range of
- * useful, ready-made
- * <a href="../filefilter/package-summary.html">File Filter</a>
+ * <a href="https://commons.apache.org/io/">Commons IO</a> has a good range of useful, ready-made <a href="../filefilter/package-summary.html">File Filter</a>
  * implementations for this purpose.
+ * </p>
  * <p>
- * For example, to only observe 1) visible directories and 2) files with a ".java" suffix
- * in a root directory called "src" you could set up a {@link FileAlterationObserver} in the following
- * way:
+ * For example, to only observe 1) visible directories and 2) files with a ".java" suffix in a root directory called "src" you could set up a
+ * {@link FileAlterationObserver} in the following way:
+ * </p>
  * <pre>
  *      // Create a FileFilter
  *      IOFileFilter directories = FileFilterUtils.and(
@@ -109,14 +101,13 @@
  *      observer.addListener(...);
  *      observer.addListener(...);
  * </pre>
- *
  * <h2>FileEntry</h2>
- * {@link FileEntry} represents the state of a file or directory, capturing
- * {@link File} attributes at a point in time. Custom implementations of
- * {@link FileEntry} can be used to capture additional properties that the
- * basic implementation does not support. The {@link FileEntry#refresh(File)}
- * method is used to determine if a file or directory has changed since the last
- * check and stores the current state of the {@link File}'s properties.
+ * <p>
+ * {@link FileEntry} represents the state of a file or directory, capturing {@link File} attributes at a point in time. Custom
+ * implementations of {@link FileEntry} can be used to capture additional properties that the basic implementation does not support. The
+ * {@link FileEntry#refresh(File)} method is used to determine if a file or directory has changed since the last check and stores the current state of the
+ * {@link File}'s properties.
+ * </p>
  * <h2>Deprecating Serialization</h2>
  * <p>
  * <em>Serialization is deprecated and will be removed in 3.0.</em>
@@ -124,13 +115,23 @@
  *
  * @see FileAlterationListener
  * @see FileAlterationMonitor
- *
  * @since 2.0
  */
 public class FileAlterationObserver implements Serializable {
 
     private static final long serialVersionUID = 1185122225658782848L;
 
+    private static Comparator<File> toComparator(final IOCase ioCase) {
+        switch (IOCase.value(ioCase, IOCase.SYSTEM)) {
+        case SYSTEM:
+            return NameFileComparator.NAME_SYSTEM_COMPARATOR;
+        case INSENSITIVE:
+            return NameFileComparator.NAME_INSENSITIVE_COMPARATOR;
+        default:
+            return NameFileComparator.NAME_COMPARATOR;
+        }
+    }
+
     /**
      * List of listeners.
      */
@@ -154,7 +155,7 @@
     /**
      * Constructs an observer for the specified directory.
      *
-     * @param directory the directory to observe
+     * @param directory the directory to observe.
      */
     public FileAlterationObserver(final File directory) {
         this(directory, null);
@@ -163,20 +164,19 @@
     /**
      * Constructs an observer for the specified directory and file filter.
      *
-     * @param directory the directory to observe
-     * @param fileFilter The file filter or null if none
+     * @param directory  the directory to observe.
+     * @param fileFilter The file filter or null if none.
      */
     public FileAlterationObserver(final File directory, final FileFilter fileFilter) {
         this(directory, fileFilter, null);
     }
 
     /**
-     * Constructs an observer for the specified directory, file filter and
-     * file comparator.
+     * Constructs an observer for the specified directory, file filter and file comparator.
      *
-     * @param directory the directory to observe.
+     * @param directory  the directory to observe.
      * @param fileFilter The file filter or null if none.
-     * @param ioCase  what case sensitivity to use comparing file names, null means system sensitive.
+     * @param ioCase     what case sensitivity to use comparing file names, null means system sensitive.
      */
     public FileAlterationObserver(final File directory, final FileFilter fileFilter, final IOCase ioCase) {
         this(new FileEntry(directory), fileFilter, ioCase);
@@ -185,31 +185,33 @@
     /**
      * Constructs an observer for the specified directory, file filter and file comparator.
      *
-     * @param rootEntry the root directory to observe.
+     * @param rootEntry  the root directory to observe.
      * @param fileFilter The file filter or null if none.
-     * @param ioCase what case sensitivity to use comparing file names, null means system sensitive.
+     * @param comparator how to compare files.
      */
-    protected FileAlterationObserver(final FileEntry rootEntry, final FileFilter fileFilter, final IOCase ioCase) {
+    private FileAlterationObserver(final FileEntry rootEntry, final FileFilter fileFilter, final Comparator<File> comparator) {
         Objects.requireNonNull(rootEntry, "rootEntry");
         Objects.requireNonNull(rootEntry.getFile(), "rootEntry.getFile()");
         this.rootEntry = rootEntry;
         this.fileFilter = fileFilter != null ? fileFilter : TrueFileFilter.INSTANCE;
-        switch (IOCase.value(ioCase, IOCase.SYSTEM)) {
-        case SYSTEM:
-            this.comparator = NameFileComparator.NAME_SYSTEM_COMPARATOR;
-            break;
-        case INSENSITIVE:
-            this.comparator = NameFileComparator.NAME_INSENSITIVE_COMPARATOR;
-            break;
-        default:
-            this.comparator = NameFileComparator.NAME_COMPARATOR;
-        }
+        this.comparator = Objects.requireNonNull(comparator, "comparator");
+    }
+
+    /**
+     * Constructs an observer for the specified directory, file filter and file comparator.
+     *
+     * @param rootEntry  the root directory to observe.
+     * @param fileFilter The file filter or null if none.
+     * @param ioCase     what case sensitivity to use comparing file names, null means system sensitive.
+     */
+    protected FileAlterationObserver(final FileEntry rootEntry, final FileFilter fileFilter, final IOCase ioCase) {
+        this(rootEntry, fileFilter, toComparator(ioCase));
     }
 
     /**
      * Constructs an observer for the specified directory.
      *
-     * @param directoryName the name of the directory to observe
+     * @param directoryName the name of the directory to observe.
      */
     public FileAlterationObserver(final String directoryName) {
         this(new File(directoryName));
@@ -218,8 +220,8 @@
     /**
      * Constructs an observer for the specified directory and file filter.
      *
-     * @param directoryName the name of the directory to observe
-     * @param fileFilter The file filter or null if none
+     * @param directoryName the name of the directory to observe.
+     * @param fileFilter    The file filter or null if none.
      */
     public FileAlterationObserver(final String directoryName, final FileFilter fileFilter) {
         this(new File(directoryName), fileFilter);
@@ -228,9 +230,9 @@
     /**
      * Constructs an observer for the specified directory, file filter and file comparator.
      *
-     * @param directoryName the name of the directory to observe
-     * @param fileFilter The file filter or null if none
-     * @param ioCase what case sensitivity to use comparing file names, null means system sensitive
+     * @param directoryName the name of the directory to observe.
+     * @param fileFilter    The file filter or null if none.
+     * @param ioCase        what case sensitivity to use comparing file names, null means system sensitive.
      */
     public FileAlterationObserver(final String directoryName, final FileFilter fileFilter, final IOCase ioCase) {
         this(new File(directoryName), fileFilter, ioCase);
@@ -239,7 +241,7 @@
     /**
      * Adds a file system listener.
      *
-     * @param listener The file system listener
+     * @param listener The file system listener.
      */
     public void addListener(final FileAlterationListener listener) {
         if (listener != null) {
@@ -248,6 +250,39 @@
     }
 
     /**
+     * Compares two file lists for files which have been created, modified or deleted.
+     *
+     * @param parentEntry     The parent entry.
+     * @param previousEntries The original list of file entries.
+     * @param currentEntries  The current list of files entries.
+     */
+    private void checkAndFire(final FileEntry parentEntry, final FileEntry[] previousEntries, final File[] currentEntries) {
+        int c = 0;
+        final FileEntry[] actualEntries = currentEntries.length > 0 ? new FileEntry[currentEntries.length] : FileEntry.EMPTY_FILE_ENTRY_ARRAY;
+        for (final FileEntry previousEntry : previousEntries) {
+            while (c < currentEntries.length && comparator.compare(previousEntry.getFile(), currentEntries[c]) > 0) {
+                actualEntries[c] = createFileEntry(parentEntry, currentEntries[c]);
+                fireOnCreate(actualEntries[c]);
+                c++;
+            }
+            if (c < currentEntries.length && comparator.compare(previousEntry.getFile(), currentEntries[c]) == 0) {
+                fireOnChange(previousEntry, currentEntries[c]);
+                checkAndFire(previousEntry, previousEntry.getChildren(), listFiles(currentEntries[c]));
+                actualEntries[c] = previousEntry;
+                c++;
+            } else {
+                checkAndFire(previousEntry, previousEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY);
+                fireOnDelete(previousEntry);
+            }
+        }
+        for (; c < currentEntries.length; c++) {
+            actualEntries[c] = createFileEntry(parentEntry, currentEntries[c]);
+            fireOnCreate(actualEntries[c]);
+        }
+        parentEntry.setChildren(actualEntries);
+    }
+
+    /**
      * Checks whether the file and its children have been created, modified or deleted.
      */
     public void checkAndNotify() {
@@ -258,9 +293,9 @@
         // fire directory/file events
         final File rootFile = rootEntry.getFile();
         if (rootFile.exists()) {
-            checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootFile));
+            checkAndFire(rootEntry, rootEntry.getChildren(), listFiles(rootFile));
         } else if (rootEntry.isExists()) {
-            checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY);
+            checkAndFire(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY);
         }
         // Else: Didn't exist and still doesn't
 
@@ -269,56 +304,23 @@
     }
 
     /**
-     * Compares two file lists for files which have been created, modified or deleted.
-     *
-     * @param parent The parent entry
-     * @param previous The original list of files
-     * @param files  The current list of files
-     */
-    private void checkAndNotify(final FileEntry parent, final FileEntry[] previous, final File[] files) {
-        int c = 0;
-        final FileEntry[] current = files.length > 0 ? new FileEntry[files.length] : FileEntry.EMPTY_FILE_ENTRY_ARRAY;
-        for (final FileEntry entry : previous) {
-            while (c < files.length && comparator.compare(entry.getFile(), files[c]) > 0) {
-                current[c] = createFileEntry(parent, files[c]);
-                doCreate(current[c]);
-                c++;
-            }
-            if (c < files.length && comparator.compare(entry.getFile(), files[c]) == 0) {
-                doMatch(entry, files[c]);
-                checkAndNotify(entry, entry.getChildren(), listFiles(files[c]));
-                current[c] = entry;
-                c++;
-            } else {
-                checkAndNotify(entry, entry.getChildren(), FileUtils.EMPTY_FILE_ARRAY);
-                doDelete(entry);
-            }
-        }
-        for (; c < files.length; c++) {
-            current[c] = createFileEntry(parent, files[c]);
-            doCreate(current[c]);
-        }
-        parent.setChildren(current);
-    }
-
-    /**
      * Creates a new file entry for the specified file.
      *
-     * @param parent The parent file entry
-     * @param file The file to create an entry for
-     * @return A new file entry
+     * @param parent The parent file entry.
+     * @param file   The file to wrap.
+     * @return A new file entry.
      */
     private FileEntry createFileEntry(final FileEntry parent, final File file) {
         final FileEntry entry = parent.newChildInstance(file);
         entry.refresh(file);
-        entry.setChildren(doListFiles(file, entry));
+        entry.setChildren(listFileEntries(file, entry));
         return entry;
     }
 
     /**
      * Final processing.
      *
-     * @throws Exception if an error occurs
+     * @throws Exception if an error occurs.
      */
     @SuppressWarnings("unused") // Possibly thrown from subclasses.
     public void destroy() throws Exception {
@@ -326,57 +328,12 @@
     }
 
     /**
-     * Fires directory/file created events to the registered listeners.
-     *
-     * @param entry The file entry
-     */
-    private void doCreate(final FileEntry entry) {
-        listeners.forEach(listener -> {
-            if (entry.isDirectory()) {
-                listener.onDirectoryCreate(entry.getFile());
-            } else {
-                listener.onFileCreate(entry.getFile());
-            }
-        });
-        Stream.of(entry.getChildren()).forEach(this::doCreate);
-    }
-
-    /**
-     * Fires directory/file delete events to the registered listeners.
-     *
-     * @param entry The file entry
-     */
-    private void doDelete(final FileEntry entry) {
-        listeners.forEach(listener -> {
-            if (entry.isDirectory()) {
-                listener.onDirectoryDelete(entry.getFile());
-            } else {
-                listener.onFileDelete(entry.getFile());
-            }
-        });
-    }
-
-    /**
-     * Lists the files in {@code file}.
-     *
-     * @param file The file to list files for
-     * @param entry the parent entry
-     * @return The child files
-     */
-    private FileEntry[] doListFiles(final File file, final FileEntry entry) {
-        final File[] files = listFiles(file);
-        final FileEntry[] children = files.length > 0 ? new FileEntry[files.length] : FileEntry.EMPTY_FILE_ENTRY_ARRAY;
-        Arrays.setAll(children, i -> createFileEntry(entry, files[i]));
-        return children;
-    }
-
-    /**
      * Fires directory/file change events to the registered listeners.
      *
-     * @param entry The previous file system entry
-     * @param file The current file
+     * @param entry The previous file system entry.
+     * @param file  The current file.
      */
-    private void doMatch(final FileEntry entry, final File file) {
+    private void fireOnChange(final FileEntry entry, final File file) {
         if (entry.refresh(file)) {
             listeners.forEach(listener -> {
                 if (entry.isDirectory()) {
@@ -389,9 +346,40 @@
     }
 
     /**
+     * Fires directory/file created events to the registered listeners.
+     *
+     * @param entry The file entry.
+     */
+    private void fireOnCreate(final FileEntry entry) {
+        listeners.forEach(listener -> {
+            if (entry.isDirectory()) {
+                listener.onDirectoryCreate(entry.getFile());
+            } else {
+                listener.onFileCreate(entry.getFile());
+            }
+        });
+        Stream.of(entry.getChildren()).forEach(this::fireOnCreate);
+    }
+
+    /**
+     * Fires directory/file delete events to the registered listeners.
+     *
+     * @param entry The file entry.
+     */
+    private void fireOnDelete(final FileEntry entry) {
+        listeners.forEach(listener -> {
+            if (entry.isDirectory()) {
+                listener.onDirectoryDelete(entry.getFile());
+            } else {
+                listener.onFileDelete(entry.getFile());
+            }
+        });
+    }
+
+    /**
      * Returns the directory being observed.
      *
-     * @return the directory being observed
+     * @return the directory being observed.
      */
     public File getDirectory() {
         return rootEntry.getFile();
@@ -400,7 +388,7 @@
     /**
      * Returns the fileFilter.
      *
-     * @return the fileFilter
+     * @return the fileFilter.
      * @since 2.1
      */
     public FileFilter getFileFilter() {
@@ -419,39 +407,39 @@
     /**
      * Initializes the observer.
      *
-     * @throws Exception if an error occurs
+     * @throws Exception if an error occurs.
      */
     @SuppressWarnings("unused") // Possibly thrown from subclasses.
     public void initialize() throws Exception {
         rootEntry.refresh(rootEntry.getFile());
-        rootEntry.setChildren(doListFiles(rootEntry.getFile(), rootEntry));
+        rootEntry.setChildren(listFileEntries(rootEntry.getFile(), rootEntry));
     }
 
     /**
-     * Lists the contents of a directory
+     * Lists the file entries in {@code file}.
+     *
+     * @param file  The directory to list.
+     * @param entry the parent entry.
+     * @return The child file entries.
+     */
+    private FileEntry[] listFileEntries(final File file, final FileEntry entry) {
+        return Stream.of(listFiles(file)).map(f -> createFileEntry(entry, f)).toArray(FileEntry[]::new);
+    }
+
+    /**
+     * Lists the contents of a directory.
      *
      * @param directory The directory to list.
-     * @return the directory contents or a zero length array if
-     * the empty or the file is not a directory
+     * @return the directory contents or a zero length array if the empty or the file is not a directory
      */
     private File[] listFiles(final File directory) {
-        File[] children = null;
-        if (directory.isDirectory()) {
-            children = directory.listFiles(fileFilter);
-        }
-        if (children == null) {
-            children = FileUtils.EMPTY_FILE_ARRAY;
-        }
-        if (children.length > 1) {
-            Arrays.sort(children, comparator);
-        }
-        return children;
+        return directory.isDirectory() ? sort(directory.listFiles(fileFilter)) : FileUtils.EMPTY_FILE_ARRAY;
     }
 
     /**
      * Removes a file system listener.
      *
-     * @param listener The file system listener
+     * @param listener The file system listener.
      */
     public void removeListener(final FileAlterationListener listener) {
         if (listener != null) {
@@ -459,10 +447,20 @@
         }
     }
 
+    private File[] sort(final File[] files) {
+        if (files == null) {
+            return FileUtils.EMPTY_FILE_ARRAY;
+        }
+        if (files.length > 1) {
+            Arrays.sort(files, comparator);
+        }
+        return files;
+    }
+
     /**
      * Returns a String representation of this observer.
      *
-     * @return a String representation of this observer
+     * @return a String representation of this observer.
      */
     @Override
     public String toString() {
diff --git a/src/test/java/org/apache/commons/io/DirectoryWalkerTest.java b/src/test/java/org/apache/commons/io/DirectoryWalkerTest.java
index e2aa2af..9ddf56c 100644
--- a/src/test/java/org/apache/commons/io/DirectoryWalkerTest.java
+++ b/src/test/java/org/apache/commons/io/DirectoryWalkerTest.java
@@ -362,8 +362,6 @@
         checkContainsFiles("Output File", outputFiles, results);
     }
 
-    // ------------ Convenience Test Methods ------------------------------------
-
     /**
      * Test Filtering and limit to depth 0
      */
@@ -458,8 +456,6 @@
         checkContainsFiles("[DirAndFile4] File", ioFiles, resultFiles);
     }
 
-    // ------------ Test DirectoryWalker implementation --------------------------
-
     /**
      * Test Filtering
      */
@@ -471,8 +467,6 @@
         checkContainsString("Output File", outputFiles, results);
     }
 
-    // ------------ Test DirectoryWalker implementation --------------------------
-
     /**
      * test an invalid start directory
      */
@@ -484,8 +478,6 @@
 
     }
 
-    // ------------ Test DirectoryWalker implementation --------------------------
-
     /**
      * Test Limiting to current directory
      */
diff --git a/src/test/java/org/apache/commons/io/DirectoryWalkerTestCaseJava4.java b/src/test/java/org/apache/commons/io/DirectoryWalkerTestCaseJava4.java
index ca5f1b8..bd8f083 100644
--- a/src/test/java/org/apache/commons/io/DirectoryWalkerTestCaseJava4.java
+++ b/src/test/java/org/apache/commons/io/DirectoryWalkerTestCaseJava4.java
@@ -373,8 +373,6 @@
         assertTrue(results.contains(orgDir), "[B] Org Dir");
     }
 
-    // ------------ Convenience Test Methods ------------------------------------
-
     /**
      * Test Filtering and limit to depth 3
      */
diff --git a/src/test/java/org/apache/commons/io/FileUtilsTest.java b/src/test/java/org/apache/commons/io/FileUtilsTest.java
index f19ed32..2e7e48f 100644
--- a/src/test/java/org/apache/commons/io/FileUtilsTest.java
+++ b/src/test/java/org/apache/commons/io/FileUtilsTest.java
@@ -751,6 +751,38 @@
     }
 
     /**
+     * Test what happens when copyDirectory copies a directory that contains a symlink
+     * to a file outside the copied directory.
+     */
+    @Test
+    public void testCopyDirectory_symLinkExternalFile() throws Exception {
+        // make a file
+        final File content = new File(tempDirFile, "hello.txt");
+        FileUtils.writeStringToFile(content, "HELLO WORLD", "UTF8");
+
+        // Make a directory
+        final File realDirectory = new File(tempDirFile, "real_directory");
+        realDirectory.mkdir();
+
+        // Make a symlink to the file
+        final Path linkPath = realDirectory.toPath().resolve("link_to_file");
+        Files.createSymbolicLink(linkPath, content.toPath());
+
+        // Now copy the directory
+        final File destination = new File(tempDirFile, "destination");
+        FileUtils.copyDirectory(realDirectory, destination);
+
+        // test that the copied directory contains a link to the original file
+        final File copiedLink = new File(destination, "link_to_file");
+        assertTrue(Files.isSymbolicLink(copiedLink.toPath()));
+        final String actual = FileUtils.readFileToString(copiedLink, "UTF8");
+        assertEquals("HELLO WORLD", actual);
+
+        final Path source = Files.readSymbolicLink(copiedLink.toPath());
+        assertEquals(content.toPath(), source);
+    }
+
+    /**
      * See what happens when copyDirectory copies a directory that is a symlink
      * to another directory containing non-symlinked files.
      * This is a characterization test to explore current behavior, and arguably
@@ -1923,7 +1955,7 @@
         // Null reference Date
         assertThrows(NullPointerException.class, () -> FileUtils.isFileNewer(oldFile, (Date) null));
 
-        // ----- Test isFileOlder() exceptions -----
+        // Test isFileOlder() exceptions
         // Null File
         assertThrows(NullPointerException.class, () -> FileUtils.isFileOlder(null, now));
 
diff --git a/src/test/java/org/apache/commons/io/filefilter/FileFilterTest.java b/src/test/java/org/apache/commons/io/filefilter/FileFilterTest.java
index 18b6aa1..cd679db 100644
--- a/src/test/java/org/apache/commons/io/filefilter/FileFilterTest.java
+++ b/src/test/java/org/apache/commons/io/filefilter/FileFilterTest.java
@@ -978,7 +978,6 @@
         fileB.delete();
     }
 
-    // -----------------------------------------------------------------------
     @Test
     public void testMakeFileOnly() throws Exception {
         assertSame(FileFileFilter.INSTANCE, FileFilterUtils.makeFileOnly(null));
diff --git a/src/test/java/org/apache/commons/io/monitor/FileAlterationObserverTest.java b/src/test/java/org/apache/commons/io/monitor/FileAlterationObserverTest.java
index faae878..b51ffcd 100644
--- a/src/test/java/org/apache/commons/io/monitor/FileAlterationObserverTest.java
+++ b/src/test/java/org/apache/commons/io/monitor/FileAlterationObserverTest.java
@@ -76,6 +76,7 @@
 
     /**
      * Test checkAndNotify() method
+     *
      * @throws Exception
      */
     @Test
@@ -135,6 +136,7 @@
 
     /**
      * Test checkAndNotify() creating
+     *
      * @throws IOException if an I/O error occurs.
      */
     @Test
@@ -143,13 +145,13 @@
         checkCollectionsEmpty("A");
         File testDirA = new File(testDir, "test-dir-A");
         testDirA.mkdir();
-        testDir  = touch(testDir);
+        testDir = touch(testDir);
         testDirA = touch(testDirA);
-        File testDirAFile1 =       new File(testDirA, "A-file1.java");
+        File testDirAFile1 = new File(testDirA, "A-file1.java");
         final File testDirAFile2 = touch(new File(testDirA, "A-file2.java"));
-        File testDirAFile3 =       new File(testDirA, "A-file3.java");
+        File testDirAFile3 = new File(testDirA, "A-file3.java");
         final File testDirAFile4 = touch(new File(testDirA, "A-file4.java"));
-        File testDirAFile5 =       new File(testDirA, "A-file5.java");
+        File testDirAFile5 = new File(testDirA, "A-file5.java");
 
         checkAndNotify();
         checkCollectionSizes("B", 1, 0, 0, 2, 0, 0);
@@ -170,7 +172,7 @@
 
         // Create file with name < first entry
         testDirAFile1 = touch(testDirAFile1);
-        testDirA      = touch(testDirA);
+        testDirA = touch(testDirA);
         checkAndNotify();
         checkCollectionSizes("D", 0, 1, 0, 1, 0, 0);
         assertTrue(testDirAFile1.exists(), "D testDirAFile1 exists");
@@ -178,7 +180,7 @@
 
         // Create file with name between 2 entries
         testDirAFile3 = touch(testDirAFile3);
-        testDirA      = touch(testDirA);
+        testDirA = touch(testDirA);
         checkAndNotify();
         checkCollectionSizes("E", 0, 1, 0, 1, 0, 0);
         assertTrue(testDirAFile3.exists(), "E testDirAFile3 exists");
@@ -186,7 +188,7 @@
 
         // Create file with name > last entry
         testDirAFile5 = touch(testDirAFile5);
-        testDirA      = touch(testDirA);
+        testDirA = touch(testDirA);
         checkAndNotify();
         checkCollectionSizes("F", 0, 1, 0, 1, 0, 0);
         assertTrue(testDirAFile5.exists(), "F testDirAFile5 exists");
@@ -195,6 +197,7 @@
 
     /**
      * Test checkAndNotify() deleting
+     *
      * @throws IOException if an I/O error occurs.
      */
     @Test
@@ -203,7 +206,7 @@
         checkCollectionsEmpty("A");
         File testDirA = new File(testDir, "test-dir-A");
         testDirA.mkdir();
-        testDir  = touch(testDir);
+        testDir = touch(testDir);
         testDirA = touch(testDirA);
         final File testDirAFile1 = touch(new File(testDirA, "A-file1.java"));
         final File testDirAFile2 = touch(new File(testDirA, "A-file2.java"));
@@ -255,6 +258,7 @@
 
     /**
      * Test checkAndNotify() creating
+     *
      * @throws IOException if an I/O error occurs.
      */
     @Test
@@ -263,7 +267,7 @@
         checkCollectionsEmpty("A");
         File testDirA = new File(testDir, "test-dir-A");
         testDirA.mkdir();
-        testDir  = touch(testDir);
+        testDir = touch(testDir);
         testDirA = touch(testDirA);
         File testDirAFile1 = touch(new File(testDirA, "A-file1.java"));
         final File testDirAFile2 = touch(new File(testDirA, "A-file2.java"));
@@ -290,21 +294,21 @@
 
         // Update first entry
         testDirAFile1 = touch(testDirAFile1);
-        testDirA      = touch(testDirA);
+        testDirA = touch(testDirA);
         checkAndNotify();
         checkCollectionSizes("D", 0, 1, 0, 0, 1, 0);
         assertTrue(listener.getChangedFiles().contains(testDirAFile1), "D testDirAFile1");
 
         // Update file with name between 2 entries
         testDirAFile3 = touch(testDirAFile3);
-        testDirA      = touch(testDirA);
+        testDirA = touch(testDirA);
         checkAndNotify();
         checkCollectionSizes("E", 0, 1, 0, 0, 1, 0);
         assertTrue(listener.getChangedFiles().contains(testDirAFile3), "E testDirAFile3");
 
         // Update last entry
         testDirAFile5 = touch(testDirAFile5);
-        testDirA      = touch(testDirA);
+        testDirA = touch(testDirA);
         checkAndNotify();
         checkCollectionSizes("F", 0, 1, 0, 0, 1, 0);
         assertTrue(listener.getChangedFiles().contains(testDirAFile5), "F testDirAFile5");
@@ -312,6 +316,7 @@
 
     /**
      * Test checkAndNotify() method
+     *
      * @throws IOException if an I/O error occurs.
      */
     @Test
@@ -328,7 +333,7 @@
 
         // Create
         testDirAFile1 = touch(testDirAFile1);
-        File testDirAFile2 = touch(new File(testDirA, "A-file2.txt"));  /* filter should ignore */
+        File testDirAFile2 = touch(new File(testDirA, "A-file2.txt")); /* filter should ignore */
         File testDirAFile3 = touch(new File(testDirA, "A-file3.java")); /* filter should ignore */
         assertTrue(testDirAFile1.exists(), "B testDirAFile1 exists");
         assertTrue(testDirAFile2.exists(), "B testDirAFile2 exists");