001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.io.filefilter;
018
019import java.io.File;
020import java.io.FileFilter;
021import java.io.FilenameFilter;
022import java.util.Arrays;
023import java.util.Collections;
024import java.util.Date;
025import java.util.HashSet;
026import java.util.List;
027import java.util.Objects;
028import java.util.Set;
029import java.util.stream.Collector;
030import java.util.stream.Collectors;
031import java.util.stream.Stream;
032import java.util.stream.StreamSupport;
033
034import org.apache.commons.io.FileUtils;
035import org.apache.commons.io.IOCase;
036
037/**
038 * Useful utilities for working with file filters. It provides access to most
039 * file filter implementations in this package so you don't have to import
040 * every class you use.
041 *
042 * @since 1.0
043 */
044public class FileFilterUtils {
045
046    /* Constructed on demand and then cached */
047    private static final IOFileFilter CVS_FILTER = notFileFilter(
048            and(directoryFileFilter(), nameFileFilter("CVS")));
049
050    /* Constructed on demand and then cached */
051    private static final IOFileFilter SVN_FILTER = notFileFilter(
052            and(directoryFileFilter(), nameFileFilter(".svn")));
053
054    /**
055     * Returns a filter that returns true if the file was last modified before
056     * or at the specified cutoff date.
057     *
058     * @param cutoffDate  the time threshold
059     * @return an appropriately configured age file filter
060     * @see AgeFileFilter
061     * @since 1.2
062     */
063    public static IOFileFilter ageFileFilter(final Date cutoffDate) {
064        return new AgeFileFilter(cutoffDate);
065    }
066
067    /**
068     * Returns a filter that filters files based on a cutoff date.
069     *
070     * @param cutoffDate  the time threshold
071     * @param acceptOlder  if true, older files get accepted, if false, newer
072     * @return an appropriately configured age file filter
073     * @see AgeFileFilter
074     * @since 1.2
075     */
076    public static IOFileFilter ageFileFilter(final Date cutoffDate, final boolean acceptOlder) {
077        return new AgeFileFilter(cutoffDate, acceptOlder);
078    }
079
080    /**
081     * Returns a filter that returns true if the file was last modified before
082     * or at the same time as the specified reference file.
083     *
084     * @param cutoffReference  the file whose last modification
085     *        time is used as the threshold age of the files
086     * @return an appropriately configured age file filter
087     * @see AgeFileFilter
088     * @since 1.2
089     */
090    public static IOFileFilter ageFileFilter(final File cutoffReference) {
091        return new AgeFileFilter(cutoffReference);
092    }
093
094    /**
095     * Returns a filter that filters files based on a cutoff reference file.
096     *
097     * @param cutoffReference  the file whose last modification
098     *        time is used as the threshold age of the files
099     * @param acceptOlder  if true, older files get accepted, if false, newer
100     * @return an appropriately configured age file filter
101     * @see AgeFileFilter
102     * @since 1.2
103     */
104    public static IOFileFilter ageFileFilter(final File cutoffReference, final boolean acceptOlder) {
105        return new AgeFileFilter(cutoffReference, acceptOlder);
106    }
107
108    /**
109     * Returns a filter that returns true if the file was last modified before
110     * or at the specified cutoff time.
111     *
112     * @param cutoffMillis  the time threshold
113     * @return an appropriately configured age file filter
114     * @see AgeFileFilter
115     * @since 1.2
116     */
117    public static IOFileFilter ageFileFilter(final long cutoffMillis) {
118        return new AgeFileFilter(cutoffMillis);
119    }
120
121    /**
122     * Returns a filter that filters files based on a cutoff time.
123     *
124     * @param cutoffMillis  the time threshold
125     * @param acceptOlder  if true, older files get accepted, if false, newer
126     * @return an appropriately configured age file filter
127     * @see AgeFileFilter
128     * @since 1.2
129     */
130    public static IOFileFilter ageFileFilter(final long cutoffMillis, final boolean acceptOlder) {
131        return new AgeFileFilter(cutoffMillis, acceptOlder);
132    }
133
134    /**
135     * Returns a filter that ANDs the specified filters.
136     *
137     * @param filters the IOFileFilters that will be ANDed together.
138     * @return a filter that ANDs the specified filters
139     *
140     * @throws IllegalArgumentException if the filters are null or contain a
141     *         null value.
142     * @see AndFileFilter
143     * @since 2.0
144     */
145    public static IOFileFilter and(final IOFileFilter... filters) {
146        return new AndFileFilter(toList(filters));
147    }
148
149    /**
150     * Returns a filter that ANDs the two specified filters.
151     *
152     * @param filter1  the first filter
153     * @param filter2  the second filter
154     * @return a filter that ANDs the two specified filters
155     * @see #and(IOFileFilter...)
156     * @see AndFileFilter
157     * @deprecated use {@link #and(IOFileFilter...)}
158     */
159    @Deprecated
160    public static IOFileFilter andFileFilter(final IOFileFilter filter1, final IOFileFilter filter2) {
161        return new AndFileFilter(filter1, filter2);
162    }
163
164    /**
165     * Returns an {@link IOFileFilter} that wraps the
166     * {@link FileFilter} instance.
167     *
168     * @param filter  the filter to be wrapped
169     * @return a new filter that implements IOFileFilter
170     * @see DelegateFileFilter
171     */
172    public static IOFileFilter asFileFilter(final FileFilter filter) {
173        return new DelegateFileFilter(filter);
174    }
175
176    /**
177     * Returns an {@link IOFileFilter} that wraps the
178     * {@link FilenameFilter} instance.
179     *
180     * @param filter  the filter to be wrapped
181     * @return a new filter that implements IOFileFilter
182     * @see DelegateFileFilter
183     */
184    public static IOFileFilter asFileFilter(final FilenameFilter filter) {
185        return new DelegateFileFilter(filter);
186    }
187
188    /**
189     * Returns a filter that checks if the file is a directory.
190     *
191     * @return file filter that accepts only directories and not files
192     * @see DirectoryFileFilter#DIRECTORY
193     */
194    public static IOFileFilter directoryFileFilter() {
195        return DirectoryFileFilter.DIRECTORY;
196    }
197
198    /**
199     * Returns a filter that always returns false.
200     *
201     * @return a false filter
202     * @see FalseFileFilter#FALSE
203     */
204    public static IOFileFilter falseFileFilter() {
205        return FalseFileFilter.FALSE;
206    }
207
208    /**
209     * Returns a filter that checks if the file is a file (and not a directory).
210     *
211     * @return file filter that accepts only files and not directories
212     * @see FileFileFilter#INSTANCE
213     */
214    public static IOFileFilter fileFileFilter() {
215        return FileFileFilter.INSTANCE;
216    }
217
218    /**
219     * <p>
220     * Applies an {@link IOFileFilter} to the provided {@link File}
221     * objects. The resulting array is a subset of the original file list that
222     * matches the provided filter.
223     * </p>
224     *
225     * <pre>
226     * Set&lt;File&gt; allFiles = ...
227     * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
228     *     FileFilterUtils.suffixFileFilter(".java"));
229     * </pre>
230     * @param filter the filter to apply to the set of files.
231     * @param files the array of files to apply the filter to.
232     *
233     * @return a subset of {@code files} that is accepted by the
234     *         file filter.
235     * @throws NullPointerException if the filter is {@code null}
236     *         or {@code files} contains a {@code null} value.
237     *
238     * @since 2.0
239     */
240    public static File[] filter(final IOFileFilter filter, final File... files) {
241        Objects.requireNonNull(filter, "filter");
242        if (files == null) {
243            return FileUtils.EMPTY_FILE_ARRAY;
244        }
245        return filterFiles(filter, Stream.of(files), Collectors.toList()).toArray(FileUtils.EMPTY_FILE_ARRAY);
246    }
247
248    /**
249     * <p>
250     * Applies an {@link IOFileFilter} to the provided {@link File}
251     * objects. The resulting array is a subset of the original file list that
252     * matches the provided filter.
253     * </p>
254     *
255     * <p>
256     * The {@link Set} returned by this method is not guaranteed to be thread safe.
257     * </p>
258     *
259     * <pre>
260     * Set&lt;File&gt; allFiles = ...
261     * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
262     *     FileFilterUtils.suffixFileFilter(".java"));
263     * </pre>
264     * @param filter the filter to apply to the set of files.
265     * @param files the array of files to apply the filter to.
266     *
267     * @return a subset of {@code files} that is accepted by the
268     *         file filter.
269     * @throws IllegalArgumentException if the filter is {@code null}
270     *         or {@code files} contains a {@code null} value.
271     *
272     * @since 2.0
273     */
274    public static File[] filter(final IOFileFilter filter, final Iterable<File> files) {
275        return filterList(filter, files).toArray(FileUtils.EMPTY_FILE_ARRAY);
276    }
277
278    /**
279     * <p>
280     * Applies an {@link IOFileFilter} to the provided {@link File} stream and collects the accepted files.
281     * </p>
282     *
283     * @param filter the filter to apply to the stream of files.
284     * @param stream the stream of files on which to apply the filter.
285     * @param collector how to collect the end result.
286     *
287     * @param <R> the return type.
288     * @param <A> the mutable accumulation type of the reduction operation (often hidden as an implementation detail)
289     * @return a subset of files from the stream that is accepted by the filter.
290     * @throws NullPointerException if the filter is {@code null}.
291     */
292    private static <R, A> R filterFiles(final IOFileFilter filter, final Stream<File> stream,
293        final Collector<? super File, A, R> collector) {
294        Objects.requireNonNull(filter, "filter");
295        Objects.requireNonNull(collector, "collector");
296        if (stream == null) {
297            return Stream.<File>empty().collect(collector);
298        }
299        return stream.filter(filter::accept).collect(collector);
300    }
301
302    /**
303     * <p>
304     * Applies an {@link IOFileFilter} to the provided {@link File}
305     * objects. The resulting list is a subset of the original files that
306     * matches the provided filter.
307     * </p>
308     *
309     * <p>
310     * The {@link List} returned by this method is not guaranteed to be thread safe.
311     * </p>
312     *
313     * <pre>
314     * List&lt;File&gt; filesAndDirectories = ...
315     * List&lt;File&gt; directories = FileFilterUtils.filterList(filesAndDirectories,
316     *     FileFilterUtils.directoryFileFilter());
317     * </pre>
318     * @param filter the filter to apply to each files in the list.
319     * @param files the collection of files to apply the filter to.
320     *
321     * @return a subset of {@code files} that is accepted by the
322     *         file filter.
323     * @throws IllegalArgumentException if the filter is {@code null}
324     *         or {@code files} contains a {@code null} value.
325     * @since 2.0
326     */
327    public static List<File> filterList(final IOFileFilter filter, final File... files) {
328        return Arrays.asList(filter(filter, files));
329    }
330
331    /**
332     * <p>
333     * Applies an {@link IOFileFilter} to the provided {@link File}
334     * objects. The resulting list is a subset of the original files that
335     * matches the provided filter.
336     * </p>
337     *
338     * <p>
339     * The {@link List} returned by this method is not guaranteed to be thread safe.
340     * </p>
341     *
342     * <pre>
343     * List&lt;File&gt; filesAndDirectories = ...
344     * List&lt;File&gt; directories = FileFilterUtils.filterList(filesAndDirectories,
345     *     FileFilterUtils.directoryFileFilter());
346     * </pre>
347     * @param filter the filter to apply to each files in the list.
348     * @param files the collection of files to apply the filter to.
349     *
350     * @return a subset of {@code files} that is accepted by the
351     *         file filter.
352     * @throws IllegalArgumentException if the filter is {@code null}
353     * @since 2.0
354     */
355    public static List<File> filterList(final IOFileFilter filter, final Iterable<File> files) {
356        if (files == null) {
357            return Collections.emptyList();
358        }
359        return filterFiles(filter, StreamSupport.stream(files.spliterator(), false), Collectors.toList());
360    }
361
362    /**
363     * <p>
364     * Applies an {@link IOFileFilter} to the provided {@link File}
365     * objects. The resulting set is a subset of the original file list that
366     * matches the provided filter.
367     * </p>
368     *
369     * <p>
370     * The {@link Set} returned by this method is not guaranteed to be thread safe.
371     * </p>
372     *
373     * <pre>
374     * Set&lt;File&gt; allFiles = ...
375     * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
376     *     FileFilterUtils.suffixFileFilter(".java"));
377     * </pre>
378     * @param filter the filter to apply to the set of files.
379     * @param files the collection of files to apply the filter to.
380     *
381     * @return a subset of {@code files} that is accepted by the
382     *         file filter.
383     * @throws IllegalArgumentException if the filter is {@code null}
384     *         or {@code files} contains a {@code null} value.
385     *
386     * @since 2.0
387     */
388    public static Set<File> filterSet(final IOFileFilter filter, final File... files) {
389        return new HashSet<>(Arrays.asList(filter(filter, files)));
390    }
391
392    /**
393     * <p>
394     * Applies an {@link IOFileFilter} to the provided {@link File}
395     * objects. The resulting set is a subset of the original file list that
396     * matches the provided filter.
397     * </p>
398     *
399     * <p>
400     * The {@link Set} returned by this method is not guaranteed to be thread safe.
401     * </p>
402     *
403     * <pre>
404     * Set&lt;File&gt; allFiles = ...
405     * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
406     *     FileFilterUtils.suffixFileFilter(".java"));
407     * </pre>
408     * @param filter the filter to apply to the set of files.
409     * @param files the collection of files to apply the filter to.
410     *
411     * @return a subset of {@code files} that is accepted by the
412     *         file filter.
413     * @throws IllegalArgumentException if the filter is {@code null}
414     *
415     * @since 2.0
416     */
417    public static Set<File> filterSet(final IOFileFilter filter, final Iterable<File> files) {
418        if (files == null) {
419            return Collections.emptySet();
420        }
421        return filterFiles(filter, StreamSupport.stream(files.spliterator(), false), Collectors.toSet());
422    }
423
424    /**
425     * Returns a filter that accepts files that begin with the provided magic
426     * number.
427     *
428     * @param magicNumber the magic number (byte sequence) to match at the
429     *        beginning of each file.
430     *
431     * @return an IOFileFilter that accepts files beginning with the provided
432     *         magic number.
433     *
434     * @throws IllegalArgumentException if {@code magicNumber} is
435     *         {@code null} or is of length zero.
436     * @see MagicNumberFileFilter
437     * @since 2.0
438     */
439    public static IOFileFilter magicNumberFileFilter(final byte[] magicNumber) {
440        return new MagicNumberFileFilter(magicNumber);
441    }
442
443    /**
444     * Returns a filter that accepts files that contains the provided magic
445     * number at a specified offset within the file.
446     *
447     * @param magicNumber the magic number (byte sequence) to match at the
448     *        provided offset in each file.
449     * @param offset the offset within the files to look for the magic number.
450     *
451     * @return an IOFileFilter that accepts files containing the magic number
452     *         at the specified offset.
453     *
454     * @throws IllegalArgumentException if {@code magicNumber} is
455     *         {@code null}, or contains no bytes, or {@code offset}
456     *         is a negative number.
457     * @see MagicNumberFileFilter
458     * @since 2.0
459     */
460    public static IOFileFilter magicNumberFileFilter(final byte[] magicNumber, final long offset) {
461        return new MagicNumberFileFilter(magicNumber, offset);
462    }
463
464    /**
465     * Returns a filter that accepts files that begin with the provided magic
466     * number.
467     *
468     * @param magicNumber the magic number (byte sequence) to match at the
469     *        beginning of each file.
470     *
471     * @return an IOFileFilter that accepts files beginning with the provided
472     *         magic number.
473     *
474     * @throws IllegalArgumentException if {@code magicNumber} is
475     *         {@code null} or the empty String.
476     * @see MagicNumberFileFilter
477     * @since 2.0
478     */
479    public static IOFileFilter magicNumberFileFilter(final String magicNumber) {
480        return new MagicNumberFileFilter(magicNumber);
481    }
482
483    /**
484     * Returns a filter that accepts files that contains the provided magic
485     * number at a specified offset within the file.
486     *
487     * @param magicNumber the magic number (byte sequence) to match at the
488     *        provided offset in each file.
489     * @param offset the offset within the files to look for the magic number.
490     *
491     * @return an IOFileFilter that accepts files containing the magic number
492     *         at the specified offset.
493     *
494     * @throws IllegalArgumentException if {@code magicNumber} is
495     *         {@code null} or the empty String, or if offset is a
496     *         negative number.
497     * @see MagicNumberFileFilter
498     * @since 2.0
499     */
500    public static IOFileFilter magicNumberFileFilter(final String magicNumber, final long offset) {
501        return new MagicNumberFileFilter(magicNumber, offset);
502    }
503
504    /**
505     * Decorates a filter to make it ignore CVS directories.
506     * Passing in {@code null} will return a filter that accepts everything
507     * except CVS directories.
508     *
509     * @param filter  the filter to decorate, null means an unrestricted filter
510     * @return the decorated filter, never null
511     * @since 1.1 (method existed but had a bug in 1.0)
512     */
513    public static IOFileFilter makeCVSAware(final IOFileFilter filter) {
514        return filter == null ? CVS_FILTER : and(filter, CVS_FILTER);
515    }
516
517    /**
518     * Decorates a filter so that it only applies to directories and not to files.
519     *
520     * @param filter  the filter to decorate, null means an unrestricted filter
521     * @return the decorated filter, never null
522     * @see DirectoryFileFilter#DIRECTORY
523     * @since 1.3
524     */
525    public static IOFileFilter makeDirectoryOnly(final IOFileFilter filter) {
526        if (filter == null) {
527            return DirectoryFileFilter.DIRECTORY;
528        }
529        return DirectoryFileFilter.DIRECTORY.and(filter);
530    }
531
532    /**
533     * Decorates a filter so that it only applies to files and not to directories.
534     *
535     * @param filter  the filter to decorate, null means an unrestricted filter
536     * @return the decorated filter, never null
537     * @see FileFileFilter#INSTANCE
538     * @since 1.3
539     */
540    public static IOFileFilter makeFileOnly(final IOFileFilter filter) {
541        if (filter == null) {
542            return FileFileFilter.INSTANCE;
543        }
544        return FileFileFilter.INSTANCE.and(filter);
545    }
546
547    /**
548     * Decorates a filter to make it ignore SVN directories.
549     * Passing in {@code null} will return a filter that accepts everything
550     * except SVN directories.
551     *
552     * @param filter  the filter to decorate, null means an unrestricted filter
553     * @return the decorated filter, never null
554     * @since 1.1
555     */
556    public static IOFileFilter makeSVNAware(final IOFileFilter filter) {
557        return filter == null ? SVN_FILTER : and(filter, SVN_FILTER);
558    }
559
560    /**
561     * Returns a filter that returns true if the file name matches the specified text.
562     *
563     * @param name  the file name
564     * @return a name checking filter
565     * @see NameFileFilter
566     */
567    public static IOFileFilter nameFileFilter(final String name) {
568        return new NameFileFilter(name);
569    }
570
571    /**
572     * Returns a filter that returns true if the file name matches the specified text.
573     *
574     * @param name  the file name
575     * @param ioCase  how to handle case sensitivity, null means case-sensitive
576     * @return a name checking filter
577     * @see NameFileFilter
578     * @since 2.0
579     */
580    public static IOFileFilter nameFileFilter(final String name, final IOCase ioCase) {
581        return new NameFileFilter(name, ioCase);
582    }
583
584    /**
585     * Returns a filter that NOTs the specified filter.
586     *
587     * @param filter  the filter to invert
588     * @return a filter that NOTs the specified filter
589     * @see NotFileFilter
590     */
591    public static IOFileFilter notFileFilter(final IOFileFilter filter) {
592        return filter.negate();
593    }
594
595    /**
596     * Returns a filter that ORs the specified filters.
597     *
598     * @param filters the IOFileFilters that will be ORed together.
599     * @return a filter that ORs the specified filters
600     *
601     * @throws IllegalArgumentException if the filters are null or contain a
602     *         null value.
603     * @see OrFileFilter
604     * @since 2.0
605     */
606    public static IOFileFilter or(final IOFileFilter... filters) {
607        return new OrFileFilter(toList(filters));
608    }
609
610    /**
611     * Returns a filter that ORs the two specified filters.
612     *
613     * @param filter1  the first filter
614     * @param filter2  the second filter
615     * @return a filter that ORs the two specified filters
616     * @see #or(IOFileFilter...)
617     * @see OrFileFilter
618     * @deprecated use {@link #or(IOFileFilter...)}
619     */
620    @Deprecated
621    public static IOFileFilter orFileFilter(final IOFileFilter filter1, final IOFileFilter filter2) {
622        return new OrFileFilter(filter1, filter2);
623    }
624
625    /**
626     * Returns a filter that returns true if the file name starts with the specified text.
627     *
628     * @param prefix  the file name prefix
629     * @return a prefix checking filter
630     * @see PrefixFileFilter
631     */
632    public static IOFileFilter prefixFileFilter(final String prefix) {
633        return new PrefixFileFilter(prefix);
634    }
635
636    /**
637     * Returns a filter that returns true if the file name starts with the specified text.
638     *
639     * @param prefix  the file name prefix
640     * @param ioCase  how to handle case sensitivity, null means case-sensitive
641     * @return a prefix checking filter
642     * @see PrefixFileFilter
643     * @since 2.0
644     */
645    public static IOFileFilter prefixFileFilter(final String prefix, final IOCase ioCase) {
646        return new PrefixFileFilter(prefix, ioCase);
647    }
648
649    /**
650     * Returns a filter that returns true if the file is bigger than a certain size.
651     *
652     * @param threshold  the file size threshold
653     * @return an appropriately configured SizeFileFilter
654     * @see SizeFileFilter
655     * @since 1.2
656     */
657    public static IOFileFilter sizeFileFilter(final long threshold) {
658        return new SizeFileFilter(threshold);
659    }
660
661    /**
662     * Returns a filter that filters based on file size.
663     *
664     * @param threshold  the file size threshold
665     * @param acceptLarger  if true, larger files get accepted, if false, smaller
666     * @return an appropriately configured SizeFileFilter
667     * @see SizeFileFilter
668     * @since 1.2
669     */
670    public static IOFileFilter sizeFileFilter(final long threshold, final boolean acceptLarger) {
671        return new SizeFileFilter(threshold, acceptLarger);
672    }
673
674    /**
675     * Returns a filter that accepts files whose size is &gt;= minimum size
676     * and &lt;= maximum size.
677     *
678     * @param minSizeInclusive the minimum file size (inclusive)
679     * @param maxSizeInclusive the maximum file size (inclusive)
680     * @return an appropriately configured IOFileFilter
681     * @see SizeFileFilter
682     * @since 1.3
683     */
684    public static IOFileFilter sizeRangeFileFilter(final long minSizeInclusive, final long maxSizeInclusive ) {
685        final IOFileFilter minimumFilter = new SizeFileFilter(minSizeInclusive, true);
686        final IOFileFilter maximumFilter = new SizeFileFilter(maxSizeInclusive + 1L, false);
687        return minimumFilter.and(maximumFilter);
688    }
689
690    /**
691     * Returns a filter that returns true if the file name ends with the specified text.
692     *
693     * @param suffix  the file name suffix
694     * @return a suffix checking filter
695     * @see SuffixFileFilter
696     */
697    public static IOFileFilter suffixFileFilter(final String suffix) {
698        return new SuffixFileFilter(suffix);
699    }
700
701    /**
702     * Returns a filter that returns true if the file name ends with the specified text.
703     *
704     * @param suffix  the file name suffix
705     * @param ioCase  how to handle case sensitivity, null means case-sensitive
706     * @return a suffix checking filter
707     * @see SuffixFileFilter
708     * @since 2.0
709     */
710    public static IOFileFilter suffixFileFilter(final String suffix, final IOCase ioCase) {
711        return new SuffixFileFilter(suffix, ioCase);
712    }
713
714    /**
715     * Create a List of file filters.
716     *
717     * @param filters The file filters
718     * @return The list of file filters
719     * @throws NullPointerException if the filters are null or contain a
720     *         null value.
721     * @since 2.0
722     */
723    public static List<IOFileFilter> toList(final IOFileFilter... filters) {
724        return Stream.of(Objects.requireNonNull(filters, "filters")).map(Objects::requireNonNull).collect(Collectors.toList());
725    }
726
727    /**
728     * Returns a filter that always returns true.
729     *
730     * @return a true filter
731     * @see TrueFileFilter#TRUE
732     */
733    public static IOFileFilter trueFileFilter() {
734        return TrueFileFilter.TRUE;
735    }
736
737    /**
738     * FileFilterUtils is not normally instantiated.
739     */
740    public FileFilterUtils() {
741    }
742
743}