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