Merge
This commit is contained in:
commit
4d33158dea
124
jdk/src/share/classes/java/nio/file/FileTreeIterator.java
Normal file
124
jdk/src/share/classes/java/nio/file/FileTreeIterator.java
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.nio.file;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.nio.file.FileTreeWalker.Event;
|
||||
|
||||
/**
|
||||
* An {@code Iterator to iterate over the nodes of a file tree.
|
||||
*
|
||||
* <pre>{@code
|
||||
* try (FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options)) {
|
||||
* while (iterator.hasNext()) {
|
||||
* Event ev = iterator.next();
|
||||
* Path path = ev.file();
|
||||
* BasicFileAttributes attrs = ev.attributes();
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*/
|
||||
|
||||
class FileTreeIterator implements Iterator<Event>, Closeable {
|
||||
private final FileTreeWalker walker;
|
||||
private Event next;
|
||||
|
||||
/**
|
||||
* Creates a new iterator to walk the file tree starting at the given file.
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code maxDepth} is negative
|
||||
* @throws IOException
|
||||
* if an I/O errors occurs opening the starting file
|
||||
* @throws SecurityException
|
||||
* if the security manager denies access to the starting file
|
||||
* @throws NullPointerException
|
||||
* if {@code start} or {@code options} is {@ocde null} or
|
||||
* the options array contains a {@code null} element
|
||||
*/
|
||||
FileTreeIterator(Path start, int maxDepth, FileVisitOption... options)
|
||||
throws IOException
|
||||
{
|
||||
this.walker = new FileTreeWalker(Arrays.asList(options), maxDepth);
|
||||
this.next = walker.walk(start);
|
||||
assert next.type() == FileTreeWalker.EventType.ENTRY ||
|
||||
next.type() == FileTreeWalker.EventType.START_DIRECTORY;
|
||||
|
||||
// IOException if there a problem accessing the starting file
|
||||
IOException ioe = next.ioeException();
|
||||
if (ioe != null)
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
private void fetchNextIfNeeded() {
|
||||
if (next == null) {
|
||||
FileTreeWalker.Event ev = walker.next();
|
||||
while (ev != null) {
|
||||
IOException ioe = ev.ioeException();
|
||||
if (ioe != null)
|
||||
throw new UncheckedIOException(ioe);
|
||||
|
||||
// END_DIRECTORY events are ignored
|
||||
if (ev.type() != FileTreeWalker.EventType.END_DIRECTORY) {
|
||||
next = ev;
|
||||
return;
|
||||
}
|
||||
ev = walker.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (!walker.isOpen())
|
||||
throw new IllegalStateException();
|
||||
fetchNextIfNeeded();
|
||||
return next != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event next() {
|
||||
if (!walker.isOpen())
|
||||
throw new IllegalStateException();
|
||||
fetchNextIfNeeded();
|
||||
if (next == null)
|
||||
throw new NoSuchElementException();
|
||||
Event result = next;
|
||||
next = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
walker.close();
|
||||
}
|
||||
}
|
@ -29,8 +29,8 @@ import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import sun.nio.fs.BasicFileAttributesHolder;
|
||||
|
||||
/**
|
||||
@ -164,8 +164,17 @@ class FileTreeWalker implements Closeable {
|
||||
|
||||
/**
|
||||
* Creates a {@code FileTreeWalker}.
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code maxDepth} is negative
|
||||
* @throws ClassCastException
|
||||
* if (@code options} contains an element that is not a
|
||||
* {@code FileVisitOption}
|
||||
* @throws NullPointerException
|
||||
* if {@code options} is {@ocde null} or the options
|
||||
* array contains a {@code null} element
|
||||
*/
|
||||
FileTreeWalker(Set<FileVisitOption> options, int maxDepth) {
|
||||
FileTreeWalker(Collection<FileVisitOption> options, int maxDepth) {
|
||||
boolean fl = false;
|
||||
for (FileVisitOption option: options) {
|
||||
// will throw NPE if options contains null
|
||||
@ -175,6 +184,9 @@ class FileTreeWalker implements Closeable {
|
||||
throw new AssertionError("Should not get here");
|
||||
}
|
||||
}
|
||||
if (maxDepth < 0)
|
||||
throw new IllegalArgumentException("'maxDepth' is negative");
|
||||
|
||||
this.followLinks = fl;
|
||||
this.linkOptions = (fl) ? new LinkOption[0] :
|
||||
new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
|
||||
|
@ -29,6 +29,7 @@ import java.nio.file.attribute.*;
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
import java.nio.file.spi.FileTypeDetector;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.io.Closeable;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
@ -38,7 +39,13 @@ import java.io.BufferedWriter;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.*;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.stream.CloseableStream;
|
||||
import java.util.stream.DelegatingStream;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.nio.charset.Charset;
|
||||
@ -2587,9 +2594,6 @@ public final class Files {
|
||||
FileVisitor<? super Path> visitor)
|
||||
throws IOException
|
||||
{
|
||||
if (maxDepth < 0)
|
||||
throw new IllegalArgumentException("'maxDepth' is negative");
|
||||
|
||||
/**
|
||||
* Create a FileTreeWalker to walk the file tree, invoking the visitor
|
||||
* for each event.
|
||||
@ -3177,4 +3181,336 @@ public final class Files {
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
// -- Stream APIs --
|
||||
|
||||
/**
|
||||
* Implementation of CloseableStream
|
||||
*/
|
||||
private static class DelegatingCloseableStream<T> extends DelegatingStream<T>
|
||||
implements CloseableStream<T>
|
||||
{
|
||||
private final Closeable closeable;
|
||||
|
||||
DelegatingCloseableStream(Closeable c, Stream<T> delegate) {
|
||||
super(delegate);
|
||||
this.closeable = c;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a lazily populated {@code CloseableStream}, the elements of
|
||||
* which are the entries in the directory. The listing is not recursive.
|
||||
*
|
||||
* <p> The elements of the stream are {@link Path} objects that are
|
||||
* obtained as if by {@link Path#resolve(Path) resolving} the name of the
|
||||
* directory entry against {@code dir}. Some file systems maintain special
|
||||
* links to the directory itself and the directory's parent directory.
|
||||
* Entries representing these links are not included.
|
||||
*
|
||||
* <p> The stream is <i>weakly consistent</i>. It is thread safe but does
|
||||
* not freeze the directory while iterating, so it may (or may not)
|
||||
* reflect updates to the directory that occur after returning from this
|
||||
* method.
|
||||
*
|
||||
* <p> When not using the try-with-resources construct, then the stream's
|
||||
* {@link CloseableStream#close close} method should be invoked after the
|
||||
* operation is completed so as to free any resources held for the open
|
||||
* directory. Operating on a closed stream behaves as if the end of stream
|
||||
* has been reached. Due to read-ahead, one or more elements may be
|
||||
* returned after the stream has been closed.
|
||||
*
|
||||
* <p> If an {@link IOException} is thrown when accessing the directory
|
||||
* after this method has returned, it is wrapped in an {@link
|
||||
* UncheckedIOException} which will be thrown from the method that caused
|
||||
* the access to take place.
|
||||
*
|
||||
* @param dir The path to the directory
|
||||
*
|
||||
* @return The {@code CloseableStream} describing the content of the
|
||||
* directory
|
||||
*
|
||||
* @throws NotDirectoryException
|
||||
* if the file could not otherwise be opened because it is not
|
||||
* a directory <i>(optional specific exception)</i>
|
||||
* @throws IOException
|
||||
* if an I/O error occurs when opening the directory
|
||||
* @throws SecurityException
|
||||
* In the case of the default provider, and a security manager is
|
||||
* installed, the {@link SecurityManager#checkRead(String) checkRead}
|
||||
* method is invoked to check read access to the directory.
|
||||
*
|
||||
* @see #newDirectoryStream(Path)
|
||||
* @since 1.8
|
||||
*/
|
||||
public static CloseableStream<Path> list(Path dir) throws IOException {
|
||||
DirectoryStream<Path> ds = Files.newDirectoryStream(dir);
|
||||
final Iterator<Path> delegate = ds.iterator();
|
||||
|
||||
// Re-wrap DirectoryIteratorException to UncheckedIOException
|
||||
Iterator<Path> it = new Iterator<Path>() {
|
||||
public boolean hasNext() {
|
||||
try {
|
||||
return delegate.hasNext();
|
||||
} catch (DirectoryIteratorException e) {
|
||||
throw new UncheckedIOException(e.getCause());
|
||||
}
|
||||
}
|
||||
public Path next() {
|
||||
try {
|
||||
return delegate.next();
|
||||
} catch (DirectoryIteratorException e) {
|
||||
throw new UncheckedIOException(e.getCause());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return new DelegatingCloseableStream<>(ds,
|
||||
StreamSupport.stream(Spliterators.spliteratorUnknownSize(it,
|
||||
Spliterator.DISTINCT)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code CloseableStream} that is lazily populated with {@code
|
||||
* Path} by walking the file tree rooted at a given starting file. The
|
||||
* file tree is traversed <em>depth-first</em>, the elements in the stream
|
||||
* are {@link Path} objects that are obtained as if by {@link
|
||||
* Path#resolve(Path) resolving} the relative path against {@code start}.
|
||||
*
|
||||
* <p> The {@code stream} walks the file tree as elements are consumed.
|
||||
* The {@code CloseableStream} returned is guaranteed to have at least one
|
||||
* element, the starting file itself. For each file visited, the stream
|
||||
* attempts to read its {@link BasicFileAttributes}. If the file is a
|
||||
* directory and can be opened successfully, entries in the directory, and
|
||||
* their <em>descendants</em> will follow the directory in the stream as
|
||||
* they are encountered. When all entries have been visited, then the
|
||||
* directory is closed. The file tree walk then continues at the next
|
||||
* <em>sibling</em> of the directory.
|
||||
*
|
||||
* <p> The stream is <i>weakly consistent</i>. It does not freeze the
|
||||
* file tree while iterating, so it may (or may not) reflect updates to
|
||||
* the file tree that occur after returned from this method.
|
||||
*
|
||||
* <p> By default, symbolic links are not automatically followed by this
|
||||
* method. If the {@code options} parameter contains the {@link
|
||||
* FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then symbolic links are
|
||||
* followed. When following links, and the attributes of the target cannot
|
||||
* be read, then this method attempts to get the {@code BasicFileAttributes}
|
||||
* of the link.
|
||||
*
|
||||
* <p> If the {@code options} parameter contains the {@link
|
||||
* FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then the stream keeps
|
||||
* track of directories visited so that cycles can be detected. A cycle
|
||||
* arises when there is an entry in a directory that is an ancestor of the
|
||||
* directory. Cycle detection is done by recording the {@link
|
||||
* java.nio.file.attribute.BasicFileAttributes#fileKey file-key} of directories,
|
||||
* or if file keys are not available, by invoking the {@link #isSameFile
|
||||
* isSameFile} method to test if a directory is the same file as an
|
||||
* ancestor. When a cycle is detected it is treated as an I/O error with
|
||||
* an instance of {@link FileSystemLoopException}.
|
||||
*
|
||||
* <p> The {@code maxDepth} parameter is the maximum number of levels of
|
||||
* directories to visit. A value of {@code 0} means that only the starting
|
||||
* file is visited, unless denied by the security manager. A value of
|
||||
* {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all
|
||||
* levels should be visited.
|
||||
*
|
||||
* <p> When a security manager is installed and it denies access to a file
|
||||
* (or directory), then it is ignored and not included in the stream.
|
||||
*
|
||||
* <p> When not using the try-with-resources construct, then the stream's
|
||||
* {@link CloseableStream#close close} method should be invoked after the
|
||||
* operation is completed so as to free any resources held for the open
|
||||
* directory. Operate the stream after it is closed will throw an
|
||||
* {@link java.lang.IllegalStateException}.
|
||||
*
|
||||
* <p> If an {@link IOException} is thrown when accessing the directory
|
||||
* after this method has returned, it is wrapped in an {@link
|
||||
* UncheckedIOException} which will be thrown from the method that caused
|
||||
* the access to take place.
|
||||
*
|
||||
* @param start
|
||||
* the starting file
|
||||
* @param maxDepth
|
||||
* the maximum number of directory levels to visit
|
||||
* @param options
|
||||
* options to configure the traversal
|
||||
*
|
||||
* @return the {@link CloseableStream} of {@link Path}
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if the {@code maxDepth} parameter is negative
|
||||
* @throws SecurityException
|
||||
* If the security manager denies access to the starting file.
|
||||
* In the case of the default provider, the {@link
|
||||
* SecurityManager#checkRead(String) checkRead} method is invoked
|
||||
* to check read access to the directory.
|
||||
* @throws IOException
|
||||
* if an I/O error is thrown when accessing the starting file.
|
||||
* @since 1.8
|
||||
*/
|
||||
public static CloseableStream<Path> walk(Path start, int maxDepth,
|
||||
FileVisitOption... options)
|
||||
throws IOException
|
||||
{
|
||||
FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
|
||||
return new DelegatingCloseableStream<>(iterator,
|
||||
StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT))
|
||||
.map(entry -> entry.file()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code CloseableStream} that is lazily populated with {@code
|
||||
* Path} by walking the file tree rooted at a given starting file. The
|
||||
* file tree is traversed <em>depth-first</em>, the elements in the stream
|
||||
* are {@link Path} objects that are obtained as if by {@link
|
||||
* Path#resolve(Path) resolving} the relative path against {@code start}.
|
||||
*
|
||||
* <p> This method works as if invoking it were equivalent to evaluating the
|
||||
* expression:
|
||||
* <blockquote><pre>
|
||||
* walk(start, Integer.MAX_VALUE, options)
|
||||
* </pre></blockquote>
|
||||
* In other words, it visits all levels of the file tree.
|
||||
*
|
||||
* @param start
|
||||
* the starting file
|
||||
* @param options
|
||||
* options to configure the traversal
|
||||
*
|
||||
* @return the {@link CloseableStream} of {@link Path}
|
||||
*
|
||||
* @throws SecurityException
|
||||
* If the security manager denies access to the starting file.
|
||||
* In the case of the default provider, the {@link
|
||||
* SecurityManager#checkRead(String) checkRead} method is invoked
|
||||
* to check read access to the directory.
|
||||
* @throws IOException
|
||||
* if an I/O error is thrown when accessing the starting file.
|
||||
*
|
||||
* @see #walk(Path, int, FileVisitOption...)
|
||||
* @since 1.8
|
||||
*/
|
||||
public static CloseableStream<Path> walk(Path start,
|
||||
FileVisitOption... options)
|
||||
throws IOException
|
||||
{
|
||||
return walk(start, Integer.MAX_VALUE, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code CloseableStream} that is lazily populated with {@code
|
||||
* Path} by searching for files in a file tree rooted at a given starting
|
||||
* file.
|
||||
*
|
||||
* <p> This method walks the file tree in exactly the manner specified by
|
||||
* the {@link #walk walk} method. For each file encountered, the given
|
||||
* {@link BiPredicate} is invoked with its {@link Path} and {@link
|
||||
* BasicFileAttributes}. The {@code Path} object is obtained as if by
|
||||
* {@link Path#resolve(Path) resolving} the relative path against {@code
|
||||
* start} and is only included in the returned {@link CloseableStream} if
|
||||
* the {@code BiPredicate} returns true. Compare to calling {@link
|
||||
* java.util.stream.Stream#filter filter} on the {@code Stream}
|
||||
* returned by {@code walk} method, this method may be more efficient by
|
||||
* avoiding redundant retrieval of the {@code BasicFileAttributes}.
|
||||
*
|
||||
* <p> If an {@link IOException} is thrown when accessing the directory
|
||||
* after returned from this method, it is wrapped in an {@link
|
||||
* UncheckedIOException} which will be thrown from the method that caused
|
||||
* the access to take place.
|
||||
*
|
||||
* @param start
|
||||
* the starting file
|
||||
* @param maxDepth
|
||||
* the maximum number of directory levels to search
|
||||
* @param matcher
|
||||
* the function used to decide whether a file should be included
|
||||
* in the returned stream
|
||||
* @param options
|
||||
* options to configure the traversal
|
||||
*
|
||||
* @return the {@link CloseableStream} of {@link Path}
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if the {@code maxDepth} parameter is negative
|
||||
* @throws SecurityException
|
||||
* If the security manager denies access to the starting file.
|
||||
* In the case of the default provider, the {@link
|
||||
* SecurityManager#checkRead(String) checkRead} method is invoked
|
||||
* to check read access to the directory.
|
||||
* @throws IOException
|
||||
* if an I/O error is thrown when accessing the starting file.
|
||||
*
|
||||
* @see #walk(Path, int, FileVisitOption...)
|
||||
* @since 1.8
|
||||
*/
|
||||
public static CloseableStream<Path> find(Path start,
|
||||
int maxDepth,
|
||||
BiPredicate<Path, BasicFileAttributes> matcher,
|
||||
FileVisitOption... options)
|
||||
throws IOException
|
||||
{
|
||||
FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
|
||||
return new DelegatingCloseableStream<>(iterator,
|
||||
StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT))
|
||||
.filter(entry -> matcher.test(entry.file(), entry.attributes()))
|
||||
.map(entry -> entry.file()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all lines from a file as a {@code CloseableStream}. Unlike {@link
|
||||
* #readAllLines(Path, Charset) readAllLines}, this method does not read
|
||||
* all lines into a {@code List}, but instead populates lazily as the stream
|
||||
* is consumed.
|
||||
*
|
||||
* <p> Bytes from the file are decoded into characters using the specified
|
||||
* charset and the same line terminators as specified by {@code
|
||||
* readAllLines} are supported.
|
||||
*
|
||||
* <p> After this method returns, then any subsequent I/O exception that
|
||||
* occurs while reading from the file or when a malformed or unmappable byte
|
||||
* sequence is read, is wrapped in an {@link UncheckedIOException} that will
|
||||
* be thrown form the
|
||||
* {@link java.util.stream.Stream} method that caused the read to take
|
||||
* place. In case an {@code IOException} is thrown when closing the file,
|
||||
* it is also wrapped as an {@code UncheckedIOException}.
|
||||
*
|
||||
* <p> When not using the try-with-resources construct, then stream's
|
||||
* {@link CloseableStream#close close} method should be invoked after
|
||||
* operation is completed so as to free any resources held for the open
|
||||
* file.
|
||||
*
|
||||
* @param path
|
||||
* the path to the file
|
||||
* @param cs
|
||||
* the charset to use for decoding
|
||||
*
|
||||
* @return the lines from the file as a {@code CloseableStream}
|
||||
*
|
||||
* @throws IOException
|
||||
* if an I/O error occurs opening the file
|
||||
* @throws SecurityException
|
||||
* In the case of the default provider, and a security manager is
|
||||
* installed, the {@link SecurityManager#checkRead(String) checkRead}
|
||||
* method is invoked to check read access to the file.
|
||||
*
|
||||
* @see #readAllLines(Path, Charset)
|
||||
* @see #newBufferedReader(Path, Charset)
|
||||
* @see java.io.BufferedReader#lines()
|
||||
* @since 1.8
|
||||
*/
|
||||
public static CloseableStream<String> lines(Path path, Charset cs)
|
||||
throws IOException
|
||||
{
|
||||
BufferedReader br = Files.newBufferedReader(path, cs);
|
||||
return new DelegatingCloseableStream<>(br, br.lines());
|
||||
}
|
||||
}
|
||||
|
@ -140,32 +140,32 @@ import java.util.function.LongConsumer;
|
||||
* (in approximate order of decreasing desirability):
|
||||
* <ul>
|
||||
* <li>The source cannot be structurally interfered with.
|
||||
* </br>For example, an instance of
|
||||
* <br>For example, an instance of
|
||||
* {@link java.util.concurrent.CopyOnWriteArrayList} is an immutable source.
|
||||
* A Spliterator created from the source reports a characteristic of
|
||||
* {@code IMMUTABLE}.</li>
|
||||
* <li>The source manages concurrent modifications.
|
||||
* </br>For example, a key set of a {@link java.util.concurrent.ConcurrentHashMap}
|
||||
* <br>For example, a key set of a {@link java.util.concurrent.ConcurrentHashMap}
|
||||
* is a concurrent source. A Spliterator created from the source reports a
|
||||
* characteristic of {@code CONCURRENT}.</li>
|
||||
* <li>The mutable source provides a late-binding and fail-fast Spliterator.
|
||||
* </br>Late binding narrows the window during which interference can affect
|
||||
* <br>Late binding narrows the window during which interference can affect
|
||||
* the calculation; fail-fast detects, on a best-effort basis, that structural
|
||||
* interference has occurred after traversal has commenced and throws
|
||||
* {@link ConcurrentModificationException}. For example, {@link ArrayList},
|
||||
* and many other non-concurrent {@code Collection} classes in the JDK, provide
|
||||
* a late-binding, fail-fast spliterator.</li>
|
||||
* <li>The mutable source provides a non-late-binding but fail-fast Spliterator.
|
||||
* </br>The source increases the likelihood of throwing
|
||||
* <br>The source increases the likelihood of throwing
|
||||
* {@code ConcurrentModificationException} since the window of potential
|
||||
* interference is larger.</li>
|
||||
* <li>The mutable source provides a late-binding and non-fail-fast Spliterator.
|
||||
* </br>The source risks arbitrary, non-deterministic behavior after traversal
|
||||
* <br>The source risks arbitrary, non-deterministic behavior after traversal
|
||||
* has commenced since interference is not detected.
|
||||
* </li>
|
||||
* <li>The mutable source provides a non-late-binding and non-fail-fast
|
||||
* Spliterator.
|
||||
* </br>The source increases the risk of arbitrary, non-deterministic behavior
|
||||
* <br>The source increases the risk of arbitrary, non-deterministic behavior
|
||||
* since non-detected interference may occur after construction.
|
||||
* </li>
|
||||
* </ul>
|
||||
@ -284,6 +284,8 @@ import java.util.function.LongConsumer;
|
||||
* is set to {@code true} then diagnostic warnings are reported if boxing of
|
||||
* primitive values occur when operating on primitive subtype specializations.
|
||||
*
|
||||
* @param <T> the type of elements returned by this Spliterator
|
||||
*
|
||||
* @see Collection
|
||||
* @since 1.8
|
||||
*/
|
||||
@ -333,9 +335,8 @@ public interface Spliterator<T> {
|
||||
* Upon non-null return:
|
||||
* <ul>
|
||||
* <li>the value reported for {@code estimateSize()} before splitting,
|
||||
* if not already zero or {@code Long.MAX_VALUE}, must, after splitting, be
|
||||
* greater than {@code estimateSize()} for this and the returned
|
||||
* Spliterator; and</li>
|
||||
* must, after splitting, be greater than or equal to {@code estimateSize()}
|
||||
* for this and the returned Spliterator; and</li>
|
||||
* <li>if this Spliterator is {@code SUBSIZED}, then {@code estimateSize()}
|
||||
* for this spliterator before splitting must be equal to the sum of
|
||||
* {@code estimateSize()} for this and the returned Spliterator after
|
||||
@ -566,13 +567,28 @@ public interface Spliterator<T> {
|
||||
public static final int SUBSIZED = 0x00004000;
|
||||
|
||||
/**
|
||||
* A Spliterator specialized for {@code int} values.
|
||||
* A Spliterator specialized for primitive values.
|
||||
*
|
||||
* @param <T> the type of elements returned by this Spliterator. The
|
||||
* type must be a wrapper type for a primitive type, such as {@code Integer}
|
||||
* for the primitive {@code int} type.
|
||||
* @param <T_CONS> the type of primitive consumer. The type must be a
|
||||
* primitive specialization of {@link java.util.function.Consumer} for
|
||||
* {@code T}, such as {@link java.util.function.IntConsumer} for
|
||||
* {@code Integer}.
|
||||
* @param <T_SPLITR> the type of primitive Spliterator. The type must be
|
||||
* a primitive specialization of Spliterator for {@code T}, such as
|
||||
* {@link Spliterator.OfInt} for {@code Integer}.
|
||||
*
|
||||
* @see Spliterator.OfInt
|
||||
* @see Spliterator.OfLong
|
||||
* @see Spliterator.OfDouble
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface OfInt extends Spliterator<Integer> {
|
||||
|
||||
public interface OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
|
||||
extends Spliterator<T> {
|
||||
@Override
|
||||
OfInt trySplit();
|
||||
T_SPLITR trySplit();
|
||||
|
||||
/**
|
||||
* If a remaining element exists, performs the given action on it,
|
||||
@ -586,7 +602,7 @@ public interface Spliterator<T> {
|
||||
* upon entry to this method, else {@code true}.
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
boolean tryAdvance(IntConsumer action);
|
||||
boolean tryAdvance(T_CONS action);
|
||||
|
||||
/**
|
||||
* Performs the given action for each remaining element, sequentially in
|
||||
@ -603,6 +619,24 @@ public interface Spliterator<T> {
|
||||
* @param action The action
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
default void forEachRemaining(T_CONS action) {
|
||||
do { } while (tryAdvance(action));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Spliterator specialized for {@code int} values.
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> {
|
||||
|
||||
@Override
|
||||
OfInt trySplit();
|
||||
|
||||
@Override
|
||||
boolean tryAdvance(IntConsumer action);
|
||||
|
||||
@Override
|
||||
default void forEachRemaining(IntConsumer action) {
|
||||
do { } while (tryAdvance(action));
|
||||
}
|
||||
@ -658,40 +692,15 @@ public interface Spliterator<T> {
|
||||
* A Spliterator specialized for {@code long} values.
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface OfLong extends Spliterator<Long> {
|
||||
public interface OfLong extends OfPrimitive<Long, LongConsumer, OfLong> {
|
||||
|
||||
@Override
|
||||
OfLong trySplit();
|
||||
|
||||
/**
|
||||
* If a remaining element exists, performs the given action on it,
|
||||
* returning {@code true}; else returns {@code false}. If this
|
||||
* Spliterator is {@link #ORDERED} the action is performed on the
|
||||
* next element in encounter order. Exceptions thrown by the
|
||||
* action are relayed to the caller.
|
||||
*
|
||||
* @param action The action
|
||||
* @return {@code false} if no remaining elements existed
|
||||
* upon entry to this method, else {@code true}.
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
@Override
|
||||
boolean tryAdvance(LongConsumer action);
|
||||
|
||||
/**
|
||||
* Performs the given action for each remaining element, sequentially in
|
||||
* the current thread, until all elements have been processed or the
|
||||
* action throws an exception. If this Spliterator is {@link #ORDERED},
|
||||
* actions are performed in encounter order. Exceptions thrown by the
|
||||
* action are relayed to the caller.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation repeatedly invokes {@link #tryAdvance}
|
||||
* until it returns {@code false}. It should be overridden whenever
|
||||
* possible.
|
||||
*
|
||||
* @param action The action
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
@Override
|
||||
default void forEachRemaining(LongConsumer action) {
|
||||
do { } while (tryAdvance(action));
|
||||
}
|
||||
@ -747,40 +756,15 @@ public interface Spliterator<T> {
|
||||
* A Spliterator specialized for {@code double} values.
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface OfDouble extends Spliterator<Double> {
|
||||
public interface OfDouble extends OfPrimitive<Double, DoubleConsumer, OfDouble> {
|
||||
|
||||
@Override
|
||||
OfDouble trySplit();
|
||||
|
||||
/**
|
||||
* If a remaining element exists, performs the given action on it,
|
||||
* returning {@code true}; else returns {@code false}. If this
|
||||
* Spliterator is {@link #ORDERED} the action is performed on the
|
||||
* next element in encounter order. Exceptions thrown by the
|
||||
* action are relayed to the caller.
|
||||
*
|
||||
* @param action The action
|
||||
* @return {@code false} if no remaining elements existed
|
||||
* upon entry to this method, else {@code true}.
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
@Override
|
||||
boolean tryAdvance(DoubleConsumer action);
|
||||
|
||||
/**
|
||||
* Performs the given action for each remaining element, sequentially in
|
||||
* the current thread, until all elements have been processed or the
|
||||
* action throws an exception. If this Spliterator is {@link #ORDERED},
|
||||
* actions are performed in encounter order. Exceptions thrown by the
|
||||
* action are relayed to the caller.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation repeatedly invokes {@link #tryAdvance}
|
||||
* until it returns {@code false}. It should be overridden whenever
|
||||
* possible.
|
||||
*
|
||||
* @param action The action
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
@Override
|
||||
default void forEachRemaining(DoubleConsumer action) {
|
||||
do { } while (tryAdvance(action));
|
||||
}
|
||||
|
@ -24,14 +24,16 @@
|
||||
*/
|
||||
package java.util.function;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* An operation which accepts two input arguments and returns no result. This is
|
||||
* the two-arity specialization of {@link Consumer}. Unlike most other
|
||||
* functional interfaces, {@code BiConsumer} is expected to operate via
|
||||
* side-effects.
|
||||
*
|
||||
* @param <T> the type of the first argument to the {@code accept} operation.
|
||||
* @param <U> the type of the second argument to the {@code accept} operation.
|
||||
* @param <T> the type of the first argument to the {@code accept} operation
|
||||
* @param <U> the type of the second argument to the {@code accept} operation
|
||||
*
|
||||
* @see Consumer
|
||||
* @since 1.8
|
||||
@ -47,4 +49,28 @@ public interface BiConsumer<T, U> {
|
||||
* @param u an input object
|
||||
*/
|
||||
void accept(T t, U u);
|
||||
|
||||
/**
|
||||
* Returns a {@code BiConsumer} which performs, in sequence, the operation
|
||||
* represented by this object followed by the operation represented by
|
||||
* the other {@code BiConsumer}.
|
||||
*
|
||||
* <p>Any exceptions thrown by either {@code accept} method are relayed
|
||||
* to the caller; if performing this operation throws an exception, the
|
||||
* other operation will not be performed.
|
||||
*
|
||||
* @param other a BiConsumer which will be chained after this BiConsumer
|
||||
* @return a BiConsumer which performs in sequence the {@code accept} method
|
||||
* of this BiConsumer and the {@code accept} method of the specified
|
||||
* BiConsumer operation
|
||||
* @throws NullPointerException if other is null
|
||||
*/
|
||||
default BiConsumer<T, U> chain(BiConsumer<? super T, ? super U> other) {
|
||||
Objects.requireNonNull(other);
|
||||
|
||||
return (l, r) -> {
|
||||
accept(l, r);
|
||||
other.accept(l, r);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -24,15 +24,17 @@
|
||||
*/
|
||||
package java.util.function;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Apply a function to the input arguments, yielding an appropriate result. This
|
||||
* is the two-arity specialization of {@link Function}. A function may
|
||||
* variously provide a mapping between types, object instances or keys and
|
||||
* values or any other form of transformation upon the input.
|
||||
*
|
||||
* @param <T> the type of the first argument to the {@code apply} operation.
|
||||
* @param <U> the type of the second argument to the {@code apply} operation.
|
||||
* @param <R> the type of results returned by the {@code apply} operation.
|
||||
* @param <T> the type of the first argument to the {@code apply} operation
|
||||
* @param <U> the type of the second argument to the {@code apply} operation
|
||||
* @param <R> the type of results returned by the {@code apply} operation
|
||||
*
|
||||
* @see Function
|
||||
* @since 1.8
|
||||
@ -48,4 +50,22 @@ public interface BiFunction<T, U, R> {
|
||||
* @return the function result
|
||||
*/
|
||||
R apply(T t, U u);
|
||||
|
||||
/**
|
||||
* Returns a new function which applies this function followed by the
|
||||
* provided function. If either function throws an exception, it is relayed
|
||||
* to the caller.
|
||||
*
|
||||
* @param <V> Type of output objects to the combined function. May be the
|
||||
* same type as {@code <T>}, {@code <U>} or {@code <R>}
|
||||
* @param after An additional function to be applied after this function is
|
||||
* applied
|
||||
* @return A function which performs this function followed by the provided
|
||||
* function
|
||||
* @throws NullPointerException if after is null
|
||||
*/
|
||||
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
|
||||
Objects.requireNonNull(after);
|
||||
return (T t, U u) -> after.apply(apply(t, u));
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ import java.util.Objects;
|
||||
* Determines if the input objects match some criteria. This is the two-arity
|
||||
* specialization of {@link Predicate}.
|
||||
*
|
||||
* @param <T> the type of the first argument to {@code test}.
|
||||
* @param <U> the type of the second argument to {@code test}.
|
||||
* @param <T> the type of the first argument to {@code test}
|
||||
* @param <U> the type of the second argument to {@code test}
|
||||
*
|
||||
* @see Predicate
|
||||
* @since 1.8
|
||||
@ -42,9 +42,9 @@ public interface BiPredicate<T, U> {
|
||||
/**
|
||||
* Return {@code true} if the inputs match some criteria.
|
||||
*
|
||||
* @param t an input object.
|
||||
* @param u an input object.
|
||||
* @return {@code true} if the inputs match some criteria.
|
||||
* @param t an input object
|
||||
* @param u an input object
|
||||
* @return {@code true} if the inputs match some criteria
|
||||
*/
|
||||
boolean test(T t, U u);
|
||||
|
||||
@ -54,11 +54,12 @@ public interface BiPredicate<T, U> {
|
||||
* this predicate returns {@code false} then the remaining predicate is not
|
||||
* evaluated.
|
||||
*
|
||||
* @param p a predicate which will be logically-ANDed with this predicate.
|
||||
* @param p a predicate which will be logically-ANDed with this predicate
|
||||
* @return a new predicate which returns {@code true} only if both
|
||||
* predicates return {@code true}.
|
||||
* predicates return {@code true}
|
||||
* @throws NullPointerException if p is null
|
||||
*/
|
||||
public default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> p) {
|
||||
default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (T t, U u) -> test(t, u) && p.test(t, u);
|
||||
}
|
||||
@ -67,9 +68,9 @@ public interface BiPredicate<T, U> {
|
||||
* Returns a predicate which negates the result of this predicate.
|
||||
*
|
||||
* @return a new predicate who's result is always the opposite of this
|
||||
* predicate.
|
||||
* predicate
|
||||
*/
|
||||
public default BiPredicate<T, U> negate() {
|
||||
default BiPredicate<T, U> negate() {
|
||||
return (T t, U u) -> !test(t, u);
|
||||
}
|
||||
|
||||
@ -79,25 +80,13 @@ public interface BiPredicate<T, U> {
|
||||
* predicate returns {@code true} then the remaining predicate is not
|
||||
* evaluated.
|
||||
*
|
||||
* @param p a predicate which will be logically-ORed with this predicate.
|
||||
* @param p a predicate which will be logically-ORed with this predicate
|
||||
* @return a new predicate which returns {@code true} if either predicate
|
||||
* returns {@code true}.
|
||||
* returns {@code true}
|
||||
* @throws NullPointerException if p is null
|
||||
*/
|
||||
public default BiPredicate<T, U> or(BiPredicate<? super T, ? super U> p) {
|
||||
default BiPredicate<T, U> or(BiPredicate<? super T, ? super U> p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (T t, U u) -> test(t, u) || p.test(t, u);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a predicate that evaluates to {@code true} if both or neither of
|
||||
* the component predicates evaluate to {@code true}.
|
||||
*
|
||||
* @param p a predicate which will be logically-XORed with this predicate.
|
||||
* @return a predicate that evaluates to {@code true} if both or neither of
|
||||
* the component predicates evaluate to {@code true}.
|
||||
*/
|
||||
public default BiPredicate<T, U> xor(BiPredicate<? super T, ? super U> p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (T t, U u) -> test(t, u) ^ p.test(t, u);
|
||||
}
|
||||
}
|
||||
|
@ -40,5 +40,5 @@ public interface BooleanSupplier {
|
||||
*
|
||||
* @return a {@code boolean} value
|
||||
*/
|
||||
public boolean getAsBoolean();
|
||||
boolean getAsBoolean();
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
*/
|
||||
package java.util.function;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* An operation which accepts a single input argument and returns no result.
|
||||
* Unlike most other functional interfaces, {@code Consumer} is expected to
|
||||
@ -41,5 +43,25 @@ public interface Consumer<T> {
|
||||
*
|
||||
* @param t the input object
|
||||
*/
|
||||
public void accept(T t);
|
||||
void accept(T t);
|
||||
|
||||
/**
|
||||
* Returns a {@code Consumer} which performs, in sequence, the operation
|
||||
* represented by this object followed by the operation represented by
|
||||
* the other {@code Consumer}.
|
||||
*
|
||||
* <p>Any exceptions thrown by either {@code accept} method are relayed
|
||||
* to the caller; if performing this operation throws an exception, the
|
||||
* other operation will not be performed.
|
||||
*
|
||||
* @param other a Consumer which will be chained after this Consumer
|
||||
* @return a Consumer which performs in sequence the {@code accept} method
|
||||
* of this Consumer and the {@code accept} method of the specified Consumer
|
||||
* operation
|
||||
* @throws NullPointerException if other is null
|
||||
*/
|
||||
default Consumer<T> chain(Consumer<? super T> other) {
|
||||
Objects.requireNonNull(other);
|
||||
return (T t) -> { accept(t); other.accept(t); };
|
||||
}
|
||||
}
|
||||
|
@ -43,5 +43,5 @@ public interface DoubleBinaryOperator {
|
||||
* @param right the right operand value
|
||||
* @return the result of the operation
|
||||
*/
|
||||
public double applyAsDouble(double left, double right);
|
||||
double applyAsDouble(double left, double right);
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
*/
|
||||
package java.util.function;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* An operation which accepts a single double argument and returns no result.
|
||||
* This is the primitive type specialization of {@link Consumer} for
|
||||
@ -41,5 +43,26 @@ public interface DoubleConsumer {
|
||||
*
|
||||
* @param value the input value
|
||||
*/
|
||||
public void accept(double value);
|
||||
void accept(double value);
|
||||
|
||||
/**
|
||||
* Returns a {@code DoubleConsumer} which performs, in sequence, the operation
|
||||
* represented by this object followed by the operation represented by
|
||||
* another {@code DoubleConsumer}.
|
||||
*
|
||||
* <p>Any exceptions thrown by either {@code accept} method are relayed
|
||||
* to the caller; if performing this operation throws an exception, the
|
||||
* other operation will not be performed.
|
||||
*
|
||||
* @param other a DoubleConsumer which will be chained after this
|
||||
* DoubleConsumer
|
||||
* @return an DoubleConsumer which performs in sequence the {@code accept} method
|
||||
* of this DoubleConsumer and the {@code accept} method of the specified IntConsumer
|
||||
* operation
|
||||
* @throws NullPointerException if other is null
|
||||
*/
|
||||
default DoubleConsumer chain(DoubleConsumer other) {
|
||||
Objects.requireNonNull(other);
|
||||
return (double t) -> { accept(t); other.accept(t); };
|
||||
}
|
||||
}
|
||||
|
@ -43,5 +43,5 @@ public interface DoubleFunction<R> {
|
||||
* @param value the input value
|
||||
* @return the function result
|
||||
*/
|
||||
public R apply(double value);
|
||||
R apply(double value);
|
||||
}
|
||||
|
@ -40,11 +40,11 @@ public interface DoublePredicate {
|
||||
/**
|
||||
* Returns {@code true} if the input value matches some criteria.
|
||||
*
|
||||
* @param value the value to be tested.
|
||||
* @param value the value to be tested
|
||||
* @return {@code true} if the input value matches some criteria, otherwise
|
||||
* {@code false}.
|
||||
* {@code false}
|
||||
*/
|
||||
public boolean test(double value);
|
||||
boolean test(double value);
|
||||
|
||||
/**
|
||||
* Returns a predicate which evaluates to {@code true} only if this
|
||||
@ -52,11 +52,16 @@ public interface DoublePredicate {
|
||||
* this predicate returns {@code false} then the remaining predicate is not
|
||||
* evaluated.
|
||||
*
|
||||
* @param p a predicate which will be logically-ANDed with this predicate.
|
||||
* <p>Any exceptions thrown by either {@code test} method are relayed
|
||||
* to the caller; if performing first operation throws an exception, the
|
||||
* second operation will not be performed.
|
||||
*
|
||||
* @param p a predicate which will be logically-ANDed with this predicate
|
||||
* @return a new predicate which returns {@code true} only if both
|
||||
* predicates return {@code true}.
|
||||
* predicates return {@code true}
|
||||
* @throws NullPointerException if p is null
|
||||
*/
|
||||
public default DoublePredicate and(DoublePredicate p) {
|
||||
default DoublePredicate and(DoublePredicate p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (value) -> test(value) && p.test(value);
|
||||
}
|
||||
@ -65,9 +70,9 @@ public interface DoublePredicate {
|
||||
* Returns a predicate which negates the result of this predicate.
|
||||
*
|
||||
* @return a new predicate who's result is always the opposite of this
|
||||
* predicate.
|
||||
* predicate
|
||||
*/
|
||||
public default DoublePredicate negate() {
|
||||
default DoublePredicate negate() {
|
||||
return (value) -> !test(value);
|
||||
}
|
||||
|
||||
@ -77,25 +82,17 @@ public interface DoublePredicate {
|
||||
* predicate returns {@code true} then the remaining predicate is not
|
||||
* evaluated.
|
||||
*
|
||||
* @param p a predicate which will be logically-ANDed with this predicate.
|
||||
* <p>Any exceptions thrown by either {@code test} method are relayed
|
||||
* to the caller; if performing first operation throws an exception, the
|
||||
* second operation will not be performed.
|
||||
*
|
||||
* @param p a predicate which will be logically-ANDed with this predicate
|
||||
* @return a new predicate which returns {@code true} if either predicate
|
||||
* returns {@code true}.
|
||||
* returns {@code true}
|
||||
* @throws NullPointerException if p is null
|
||||
*/
|
||||
public default DoublePredicate or(DoublePredicate p) {
|
||||
default DoublePredicate or(DoublePredicate p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (value) -> test(value) || p.test(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a predicate that evaluates to {@code true} if both or neither of
|
||||
* the component predicates evaluate to {@code true}.
|
||||
*
|
||||
* @param p a predicate which will be logically-XORed with this predicate.
|
||||
* @return a predicate that evaluates to {@code true} if all or none of the
|
||||
* component predicates evaluate to {@code true}.
|
||||
*/
|
||||
public default DoublePredicate xor(DoublePredicate p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (value) -> test(value) ^ p.test(value);
|
||||
}
|
||||
}
|
||||
|
@ -39,5 +39,5 @@ public interface DoubleSupplier {
|
||||
*
|
||||
* @return a {@code double} value
|
||||
*/
|
||||
public double getAsDouble();
|
||||
double getAsDouble();
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
*/
|
||||
package java.util.function;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* An operation on a {@code double} operand yielding a {@code double}
|
||||
* result. This is the primitive type specialization of {@link UnaryOperator}
|
||||
@ -42,5 +44,46 @@ public interface DoubleUnaryOperator {
|
||||
* @param operand the operand value
|
||||
* @return the operation result value
|
||||
*/
|
||||
public double applyAsDouble(double operand);
|
||||
double applyAsDouble(double operand);
|
||||
|
||||
/**
|
||||
* Compose a new function which applies the provided function followed by
|
||||
* this function. If either function throws an exception, it is relayed
|
||||
* to the caller.
|
||||
*
|
||||
* @param before An additional function to be applied before this function
|
||||
* is applied
|
||||
* @return A function which performs the provided function followed by this
|
||||
* function
|
||||
* @throws NullPointerException if before is null
|
||||
*/
|
||||
default DoubleUnaryOperator compose(DoubleUnaryOperator before) {
|
||||
Objects.requireNonNull(before);
|
||||
return (double v) -> applyAsDouble(before.applyAsDouble(v));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose a new function which applies this function followed by the
|
||||
* provided function. If either function throws an exception, it is relayed
|
||||
* to the caller.
|
||||
*
|
||||
* @param after An additional function to be applied after this function is
|
||||
* applied
|
||||
* @return A function which performs this function followed by the provided
|
||||
* function followed
|
||||
* @throws NullPointerException if after is null
|
||||
*/
|
||||
default DoubleUnaryOperator andThen(DoubleUnaryOperator after) {
|
||||
Objects.requireNonNull(after);
|
||||
return (double t) -> after.applyAsDouble(applyAsDouble(t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unary operator that provides its input value as the result.
|
||||
*
|
||||
* @return a unary operator that provides its input value as the result
|
||||
*/
|
||||
static DoubleUnaryOperator identity() {
|
||||
return t -> t;
|
||||
}
|
||||
}
|
||||
|
@ -24,14 +24,15 @@
|
||||
*/
|
||||
package java.util.function;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Apply a function to the input argument, yielding an appropriate result. A
|
||||
* function may variously provide a mapping between types, object instances or
|
||||
* keys and values or any other form of transformation upon the input.
|
||||
*
|
||||
* @param <T> the type of the input to the {@code apply} operation.
|
||||
* @param <R> the type of the result of the {@code apply} operation.
|
||||
* @param <T> the type of the input to the {@code apply} operation
|
||||
* @param <R> the type of the result of the {@code apply} operation
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
@ -44,5 +45,50 @@ public interface Function<T, R> {
|
||||
* @param t the input object
|
||||
* @return the function result
|
||||
*/
|
||||
public R apply(T t);
|
||||
R apply(T t);
|
||||
|
||||
/**
|
||||
* Returns a new function which applies the provided function followed by
|
||||
* this function. If either function throws an exception, it is relayed
|
||||
* to the caller.
|
||||
*
|
||||
* @param <V> type of input objects to the combined function. May be the
|
||||
* same type as {@code <T>} or {@code <R>}
|
||||
* @param before an additional function to be applied before this function
|
||||
* is applied
|
||||
* @return a function which performs the provided function followed by this
|
||||
* function
|
||||
* @throws NullPointerException if before is null
|
||||
*/
|
||||
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
|
||||
Objects.requireNonNull(before);
|
||||
return (V v) -> apply(before.apply(v));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new function which applies this function followed by the
|
||||
* provided function. If either function throws an exception, it is relayed
|
||||
* to the caller.
|
||||
*
|
||||
* @param <V> type of output objects to the combined function. May be the
|
||||
* same type as {@code <T>} or {@code <R>}
|
||||
* @param after an additional function to be applied after this function is
|
||||
* applied
|
||||
* @return a function which performs this function followed by the provided
|
||||
* function
|
||||
* @throws NullPointerException if after is null
|
||||
*/
|
||||
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
|
||||
Objects.requireNonNull(after);
|
||||
return (T t) -> after.apply(apply(t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Function} whose {@code apply} method returns its input.
|
||||
*
|
||||
* @param <T> the type of the input and output objects to the function
|
||||
*/
|
||||
static <T> Function<T, T> identity() {
|
||||
return t -> t;
|
||||
}
|
||||
}
|
||||
|
@ -44,5 +44,5 @@ public interface IntBinaryOperator {
|
||||
* @param right the right operand value
|
||||
* @return the result of the operation
|
||||
*/
|
||||
public int applyAsInt(int left, int right);
|
||||
int applyAsInt(int left, int right);
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
*/
|
||||
package java.util.function;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* An operation which accepts a single integer argument and returns no result.
|
||||
* This is the primitive type specialization of {@link Consumer} for {@code int}.
|
||||
@ -41,5 +43,26 @@ public interface IntConsumer {
|
||||
*
|
||||
* @param value the input value
|
||||
*/
|
||||
public void accept(int value);
|
||||
void accept(int value);
|
||||
|
||||
/**
|
||||
* Returns an {@code IntConsumer} which performs, in sequence, the operation
|
||||
* represented by this object followed by the operation represented by
|
||||
* another {@code IntConsumer}.
|
||||
*
|
||||
* <p>Any exceptions thrown by either {@code accept} method are relayed
|
||||
* to the caller; if performing this operation throws an exception, the
|
||||
* other operation will not be performed.
|
||||
*
|
||||
* @param other an IntConsumer which will be chained after this
|
||||
* IntConsumer
|
||||
* @return an IntConsumer which performs in sequence the {@code accept} method
|
||||
* of this IntConsumer and the {@code accept} method of the specified IntConsumer
|
||||
* operation
|
||||
* @throws NullPointerException if other is null
|
||||
*/
|
||||
default IntConsumer chain(IntConsumer other) {
|
||||
Objects.requireNonNull(other);
|
||||
return (int t) -> { accept(t); other.accept(t); };
|
||||
}
|
||||
}
|
||||
|
@ -43,5 +43,5 @@ public interface IntFunction<R> {
|
||||
* @param value the input value
|
||||
* @return the function result
|
||||
*/
|
||||
public R apply(int value);
|
||||
R apply(int value);
|
||||
}
|
||||
|
@ -39,11 +39,11 @@ public interface IntPredicate {
|
||||
/**
|
||||
* Returns {@code true} if the input value matches some criteria.
|
||||
*
|
||||
* @param value the value to be tested.
|
||||
* @param value the value to be tested
|
||||
* @return {@code true} if the input value matches some criteria, otherwise
|
||||
* {@code false}
|
||||
*/
|
||||
public boolean test(int value);
|
||||
boolean test(int value);
|
||||
|
||||
/**
|
||||
* Returns a predicate which evaluates to {@code true} only if this
|
||||
@ -51,11 +51,16 @@ public interface IntPredicate {
|
||||
* this predicate returns {@code false} then the remaining predicate is not
|
||||
* evaluated.
|
||||
*
|
||||
* @param p a predicate which will be logically-ANDed with this predicate.
|
||||
* <p>Any exceptions thrown by either {@code test} method are relayed
|
||||
* to the caller; if performing first operation throws an exception, the
|
||||
* second operation will not be performed.
|
||||
*
|
||||
* @param p a predicate which will be logically-ANDed with this predicate
|
||||
* @return a new predicate which returns {@code true} only if both
|
||||
* predicates return {@code true}.
|
||||
* predicates return {@code true}
|
||||
* @throws NullPointerException if p is null
|
||||
*/
|
||||
public default IntPredicate and(IntPredicate p) {
|
||||
default IntPredicate and(IntPredicate p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (value) -> test(value) && p.test(value);
|
||||
}
|
||||
@ -64,9 +69,9 @@ public interface IntPredicate {
|
||||
* Returns a predicate which negates the result of this predicate.
|
||||
*
|
||||
* @return a new predicate who's result is always the opposite of this
|
||||
* predicate.
|
||||
* predicate
|
||||
*/
|
||||
public default IntPredicate negate() {
|
||||
default IntPredicate negate() {
|
||||
return (value) -> !test(value);
|
||||
}
|
||||
|
||||
@ -76,25 +81,17 @@ public interface IntPredicate {
|
||||
* predicate returns {@code true} then the remaining predicate is not
|
||||
* evaluated.
|
||||
*
|
||||
* @param p a predicate which will be logically-ORed with this predicate.
|
||||
* <p>Any exceptions thrown by either {@code test} method are relayed
|
||||
* to the caller; if performing first operation throws an exception, the
|
||||
* second operation will not be performed.
|
||||
*
|
||||
* @param p a predicate which will be logically-ORed with this predicate
|
||||
* @return a new predicate which returns {@code true} if either predicate
|
||||
* returns {@code true}.
|
||||
* returns {@code true}
|
||||
* @throws NullPointerException if p is null
|
||||
*/
|
||||
public default IntPredicate or(IntPredicate p) {
|
||||
default IntPredicate or(IntPredicate p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (value) -> test(value) || p.test(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a predicate that evaluates to {@code true} if both or neither of
|
||||
* the component predicates evaluate to {@code true}.
|
||||
*
|
||||
* @param p a predicate which will be logically-XORed with this predicate.
|
||||
* @return a predicate that evaluates to {@code true} if both or neither of
|
||||
* the component predicates evaluate to {@code true}
|
||||
*/
|
||||
public default IntPredicate xor(IntPredicate p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (value) -> test(value) ^ p.test(value);
|
||||
}
|
||||
}
|
||||
|
@ -39,5 +39,5 @@ public interface IntSupplier {
|
||||
*
|
||||
* @return an {@code int} value
|
||||
*/
|
||||
public int getAsInt();
|
||||
int getAsInt();
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
*/
|
||||
package java.util.function;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* An operation on a single {@code int} operand yielding an {@code int} result.
|
||||
* This is the primitive type specialization of {@link UnaryOperator} for
|
||||
@ -37,10 +39,51 @@ public interface IntUnaryOperator {
|
||||
|
||||
/**
|
||||
* Returns the {@code int} value result of the operation upon the
|
||||
* {@code int} operand.
|
||||
* {@code int} operand.
|
||||
*
|
||||
* @param operand the operand value
|
||||
* @return the operation result value
|
||||
*/
|
||||
public int applyAsInt(int operand);
|
||||
int applyAsInt(int operand);
|
||||
|
||||
/**
|
||||
* Compose a new function which applies the provided function followed by
|
||||
* this function. If either function throws an exception, it is relayed
|
||||
* to the caller.
|
||||
*
|
||||
* @param before an additional function to be applied before this function
|
||||
* is applied
|
||||
* @return a function which performs the provided function followed by this
|
||||
* function
|
||||
* @throws NullPointerException if before is null
|
||||
*/
|
||||
default IntUnaryOperator compose(IntUnaryOperator before) {
|
||||
Objects.requireNonNull(before);
|
||||
return (int v) -> applyAsInt(before.applyAsInt(v));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose a new function which applies this function followed by the
|
||||
* provided function. If either function throws an exception, it is relayed
|
||||
* to the caller.
|
||||
*
|
||||
* @param after an additional function to be applied after this function is
|
||||
* applied
|
||||
* @return a function which performs this function followed by the provided
|
||||
* function followed
|
||||
* @throws NullPointerException if after is null
|
||||
*/
|
||||
default IntUnaryOperator andThen(IntUnaryOperator after) {
|
||||
Objects.requireNonNull(after);
|
||||
return (int t) -> after.applyAsInt(applyAsInt(t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unary operator that provides its input value as the result.
|
||||
*
|
||||
* @return a unary operator that provides its input value as the result
|
||||
*/
|
||||
static IntUnaryOperator identity() {
|
||||
return t -> t;
|
||||
}
|
||||
}
|
||||
|
@ -44,5 +44,5 @@ public interface LongBinaryOperator {
|
||||
* @param right the right operand value
|
||||
* @return the result of the operation
|
||||
*/
|
||||
public long applyAsLong(long left, long right);
|
||||
long applyAsLong(long left, long right);
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
*/
|
||||
package java.util.function;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* An operation which accepts a single long argument and returns no result.
|
||||
* This is the {@code long}-consuming primitive type specialization of
|
||||
@ -41,5 +43,26 @@ public interface LongConsumer {
|
||||
*
|
||||
* @param value the input value
|
||||
*/
|
||||
public void accept(long value);
|
||||
void accept(long value);
|
||||
|
||||
/**
|
||||
* Returns a {@code LongConsumer} which performs, in sequence, the operation
|
||||
* represented by this object followed by the operation represented by
|
||||
* another {@code LongConsumer}.
|
||||
*
|
||||
* <p>Any exceptions thrown by either {@code accept} method are relayed
|
||||
* to the caller; if performing this operation throws an exception, the
|
||||
* other operation will not be performed.
|
||||
*
|
||||
* @param other a LongConsumer which will be chained after this
|
||||
* LongConsumer
|
||||
* @return a LongConsumer which performs in sequence the {@code accept} method
|
||||
* of this LongConsumer and the {@code accept} method of the specified LongConsumer
|
||||
* operation
|
||||
* @throws NullPointerException if other is null
|
||||
*/
|
||||
default LongConsumer chain(LongConsumer other) {
|
||||
Objects.requireNonNull(other);
|
||||
return (long t) -> { accept(t); other.accept(t); };
|
||||
}
|
||||
}
|
||||
|
@ -43,5 +43,5 @@ public interface LongFunction<R> {
|
||||
* @param value the input value
|
||||
* @return the function result
|
||||
*/
|
||||
public R apply(long value);
|
||||
R apply(long value);
|
||||
}
|
||||
|
@ -39,11 +39,11 @@ public interface LongPredicate {
|
||||
/**
|
||||
* Returns {@code true} if the input value matches some criteria.
|
||||
*
|
||||
* @param value the value to be tested.
|
||||
* @param value the value to be tested
|
||||
* @return {@code true} if the input value matches some criteria, otherwise
|
||||
* {@code false}.
|
||||
* {@code false}
|
||||
*/
|
||||
public boolean test(long value);
|
||||
boolean test(long value);
|
||||
|
||||
/**
|
||||
* Returns a predicate which evaluates to {@code true} only if this
|
||||
@ -51,11 +51,15 @@ public interface LongPredicate {
|
||||
* this predicate returns {@code false} then the remaining predicate is not
|
||||
* evaluated.
|
||||
*
|
||||
* @param p a predicate which will be logically-ANDed with this predicate.
|
||||
* <p>Any exceptions thrown by either {@code test} method are relayed
|
||||
* to the caller; if performing first operation throws an exception, the
|
||||
* second operation will not be performed.
|
||||
*
|
||||
* @param p a predicate which will be logically-ANDed with this predicate
|
||||
* @return a new predicate which returns {@code true} only if both
|
||||
* predicates return {@code true}.
|
||||
* predicates return {@code true}
|
||||
*/
|
||||
public default LongPredicate and(LongPredicate p) {
|
||||
default LongPredicate and(LongPredicate p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (value) -> test(value) && p.test(value);
|
||||
}
|
||||
@ -64,9 +68,9 @@ public interface LongPredicate {
|
||||
* Returns a predicate which negates the result of this predicate.
|
||||
*
|
||||
* @return a new predicate who's result is always the opposite of this
|
||||
* predicate.
|
||||
* predicate
|
||||
*/
|
||||
public default LongPredicate negate() {
|
||||
default LongPredicate negate() {
|
||||
return (value) -> !test(value);
|
||||
}
|
||||
|
||||
@ -76,25 +80,17 @@ public interface LongPredicate {
|
||||
* predicate returns {@code true} then the remaining predicate is not
|
||||
* evaluated.
|
||||
*
|
||||
* @param p a predicate which will be logically-ORed with this predicate.
|
||||
* <p>Any exceptions thrown by either {@code test} method are relayed
|
||||
* to the caller; if performing first operation throws an exception, the
|
||||
* second operation will not be performed.
|
||||
*
|
||||
* @param p a predicate which will be logically-ORed with this predicate
|
||||
* @return a new predicate which returns {@code true} if either predicate
|
||||
* returns {@code true}.
|
||||
* returns {@code true}
|
||||
* @throws NullPointerException if p is null
|
||||
*/
|
||||
public default LongPredicate or(LongPredicate p) {
|
||||
default LongPredicate or(LongPredicate p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (value) -> test(value) || p.test(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a predicate that evaluates to {@code true} if both or neither of
|
||||
* the component predicates evaluate to {@code true}.
|
||||
*
|
||||
* @param p a predicate which will be logically-XORed with this predicate.
|
||||
* @return a predicate that evaluates to {@code true} if both or neither of
|
||||
* the component predicates evaluate to {@code true}.
|
||||
*/
|
||||
public default LongPredicate xor(LongPredicate p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (value) -> test(value) ^ p.test(value);
|
||||
}
|
||||
}
|
||||
|
@ -39,5 +39,5 @@ public interface LongSupplier {
|
||||
*
|
||||
* @return a {@code long} value
|
||||
*/
|
||||
public long getAsLong();
|
||||
long getAsLong();
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
*/
|
||||
package java.util.function;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* An operation on a single {@code long} operand yielding a {@code long} result.
|
||||
* This is the primitive type specialization of {@link UnaryOperator} for
|
||||
@ -42,5 +44,46 @@ public interface LongUnaryOperator {
|
||||
* @param operand the operand value
|
||||
* @return the operation result value
|
||||
*/
|
||||
public long applyAsLong(long operand);
|
||||
long applyAsLong(long operand);
|
||||
|
||||
/**
|
||||
* Compose a new function which applies the provided function followed by
|
||||
* this function. If either function throws an exception, it is relayed
|
||||
* to the caller.
|
||||
*
|
||||
* @param before An additional function to be applied before this function
|
||||
* is applied
|
||||
* @return A function which performs the provided function followed by this
|
||||
* function
|
||||
* @throws NullPointerException if before is null
|
||||
*/
|
||||
default LongUnaryOperator compose(LongUnaryOperator before) {
|
||||
Objects.requireNonNull(before);
|
||||
return (long v) -> applyAsLong(before.applyAsLong(v));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose a new function which applies this function followed by the
|
||||
* provided function. If either function throws an exception, it is relayed
|
||||
* to the caller.
|
||||
*
|
||||
* @param after An additional function to be applied after this function is
|
||||
* applied
|
||||
* @return A function which performs this function followed by the provided
|
||||
* function followed
|
||||
* @throws NullPointerException if after is null
|
||||
*/
|
||||
default LongUnaryOperator andThen(LongUnaryOperator after) {
|
||||
Objects.requireNonNull(after);
|
||||
return (long t) -> after.applyAsLong(applyAsLong(t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unary operator that provides its input value as the result.
|
||||
*
|
||||
* @return a unary operator that provides its input value as the result
|
||||
*/
|
||||
static LongUnaryOperator identity() {
|
||||
return t -> t;
|
||||
}
|
||||
}
|
||||
|
@ -44,5 +44,5 @@ public interface ObjDoubleConsumer<T> {
|
||||
* @param t an input object
|
||||
* @param value an input value
|
||||
*/
|
||||
public void accept(T t, double value);
|
||||
void accept(T t, double value);
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ package java.util.function;
|
||||
* {@link BiConsumer}. Unlike most other functional interfaces,
|
||||
* {@code ObjIntConsumer} is expected to operate via side-effects.
|
||||
*
|
||||
* @param <T> Type of reference argument to {@code accept()}.
|
||||
* @param <T> Type of reference argument to {@code accept()}
|
||||
*
|
||||
* @see BiConsumer
|
||||
* @since 1.8
|
||||
@ -44,5 +44,5 @@ public interface ObjIntConsumer<T> {
|
||||
* @param t an input object
|
||||
* @param value an input value
|
||||
*/
|
||||
public void accept(T t, int value);
|
||||
void accept(T t, int value);
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ package java.util.function;
|
||||
* {@link BiConsumer}. Unlike most other functional interfaces,
|
||||
* {@code ObjLongConsumer} is expected to operate via side-effects.
|
||||
*
|
||||
* @param <T> Type of reference argument to {@code accept()}.
|
||||
* @param <T> Type of reference argument to {@code accept()}
|
||||
*
|
||||
* @see BiConsumer
|
||||
* @since 1.8
|
||||
@ -44,5 +44,5 @@ public interface ObjLongConsumer<T> {
|
||||
* @param t an input object
|
||||
* @param value an input value
|
||||
*/
|
||||
public void accept(T t, long value);
|
||||
void accept(T t, long value);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ public interface Predicate<T> {
|
||||
* @return {@code true} if the input object matches some criteria, otherwise
|
||||
* {@code false}
|
||||
*/
|
||||
public boolean test(T t);
|
||||
boolean test(T t);
|
||||
|
||||
/**
|
||||
* Returns a predicate which evaluates to {@code true} only if this
|
||||
@ -51,11 +51,16 @@ public interface Predicate<T> {
|
||||
* this predicate returns {@code false} then the remaining predicate is not
|
||||
* evaluated.
|
||||
*
|
||||
* @param p a predicate which will be logically-ANDed with this predicate.
|
||||
* <p>Any exceptions thrown by either {@code test} method are relayed
|
||||
* to the caller; if performing first operation throws an exception, the
|
||||
* second operation will not be performed.
|
||||
*
|
||||
* @param p a predicate which will be logically-ANDed with this predicate
|
||||
* @return a new predicate which returns {@code true} only if both
|
||||
* predicates return {@code true}.
|
||||
* predicates return {@code true}
|
||||
* @throws NullPointerException if p is null
|
||||
*/
|
||||
public default Predicate<T> and(Predicate<? super T> p) {
|
||||
default Predicate<T> and(Predicate<? super T> p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (t) -> test(t) && p.test(t);
|
||||
}
|
||||
@ -66,7 +71,7 @@ public interface Predicate<T> {
|
||||
* @return a new predicate who's result is always the opposite of this
|
||||
* predicate.
|
||||
*/
|
||||
public default Predicate<T> negate() {
|
||||
default Predicate<T> negate() {
|
||||
return (t) -> !test(t);
|
||||
}
|
||||
|
||||
@ -76,25 +81,32 @@ public interface Predicate<T> {
|
||||
* predicate returns {@code true} then the remaining predicate is not
|
||||
* evaluated.
|
||||
*
|
||||
* @param p a predicate which will be logically-ORed with this predicate.
|
||||
* <p>Any exceptions thrown by either {@code test} method are relayed
|
||||
* to the caller; if performing first operation throws an exception, the
|
||||
* second operation will not be performed.
|
||||
*
|
||||
* @param p a predicate which will be logically-ORed with this predicate
|
||||
* @return a new predicate which returns {@code true} if either predicate
|
||||
* returns {@code true}.
|
||||
* returns {@code true}
|
||||
* @throws NullPointerException if p is null
|
||||
*/
|
||||
public default Predicate<T> or(Predicate<? super T> p) {
|
||||
default Predicate<T> or(Predicate<? super T> p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (t) -> test(t) || p.test(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a predicate that evaluates to {@code true} if both or neither of
|
||||
* the component predicates evaluate to {@code true}.
|
||||
* Returns a predicate who's result matches
|
||||
* {@code Objects.equals(target, t)}.
|
||||
*
|
||||
* @param p a predicate which will be logically-XORed with this predicte.
|
||||
* @return a predicate that evaluates to {@code true} if both or neither of
|
||||
* the component predicates evaluate to {@code true}.
|
||||
* @param <T> the type of values evaluated by the predicate
|
||||
* @param target the target value to be compared for equality
|
||||
* @return a predicate who's result matches
|
||||
* {@code Objects.equals(target, t)}
|
||||
*/
|
||||
public default Predicate<T> xor(Predicate<? super T> p) {
|
||||
Objects.requireNonNull(p);
|
||||
return (t) -> test(t) ^ p.test(t);
|
||||
static <T> Predicate<T> isEqual(Object target) {
|
||||
return (null == target)
|
||||
? Objects::isNull
|
||||
: object -> target.equals(object);
|
||||
}
|
||||
}
|
||||
|
@ -40,5 +40,5 @@ public interface Supplier<T> {
|
||||
*
|
||||
* @return an object
|
||||
*/
|
||||
public T get();
|
||||
T get();
|
||||
}
|
||||
|
@ -46,5 +46,5 @@ public interface ToDoubleBiFunction<T, U> {
|
||||
* @param u an input object
|
||||
* @return the function result value
|
||||
*/
|
||||
public double applyAsDouble(T t, U u);
|
||||
double applyAsDouble(T t, U u);
|
||||
}
|
||||
|
@ -42,5 +42,5 @@ public interface ToDoubleFunction<T> {
|
||||
* @param t the input object
|
||||
* @return the function result value
|
||||
*/
|
||||
public double applyAsDouble(T t);
|
||||
double applyAsDouble(T t);
|
||||
}
|
||||
|
@ -28,10 +28,10 @@ package java.util.function;
|
||||
* Apply a function to the input arguments, yielding an appropriate result.
|
||||
* This is the {@code int}-bearing specialization for {@link BiFunction}.
|
||||
*
|
||||
* @param <T> the type of the first argument to the {@code applyAsLong}
|
||||
* operation.
|
||||
* @param <U> the type of the second argument to the {@code applyAsLong}
|
||||
* operation.
|
||||
* @param <T> the type of the first argument to the {@code applyAsInt}
|
||||
* operation
|
||||
* @param <U> the type of the second argument to the {@code applyAsInt}
|
||||
* operation
|
||||
*
|
||||
* @see BiFunction
|
||||
* @since 1.8
|
||||
@ -46,5 +46,5 @@ public interface ToIntBiFunction<T, U> {
|
||||
* @param u an input object
|
||||
* @return the function result value
|
||||
*/
|
||||
public int applyAsInt(T t, U u);
|
||||
int applyAsInt(T t, U u);
|
||||
}
|
||||
|
@ -42,5 +42,5 @@ public interface ToIntFunction<T> {
|
||||
* @param t the input object
|
||||
* @return the function result value
|
||||
*/
|
||||
public int applyAsInt(T t);
|
||||
int applyAsInt(T t);
|
||||
}
|
||||
|
@ -46,5 +46,5 @@ public interface ToLongBiFunction<T, U> {
|
||||
* @param u an input object
|
||||
* @return the function result value
|
||||
*/
|
||||
public long applyAsLong(T t, U u);
|
||||
long applyAsLong(T t, U u);
|
||||
}
|
||||
|
@ -42,5 +42,5 @@ public interface ToLongFunction<T> {
|
||||
* @param t the input object
|
||||
* @return the function result value
|
||||
*/
|
||||
public long applyAsLong(T t);
|
||||
long applyAsLong(T t);
|
||||
}
|
||||
|
@ -36,4 +36,13 @@ package java.util.function;
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface UnaryOperator<T> extends Function<T, T> {
|
||||
|
||||
/**
|
||||
* Returns a unary operator that provides its input value as the result.
|
||||
*
|
||||
* @return a unary operator that provides its input value as the result
|
||||
*/
|
||||
static <T> UnaryOperator<T> identity() {
|
||||
return t -> t;
|
||||
}
|
||||
}
|
||||
|
499
jdk/test/java/nio/file/Files/FaultyFileSystem.java
Normal file
499
jdk/test/java/nio/file/Files/FaultyFileSystem.java
Normal file
@ -0,0 +1,499 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.nio.file.AccessMode;
|
||||
import java.nio.file.CopyOption;
|
||||
import java.nio.file.DirectoryIteratorException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.FileStore;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystemAlreadyExistsException;
|
||||
import java.nio.file.FileSystemNotFoundException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.nio.file.WatchService;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import java.nio.file.attribute.FileAttributeView;
|
||||
import java.nio.file.attribute.UserPrincipalLookupService;
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A {@code FileSystem} that helps testing by trigger exception throwing based on filenames.
|
||||
*/
|
||||
class FaultyFileSystem extends FileSystem {
|
||||
final Path root;
|
||||
final boolean removeRootAfterClose;
|
||||
final FileSystem delegate;
|
||||
boolean isOpen;
|
||||
|
||||
FaultyFileSystem(Path root) throws IOException {
|
||||
if (root == null) {
|
||||
root = Files.createTempDirectory("faultyFS");
|
||||
removeRootAfterClose = true;
|
||||
} else {
|
||||
if (! Files.isDirectory(root)) {
|
||||
throw new IllegalArgumentException("must be a directory.");
|
||||
}
|
||||
removeRootAfterClose = false;
|
||||
}
|
||||
this.root = root;
|
||||
delegate = root.getFileSystem();
|
||||
isOpen = true;
|
||||
}
|
||||
|
||||
private static Path unwrap(Path p) {
|
||||
return PassThroughFileSystem.unwrap(p);
|
||||
}
|
||||
|
||||
Path getRoot() {
|
||||
return new PassThroughFileSystem.PassThroughPath(this, root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (isOpen) {
|
||||
if (removeRootAfterClose) {
|
||||
TestUtil.removeAll(root);
|
||||
}
|
||||
isOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystemProvider provider() {
|
||||
return FaultyFSProvider.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return isOpen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return delegate.isReadOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSeparator() {
|
||||
return delegate.getSeparator();
|
||||
}
|
||||
|
||||
private <T> Iterable<T> SoleIterable(final T element) {
|
||||
return new Iterable<T>() {
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new Iterator<T>() {
|
||||
private T soleElement = element;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return soleElement != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
try {
|
||||
return soleElement;
|
||||
} finally {
|
||||
soleElement = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Path> getRootDirectories() {
|
||||
return SoleIterable(getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<FileStore> getFileStores() {
|
||||
FileStore store;
|
||||
try {
|
||||
store = Files.getFileStore(root);
|
||||
} catch (IOException ioe) {
|
||||
store = null;
|
||||
}
|
||||
return SoleIterable(store);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> supportedFileAttributeViews() {
|
||||
// assume that unwrapped objects aren't exposed
|
||||
return delegate.supportedFileAttributeViews();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath(String first, String... more) {
|
||||
return new PassThroughFileSystem.PassThroughPath(this, delegate.getPath(first, more));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathMatcher getPathMatcher(String syntaxAndPattern) {
|
||||
final PathMatcher matcher = delegate.getPathMatcher(syntaxAndPattern);
|
||||
return new PathMatcher() {
|
||||
@Override
|
||||
public boolean matches(Path path) {
|
||||
return matcher.matches(unwrap(path));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserPrincipalLookupService getUserPrincipalLookupService() {
|
||||
// assume that unwrapped objects aren't exposed
|
||||
return delegate.getUserPrincipalLookupService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WatchService newWatchService() throws IOException {
|
||||
// to keep it simple
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
static class FaultyException extends IOException {
|
||||
FaultyException() {
|
||||
super("fault triggered.");
|
||||
}
|
||||
}
|
||||
|
||||
static class FaultyFSProvider extends FileSystemProvider {
|
||||
private static final String SCHEME = "faulty";
|
||||
private static volatile FaultyFileSystem delegate;
|
||||
private static FaultyFSProvider INSTANCE = new FaultyFSProvider();
|
||||
private boolean enabled;
|
||||
|
||||
private FaultyFSProvider() {}
|
||||
|
||||
public static FaultyFSProvider getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public void setFaultyMode(boolean enable) {
|
||||
enabled = enable;
|
||||
}
|
||||
|
||||
private void triggerEx(String filename, String... names) throws IOException {
|
||||
if (! enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (filename.equals("SecurityException")) {
|
||||
throw new SecurityException("FaultyFS", new FaultyException());
|
||||
}
|
||||
|
||||
if (filename.equals("IOException")) {
|
||||
throw new FaultyException();
|
||||
}
|
||||
|
||||
for (String name: names) {
|
||||
if (name.equals(filename)) {
|
||||
throw new FaultyException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void triggerEx(Path path, String... names) throws IOException {
|
||||
triggerEx(path.getFileName().toString(), names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScheme() {
|
||||
return SCHEME;
|
||||
}
|
||||
|
||||
private void checkScheme(URI uri) {
|
||||
if (!uri.getScheme().equalsIgnoreCase(SCHEME))
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
private void checkUri(URI uri) {
|
||||
checkScheme(uri);
|
||||
if (!uri.getSchemeSpecificPart().equals("///"))
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystem newFileSystem(Path fakeRoot, Map<String,?> env)
|
||||
throws IOException
|
||||
{
|
||||
if (env != null && env.keySet().contains("IOException")) {
|
||||
triggerEx("IOException");
|
||||
}
|
||||
|
||||
synchronized (FaultyFSProvider.class) {
|
||||
if (delegate != null && delegate.isOpen())
|
||||
throw new FileSystemAlreadyExistsException();
|
||||
FaultyFileSystem result = new FaultyFileSystem(fakeRoot);
|
||||
delegate = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystem newFileSystem(URI uri, Map<String,?> env)
|
||||
throws IOException
|
||||
{
|
||||
if (env != null && env.keySet().contains("IOException")) {
|
||||
triggerEx("IOException");
|
||||
}
|
||||
|
||||
checkUri(uri);
|
||||
synchronized (FaultyFSProvider.class) {
|
||||
if (delegate != null && delegate.isOpen())
|
||||
throw new FileSystemAlreadyExistsException();
|
||||
FaultyFileSystem result = new FaultyFileSystem(null);
|
||||
delegate = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystem getFileSystem(URI uri) {
|
||||
checkUri(uri);
|
||||
FileSystem result = delegate;
|
||||
if (result == null)
|
||||
throw new FileSystemNotFoundException();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath(URI uri) {
|
||||
checkScheme(uri);
|
||||
if (delegate == null)
|
||||
throw new FileSystemNotFoundException();
|
||||
|
||||
// only allow absolute path
|
||||
String path = uri.getSchemeSpecificPart();
|
||||
if (! path.startsWith("///")) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return new PassThroughFileSystem.PassThroughPath(delegate, delegate.root.resolve(path.substring(3)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(Path file, String attribute, Object value, LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
triggerEx(file, "setAttribute");
|
||||
Files.setAttribute(unwrap(file), attribute, value, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,Object> readAttributes(Path file, String attributes, LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
triggerEx(file, "readAttributes");
|
||||
return Files.readAttributes(unwrap(file), attributes, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V extends FileAttributeView> V getFileAttributeView(Path file,
|
||||
Class<V> type,
|
||||
LinkOption... options)
|
||||
{
|
||||
return Files.getFileAttributeView(unwrap(file), type, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends BasicFileAttributes> A readAttributes(Path file,
|
||||
Class<A> type,
|
||||
LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
triggerEx(file, "readAttributes");
|
||||
return Files.readAttributes(unwrap(file), type, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Path file) throws IOException {
|
||||
triggerEx(file, "delete");
|
||||
Files.delete(unwrap(file));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
triggerEx(target, "createSymbolicLink");
|
||||
Files.createSymbolicLink(unwrap(link), unwrap(target), attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createLink(Path link, Path existing) throws IOException {
|
||||
triggerEx(existing, "createLink");
|
||||
Files.createLink(unwrap(link), unwrap(existing));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path readSymbolicLink(Path link) throws IOException {
|
||||
Path target = Files.readSymbolicLink(unwrap(link));
|
||||
triggerEx(target, "readSymbolicLink");
|
||||
return new PassThroughFileSystem.PassThroughPath(delegate, target);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void copy(Path source, Path target, CopyOption... options) throws IOException {
|
||||
triggerEx(source, "copy");
|
||||
Files.copy(unwrap(source), unwrap(target), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(Path source, Path target, CopyOption... options) throws IOException {
|
||||
triggerEx(source, "move");
|
||||
Files.move(unwrap(source), unwrap(target), options);
|
||||
}
|
||||
|
||||
private DirectoryStream<Path> wrap(final DirectoryStream<Path> stream) {
|
||||
return new DirectoryStream<Path>() {
|
||||
@Override
|
||||
public Iterator<Path> iterator() {
|
||||
final Iterator<Path> itr = stream.iterator();
|
||||
return new Iterator<Path>() {
|
||||
private Path next = null;
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (next == null) {
|
||||
if (itr.hasNext()) {
|
||||
next = itr.next();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (next != null) {
|
||||
try {
|
||||
triggerEx(next, "DirectoryIteratorException");
|
||||
} catch (IOException ioe) {
|
||||
throw new DirectoryIteratorException(ioe);
|
||||
} catch (SecurityException se) {
|
||||
// ??? Does DS throw SecurityException during iteration?
|
||||
next = null;
|
||||
return hasNext();
|
||||
}
|
||||
}
|
||||
return (next != null);
|
||||
}
|
||||
@Override
|
||||
public Path next() {
|
||||
try {
|
||||
if (next != null || hasNext()) {
|
||||
return new PassThroughFileSystem.PassThroughPath(delegate, next);
|
||||
} else {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
} finally {
|
||||
next = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
itr.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
stream.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter)
|
||||
throws IOException
|
||||
{
|
||||
triggerEx(dir, "newDirectoryStream");
|
||||
return wrap(Files.newDirectoryStream(unwrap(dir), filter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDirectory(Path dir, FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
triggerEx(dir, "createDirectory");
|
||||
Files.createDirectory(unwrap(dir), attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeekableByteChannel newByteChannel(Path file,
|
||||
Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
triggerEx(file, "newByteChannel");
|
||||
return Files.newByteChannel(unwrap(file), options, attrs);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isHidden(Path file) throws IOException {
|
||||
triggerEx(file, "isHidden");
|
||||
return Files.isHidden(unwrap(file));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileStore getFileStore(Path file) throws IOException {
|
||||
triggerEx(file, "getFileStore");
|
||||
return Files.getFileStore(unwrap(file));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameFile(Path file, Path other) throws IOException {
|
||||
triggerEx(file, "isSameFile");
|
||||
return Files.isSameFile(unwrap(file), unwrap(other));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAccess(Path file, AccessMode... modes)
|
||||
throws IOException
|
||||
{
|
||||
triggerEx(file, "checkAccess");
|
||||
// hack
|
||||
if (modes.length == 0) {
|
||||
if (Files.exists(unwrap(file)))
|
||||
return;
|
||||
else
|
||||
throw new NoSuchFileException(file.toString());
|
||||
}
|
||||
throw new RuntimeException("not implemented yet");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -304,7 +304,7 @@ class PassThroughFileSystem extends FileSystem {
|
||||
public DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter)
|
||||
throws IOException
|
||||
{
|
||||
return wrap(Files.newDirectoryStream(dir, filter));
|
||||
return wrap(Files.newDirectoryStream(unwrap(dir), filter));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
621
jdk/test/java/nio/file/Files/StreamTest.java
Normal file
621
jdk/test/java/nio/file/Files/StreamTest.java
Normal file
@ -0,0 +1,621 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8006884
|
||||
* @summary Unit test for java.nio.file.Files
|
||||
* @library ..
|
||||
* @build PassThroughFileSystem FaultyFileSystem
|
||||
* @run testng StreamTest
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.MalformedInputException;
|
||||
import java.nio.file.DirectoryIteratorException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.FileSystemLoopException;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparators;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.stream.CloseableStream;
|
||||
import java.util.stream.Collectors;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
@Test(groups = "unit")
|
||||
public class StreamTest {
|
||||
/**
|
||||
* Default test folder
|
||||
* testFolder - empty
|
||||
* - file
|
||||
* - dir - d1
|
||||
* - f1
|
||||
* - lnDir2 (../dir2)
|
||||
* - dir2
|
||||
* - linkDir (./dir)
|
||||
* - linkFile(./file)
|
||||
*/
|
||||
static Path testFolder;
|
||||
static boolean supportsLinks;
|
||||
static Path[] level1;
|
||||
static Path[] all;
|
||||
static Path[] all_folowLinks;
|
||||
|
||||
@BeforeClass
|
||||
void setupTestFolder() throws IOException {
|
||||
testFolder = TestUtil.createTemporaryDirectory();
|
||||
supportsLinks = TestUtil.supportsLinks(testFolder);
|
||||
TreeSet<Path> set = new TreeSet<>();
|
||||
|
||||
// Level 1
|
||||
Path empty = testFolder.resolve("empty");
|
||||
Path file = testFolder.resolve("file");
|
||||
Path dir = testFolder.resolve("dir");
|
||||
Path dir2 = testFolder.resolve("dir2");
|
||||
Files.createDirectory(empty);
|
||||
Files.createFile(file);
|
||||
Files.createDirectory(dir);
|
||||
Files.createDirectory(dir2);
|
||||
set.add(empty);
|
||||
set.add(file);
|
||||
set.add(dir);
|
||||
set.add(dir2);
|
||||
if (supportsLinks) {
|
||||
Path tmp = testFolder.resolve("linkDir");
|
||||
Files.createSymbolicLink(tmp, dir);
|
||||
set.add(tmp);
|
||||
tmp = testFolder.resolve("linkFile");
|
||||
Files.createSymbolicLink(tmp, file);
|
||||
set.add(tmp);
|
||||
}
|
||||
level1 = set.toArray(new Path[0]);
|
||||
|
||||
// Level 2
|
||||
Path tmp = dir.resolve("d1");
|
||||
Files.createDirectory(tmp);
|
||||
set.add(tmp);
|
||||
tmp = dir.resolve("f1");
|
||||
Files.createFile(tmp);
|
||||
set.add(tmp);
|
||||
if (supportsLinks) {
|
||||
tmp = dir.resolve("lnDir2");
|
||||
Files.createSymbolicLink(tmp, dir2);
|
||||
set.add(tmp);
|
||||
}
|
||||
// walk include starting folder
|
||||
set.add(testFolder);
|
||||
all = set.toArray(new Path[0]);
|
||||
|
||||
// Follow links
|
||||
if (supportsLinks) {
|
||||
tmp = testFolder.resolve("linkDir");
|
||||
set.add(tmp.resolve("d1"));
|
||||
set.add(tmp.resolve("f1"));
|
||||
tmp = tmp.resolve("lnDir2");
|
||||
set.add(tmp);
|
||||
}
|
||||
all_folowLinks = set.toArray(new Path[0]);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
void cleanupTestFolder() throws IOException {
|
||||
TestUtil.removeAll(testFolder);
|
||||
}
|
||||
|
||||
public void testBasic() {
|
||||
try (CloseableStream<Path> s = Files.list(testFolder)) {
|
||||
Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
|
||||
assertEquals(actual, level1);
|
||||
} catch (IOException ioe) {
|
||||
fail("Unexpected IOException");
|
||||
}
|
||||
|
||||
try (CloseableStream<Path> s = Files.list(testFolder.resolve("empty"))) {
|
||||
int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
|
||||
assertEquals(count, 0, "Expect empty stream.");
|
||||
} catch (IOException ioe) {
|
||||
fail("Unexpected IOException");
|
||||
}
|
||||
}
|
||||
|
||||
public void testWalk() {
|
||||
try (CloseableStream<Path> s = Files.walk(testFolder)) {
|
||||
Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
|
||||
assertEquals(actual, all);
|
||||
} catch (IOException ioe) {
|
||||
fail("Unexpected IOException");
|
||||
}
|
||||
}
|
||||
|
||||
public void testWalkOneLevel() {
|
||||
try (CloseableStream<Path> s = Files.walk(testFolder, 1)) {
|
||||
Object[] actual = s.filter(path -> ! path.equals(testFolder))
|
||||
.sorted(Comparators.naturalOrder())
|
||||
.toArray();
|
||||
assertEquals(actual, level1);
|
||||
} catch (IOException ioe) {
|
||||
fail("Unexpected IOException");
|
||||
}
|
||||
}
|
||||
|
||||
public void testWalkFollowLink() {
|
||||
// If link is not supported, the directory structure won't have link.
|
||||
// We still want to test the behavior with FOLLOW_LINKS option.
|
||||
try (CloseableStream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
|
||||
Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
|
||||
assertEquals(actual, all_folowLinks);
|
||||
} catch (IOException ioe) {
|
||||
fail("Unexpected IOException");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateFileSystemLoopException(Path start, Path... causes) {
|
||||
try (CloseableStream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {
|
||||
try {
|
||||
int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
|
||||
fail("Should got FileSystemLoopException, but got " + count + "elements.");
|
||||
} catch (UncheckedIOException uioe) {
|
||||
IOException ioe = uioe.getCause();
|
||||
if (ioe instanceof FileSystemLoopException) {
|
||||
FileSystemLoopException fsle = (FileSystemLoopException) ioe;
|
||||
boolean match = false;
|
||||
for (Path cause: causes) {
|
||||
if (fsle.getFile().equals(cause.toString())) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue(match);
|
||||
} else {
|
||||
fail("Unexpected UncheckedIOException cause " + ioe.toString());
|
||||
}
|
||||
}
|
||||
} catch(IOException ex) {
|
||||
fail("Unexpected IOException " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void testWalkFollowLinkLoop() {
|
||||
if (!supportsLinks) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Loops.
|
||||
try {
|
||||
Path dir = testFolder.resolve("dir");
|
||||
Path linkdir = testFolder.resolve("linkDir");
|
||||
Path d1 = dir.resolve("d1");
|
||||
Path cause = d1.resolve("lnSelf");
|
||||
Files.createSymbolicLink(cause, d1);
|
||||
|
||||
// loop in descendant.
|
||||
validateFileSystemLoopException(dir, cause);
|
||||
// loop in self
|
||||
validateFileSystemLoopException(d1, cause);
|
||||
// start from other place via link
|
||||
validateFileSystemLoopException(linkdir,
|
||||
linkdir.resolve(Paths.get("d1", "lnSelf")));
|
||||
Files.delete(cause);
|
||||
|
||||
// loop to parent.
|
||||
cause = d1.resolve("lnParent");
|
||||
Files.createSymbolicLink(cause, dir);
|
||||
|
||||
// loop should be detected at test/dir/d1/lnParent/d1
|
||||
validateFileSystemLoopException(d1, cause.resolve("d1"));
|
||||
// loop should be detected at link
|
||||
validateFileSystemLoopException(dir, cause);
|
||||
// loop should be detected at test/linkdir/d1/lnParent
|
||||
// which is test/dir we have visited via test/linkdir
|
||||
validateFileSystemLoopException(linkdir,
|
||||
linkdir.resolve(Paths.get("d1", "lnParent")));
|
||||
Files.delete(cause);
|
||||
|
||||
// cross loop
|
||||
Path dir2 = testFolder.resolve("dir2");
|
||||
cause = dir2.resolve("lnDir");
|
||||
Files.createSymbolicLink(cause, dir);
|
||||
validateFileSystemLoopException(dir,
|
||||
dir.resolve(Paths.get("lnDir2", "lnDir")));
|
||||
validateFileSystemLoopException(dir2,
|
||||
dir2.resolve(Paths.get("lnDir", "lnDir2")));
|
||||
validateFileSystemLoopException(linkdir,
|
||||
linkdir.resolve(Paths.get("lnDir2", "lnDir")));
|
||||
} catch(IOException ioe) {
|
||||
fail("Unexpected IOException " + ioe);
|
||||
}
|
||||
}
|
||||
|
||||
private static class PathBiPredicate implements BiPredicate<Path, BasicFileAttributes> {
|
||||
private final BiPredicate<Path, BasicFileAttributes> pred;
|
||||
private final Set<Path> visited = new TreeSet<Path>();
|
||||
|
||||
PathBiPredicate(BiPredicate<Path, BasicFileAttributes> pred) {
|
||||
this.pred = Objects.requireNonNull(pred);
|
||||
}
|
||||
|
||||
public boolean test(Path path, BasicFileAttributes attrs) {
|
||||
visited.add(path);
|
||||
return pred.test(path, attrs);
|
||||
}
|
||||
|
||||
public Path[] visited() {
|
||||
return visited.toArray(new Path[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public void testFind() throws IOException {
|
||||
PathBiPredicate pred = new PathBiPredicate((path, attrs) -> true);
|
||||
|
||||
try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
|
||||
Set<Path> result = s.collect(Collectors.toCollection(TreeSet::new));
|
||||
assertEquals(pred.visited(), all);
|
||||
assertEquals(result.toArray(new Path[0]), pred.visited());
|
||||
}
|
||||
|
||||
pred = new PathBiPredicate((path, attrs) -> attrs.isSymbolicLink());
|
||||
try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
|
||||
s.forEach(path -> assertTrue(Files.isSymbolicLink(path)));
|
||||
assertEquals(pred.visited(), all);
|
||||
}
|
||||
|
||||
pred = new PathBiPredicate((path, attrs) ->
|
||||
path.getFileName().toString().startsWith("e"));
|
||||
try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
|
||||
s.forEach(path -> assertEquals(path.getFileName().toString(), "empty"));
|
||||
assertEquals(pred.visited(), all);
|
||||
}
|
||||
|
||||
pred = new PathBiPredicate((path, attrs) ->
|
||||
path.getFileName().toString().startsWith("l") && attrs.isRegularFile());
|
||||
try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
|
||||
s.forEach(path -> fail("Expect empty stream"));
|
||||
assertEquals(pred.visited(), all);
|
||||
}
|
||||
}
|
||||
|
||||
// Test borrowed from BytesAndLines
|
||||
public void testLines() throws IOException {
|
||||
final Charset US_ASCII = Charset.forName("US-ASCII");
|
||||
Path tmpfile = Files.createTempFile("blah", "txt");
|
||||
|
||||
try {
|
||||
// zero lines
|
||||
assertTrue(Files.size(tmpfile) == 0, "File should be empty");
|
||||
try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
|
||||
assertEquals(s.mapToInt(l -> 1).reduce(0, Integer::sum), 0, "No line expected");
|
||||
}
|
||||
|
||||
// one line
|
||||
byte[] hi = { (byte)'h', (byte)'i' };
|
||||
Files.write(tmpfile, hi);
|
||||
try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
|
||||
List<String> lines = s.collect(Collectors.toList());
|
||||
assertTrue(lines.size() == 1, "One line expected");
|
||||
assertTrue(lines.get(0).equals("hi"), "'Hi' expected");
|
||||
}
|
||||
|
||||
// two lines using platform's line separator
|
||||
List<String> expected = Arrays.asList("hi", "there");
|
||||
Files.write(tmpfile, expected, US_ASCII);
|
||||
assertTrue(Files.size(tmpfile) > 0, "File is empty");
|
||||
try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
|
||||
List<String> lines = s.collect(Collectors.toList());
|
||||
assertTrue(lines.equals(expected), "Unexpected lines");
|
||||
}
|
||||
|
||||
// MalformedInputException
|
||||
byte[] bad = { (byte)0xff, (byte)0xff };
|
||||
Files.write(tmpfile, bad);
|
||||
try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
|
||||
try {
|
||||
List<String> lines = s.collect(Collectors.toList());
|
||||
throw new RuntimeException("UncheckedIOException expected");
|
||||
} catch (UncheckedIOException ex) {
|
||||
assertTrue(ex.getCause() instanceof MalformedInputException,
|
||||
"MalformedInputException expected");
|
||||
}
|
||||
}
|
||||
|
||||
// NullPointerException
|
||||
try {
|
||||
Files.lines(null, US_ASCII);
|
||||
throw new RuntimeException("NullPointerException expected");
|
||||
} catch (NullPointerException ignore) { }
|
||||
try {
|
||||
Files.lines(tmpfile, null);
|
||||
throw new RuntimeException("NullPointerException expected");
|
||||
} catch (NullPointerException ignore) { }
|
||||
|
||||
} finally {
|
||||
Files.delete(tmpfile);
|
||||
}
|
||||
}
|
||||
|
||||
public void testDirectoryIteratorException() throws IOException {
|
||||
Path dir = testFolder.resolve("dir2");
|
||||
Path trigger = dir.resolve("DirectoryIteratorException");
|
||||
Files.createFile(trigger);
|
||||
FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
|
||||
FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(dir, null);
|
||||
|
||||
try {
|
||||
fsp.setFaultyMode(false);
|
||||
Path fakeRoot = fs.getRoot();
|
||||
try {
|
||||
try (CloseableStream<Path> s = Files.list(fakeRoot)) {
|
||||
s.forEach(path -> assertEquals(path.getFileName().toString(), "DirectoryIteratorException"));
|
||||
}
|
||||
} catch (UncheckedIOException uioe) {
|
||||
fail("Unexpected exception.");
|
||||
}
|
||||
|
||||
fsp.setFaultyMode(true);
|
||||
try {
|
||||
try (DirectoryStream<Path> ds = Files.newDirectoryStream(fakeRoot)) {
|
||||
Iterator<Path> itor = ds.iterator();
|
||||
while (itor.hasNext()) {
|
||||
itor.next();
|
||||
}
|
||||
}
|
||||
fail("Shoule throw DirectoryIteratorException");
|
||||
} catch (DirectoryIteratorException die) {
|
||||
}
|
||||
|
||||
try {
|
||||
try (CloseableStream<Path> s = Files.list(fakeRoot)) {
|
||||
s.forEach(path -> fail("should not get here"));
|
||||
}
|
||||
} catch (UncheckedIOException uioe) {
|
||||
assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
|
||||
} catch (DirectoryIteratorException die) {
|
||||
fail("Should have been converted into UncheckedIOException.");
|
||||
}
|
||||
} finally {
|
||||
// Cleanup
|
||||
if (fs != null) {
|
||||
fs.close();
|
||||
}
|
||||
Files.delete(trigger);
|
||||
}
|
||||
}
|
||||
|
||||
public void testUncheckedIOException() throws IOException {
|
||||
Path triggerFile = testFolder.resolve(Paths.get("dir2", "IOException"));
|
||||
Files.createFile(triggerFile);
|
||||
Path triggerDir = testFolder.resolve(Paths.get("empty", "IOException"));
|
||||
Files.createDirectories(triggerDir);
|
||||
Files.createFile(triggerDir.resolve("file"));
|
||||
FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
|
||||
FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
|
||||
|
||||
try {
|
||||
fsp.setFaultyMode(false);
|
||||
Path fakeRoot = fs.getRoot();
|
||||
try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
|
||||
// only one file
|
||||
s.forEach(path -> assertEquals(path.getFileName().toString(), "IOException"));
|
||||
}
|
||||
|
||||
try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
|
||||
String[] result = s.map(path -> path.getFileName().toString())
|
||||
.toArray(String[]::new);
|
||||
// ordered as depth-first
|
||||
assertEquals(result, new String[] { "empty", "IOException", "file"});
|
||||
}
|
||||
|
||||
fsp.setFaultyMode(true);
|
||||
try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
|
||||
s.forEach(path -> fail("should have caused exception"));
|
||||
} catch (UncheckedIOException uioe) {
|
||||
assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
|
||||
}
|
||||
|
||||
try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
|
||||
String[] result = s.map(path -> path.getFileName().toString())
|
||||
.toArray(String[]::new);
|
||||
fail("should not reach here due to IOException");
|
||||
} catch (UncheckedIOException uioe) {
|
||||
assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
|
||||
}
|
||||
|
||||
try (CloseableStream<Path> s = Files.walk(
|
||||
fakeRoot.resolve("empty").resolve("IOException")))
|
||||
{
|
||||
String[] result = s.map(path -> path.getFileName().toString())
|
||||
.toArray(String[]::new);
|
||||
fail("should not reach here due to IOException");
|
||||
} catch (IOException ioe) {
|
||||
assertTrue(ioe instanceof FaultyFileSystem.FaultyException);
|
||||
} catch (UncheckedIOException ex) {
|
||||
fail("Top level should be repored as is");
|
||||
}
|
||||
} finally {
|
||||
// Cleanup
|
||||
if (fs != null) {
|
||||
fs.close();
|
||||
}
|
||||
Files.delete(triggerFile);
|
||||
TestUtil.removeAll(triggerDir);
|
||||
}
|
||||
}
|
||||
|
||||
public void testSecurityException() throws IOException {
|
||||
Path triggerFile = testFolder.resolve(Paths.get("dir", "SecurityException"));
|
||||
Files.createFile(triggerFile);
|
||||
Path sampleFile = testFolder.resolve(Paths.get("dir", "sample"));
|
||||
Files.createFile(sampleFile);
|
||||
Path triggerDir = testFolder.resolve(Paths.get("dir2", "SecurityException"));
|
||||
Files.createDirectories(triggerDir);
|
||||
Files.createFile(triggerDir.resolve("fileInSE"));
|
||||
Path sample = testFolder.resolve(Paths.get("dir2", "file"));
|
||||
Files.createFile(sample);
|
||||
FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
|
||||
FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
|
||||
|
||||
try {
|
||||
fsp.setFaultyMode(false);
|
||||
Path fakeRoot = fs.getRoot();
|
||||
// validate setting
|
||||
try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
|
||||
String[] result = s.map(path -> path.getFileName().toString())
|
||||
.toArray(String[]::new);
|
||||
assertEqualsNoOrder(result, new String[] { "d1","f1", "lnDir2", "SecurityException", "sample" });
|
||||
}
|
||||
|
||||
try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
|
||||
String[] result = s.map(path -> path.getFileName().toString())
|
||||
.toArray(String[]::new);
|
||||
assertEqualsNoOrder(result, new String[] { "dir2", "SecurityException", "fileInSE", "file" });
|
||||
}
|
||||
|
||||
// execute test
|
||||
fsp.setFaultyMode(true);
|
||||
// ignore file cause SecurityException
|
||||
try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {
|
||||
String[] result = s.map(path -> path.getFileName().toString())
|
||||
.toArray(String[]::new);
|
||||
assertEqualsNoOrder(result, new String[] { "dir", "d1","f1", "lnDir2", "sample" });
|
||||
}
|
||||
// skip folder cause SecurityException
|
||||
try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
|
||||
String[] result = s.map(path -> path.getFileName().toString())
|
||||
.toArray(String[]::new);
|
||||
assertEqualsNoOrder(result, new String[] { "dir2", "file" });
|
||||
}
|
||||
|
||||
// list instead of walk
|
||||
try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
|
||||
String[] result = s.map(path -> path.getFileName().toString())
|
||||
.toArray(String[]::new);
|
||||
assertEqualsNoOrder(result, new String[] { "d1","f1", "lnDir2", "sample" });
|
||||
}
|
||||
try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
|
||||
String[] result = s.map(path -> path.getFileName().toString())
|
||||
.toArray(String[]::new);
|
||||
assertEqualsNoOrder(result, new String[] { "file" });
|
||||
}
|
||||
|
||||
// root cause SecurityException should be reported
|
||||
try (CloseableStream<Path> s = Files.walk(
|
||||
fakeRoot.resolve("dir2").resolve("SecurityException")))
|
||||
{
|
||||
String[] result = s.map(path -> path.getFileName().toString())
|
||||
.toArray(String[]::new);
|
||||
fail("should not reach here due to SecurityException");
|
||||
} catch (SecurityException se) {
|
||||
assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
|
||||
}
|
||||
|
||||
// Walk a file cause SecurityException, we should get SE
|
||||
try (CloseableStream<Path> s = Files.walk(
|
||||
fakeRoot.resolve("dir").resolve("SecurityException")))
|
||||
{
|
||||
String[] result = s.map(path -> path.getFileName().toString())
|
||||
.toArray(String[]::new);
|
||||
fail("should not reach here due to SecurityException");
|
||||
} catch (SecurityException se) {
|
||||
assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
|
||||
}
|
||||
|
||||
// List a file cause SecurityException, we should get SE as cannot read attribute
|
||||
try (CloseableStream<Path> s = Files.list(
|
||||
fakeRoot.resolve("dir2").resolve("SecurityException")))
|
||||
{
|
||||
String[] result = s.map(path -> path.getFileName().toString())
|
||||
.toArray(String[]::new);
|
||||
fail("should not reach here due to SecurityException");
|
||||
} catch (SecurityException se) {
|
||||
assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
|
||||
}
|
||||
|
||||
try (CloseableStream<Path> s = Files.list(
|
||||
fakeRoot.resolve("dir").resolve("SecurityException")))
|
||||
{
|
||||
String[] result = s.map(path -> path.getFileName().toString())
|
||||
.toArray(String[]::new);
|
||||
fail("should not reach here due to SecurityException");
|
||||
} catch (SecurityException se) {
|
||||
assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
|
||||
}
|
||||
} finally {
|
||||
// Cleanup
|
||||
if (fs != null) {
|
||||
fs.close();
|
||||
}
|
||||
Files.delete(triggerFile);
|
||||
Files.delete(sampleFile);
|
||||
Files.delete(sample);
|
||||
TestUtil.removeAll(triggerDir);
|
||||
}
|
||||
}
|
||||
|
||||
public void testConstructException() {
|
||||
try (CloseableStream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {
|
||||
s.forEach(l -> fail("File is not even exist!"));
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace(System.err);
|
||||
assertTrue(ioe instanceof NoSuchFileException);
|
||||
}
|
||||
}
|
||||
|
||||
public void testClosedStream() throws IOException {
|
||||
try (CloseableStream<Path> s = Files.list(testFolder)) {
|
||||
s.close();
|
||||
Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
|
||||
assertTrue(actual.length <= level1.length);
|
||||
}
|
||||
|
||||
try (CloseableStream<Path> s = Files.walk(testFolder)) {
|
||||
s.close();
|
||||
Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
|
||||
fail("Operate on closed stream should throw IllegalStateException");
|
||||
} catch (IllegalStateException ex) {
|
||||
// expected
|
||||
}
|
||||
|
||||
try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,
|
||||
(p, attr) -> true)) {
|
||||
s.close();
|
||||
Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
|
||||
fail("Operate on closed stream should throw IllegalStateException");
|
||||
} catch (IllegalStateException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user