Java tutorial
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common * Development and Distribution License("CDDL") (collectively, the * "License"). You may not use this file except in compliance with the * License. You can obtain a copy of the License at * http://www.netbeans.org/cddl-gplv2.html * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the * specific language governing permissions and limitations under the * License. When distributing the software, include this License Header * Notice in each file and include the License file at * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the * License Header, with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL * or only the GPL Version 2, indicate your decision by adding * "[Contributor] elects to include this software in this distribution * under the [CDDL or GPL Version 2] license." If you do not indicate a * single choice of license, a recipient has the option to distribute * your version of this file under either the CDDL, the GPL Version 2 or * to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. */ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; /** * @since 4.37 * @author Jaroslav Tulach */ final class Enumerations extends Object { /** * Removes all <code>null</code>s from the input enumeration. * @param en enumeration that can contain nulls * @return new enumeration without null values */ public static <T> Enumeration<T> removeNulls(Enumeration<T> en) { return filter(en, new RNulls<T>()); } /** * For each element of the input enumeration <code>en</code> asks the * {@link Processor} to provide a replacement. * The <code>toAdd</code> argument of the processor is always null. * * Example to convert any objects into strings: * <pre> * Processor convertToString = new Processor() { * public Object process(Object obj, Collection alwaysNull) { * return obj.toString(); // converts to string * } * }; * Enumeration strings = Enumerations.convert(elems, convertToString); * </pre> * * @param en enumeration of any objects * @param processor a callback processor for the elements (its toAdd arguments is always null) * @return new enumeration where all elements has been processed */ public static <T, R> Enumeration<R> convert(Enumeration<? extends T> en, Processor<T, R> processor) { return new AltEn<T, R>(en, processor); } /** * Filters some elements out from the input enumeration. * Just make the * {@link Processor} return <code>null</code>. Please notice the <code>toAdd</code> * argument of the processor is always <code>null</code>. * * Example to remove all objects that are not strings: * <pre> * Processor onlyString = new Processor() { * public Object process(Object obj, Collection alwaysNull) { * if (obj instanceof String) { * return obj; * } else { * return null; * } * } * }; * Enumeration strings = Enumerations.filter(elems, onlyString); * </pre> * * @param en enumeration of any objects * @param filter a callback processor for the elements (its toAdd arguments is always null) * @return new enumeration which does not include non-processed (returned null from processor) elements * @see NbCollections#checkedEnumerationByFilter */ public static <T, R> Enumeration<R> filter(Enumeration<? extends T> en, Processor<T, R> filter) { return new FilEn<T, R>(en, filter); } /** * Support for breadth-first enumerating. * Before any element is returned * for the resulting enumeration it is processed in the {@link Processor} and * the processor is allowed to modify it and also add additional elements * at the (current) end of the <q>queue</q> by calling <code>toAdd.add</code> * or <code>toAdd.addAll</code>. No other methods can be called on the * provided <code>toAdd</code> collection. * * Example of doing breadth-first walk through a tree: * <pre> * Processor queueSubnodes = new Processor() { * public Object process(Object obj, Collection toAdd) { * Node n = (Node)obj; * toAdd.addAll (n.getChildrenList()); * return n; * } * }; * Enumeration strings = Enumerations.queue(elems, queueSubnodes); * </pre> * * @param en initial content of the resulting enumeration * @param filter the processor that is called for each element and can * add and addAll elements to its toAdd Collection argument and * also change the value to be returned * @return enumeration with the initial and queued content (it can contain * <code>null</code> if the filter returned <code>null</code> from its * {@link Processor#process} method. */ public static <T, R> Enumeration<R> queue(Enumeration<? extends T> en, Processor<T, R> filter) { QEn<T, R> q = new QEn<T, R>(filter); while (en.hasMoreElements()) { q.put(en.nextElement()); } return q; } /** * Processor interface that can filter out objects from the enumeration, * change them or add aditional objects to the end of the current enumeration. */ public static interface Processor<T, R> { /** @param original the object that is going to be returned from the enumeration right now * @return a replacement for this object * @param toAdd can be non-null if one can add new objects at the end of the enumeration */ public R process(T original, Collection<T> toAdd); } /** Altering enumeration implementation */ private static final class AltEn<T, R> extends Object implements Enumeration<R> { /** enumeration to filter */ private Enumeration<? extends T> en; /** map to alter */ private Processor<T, R> process; /** * @param en enumeration to filter */ public AltEn(Enumeration<? extends T> en, Processor<T, R> process) { this.en = en; this.process = process; } /** @return true if there is more elements in the enumeration */ public boolean hasMoreElements() { return en.hasMoreElements(); } /** @return next object in the enumeration * @exception NoSuchElementException can be thrown if there is no next object * in the enumeration */ public R nextElement() { return process.process(en.nextElement(), null); } } // end of AltEn /** QueueEnumeration */ private static class QEn<T, R> extends Object implements Enumeration<R> { /** next object to be returned */ private ListItem<T> next = null; /** last object in the queue */ private ListItem<T> last = null; /** processor to use */ private Processor<T, R> processor; public QEn(Processor<T, R> p) { this.processor = p; } /** Put adds new object to the end of queue. * @param o the object to add */ public void put(T o) { if (last != null) { ListItem<T> li = new ListItem<T>(o); last.next = li; last = li; } else { next = last = new ListItem<T>(o); } } /** Adds array of objects into the queue. * @param arr array of objects to put into the queue */ public void put(Collection<? extends T> arr) { for (T e : arr) { put(e); } } /** Is there any next object? * @return true if there is next object, false otherwise */ public boolean hasMoreElements() { return next != null; } /** @return next object in enumeration * @exception NoSuchElementException if there is no next object */ public R nextElement() { if (next == null) { throw new NoSuchElementException(); } T res = next.object; if ((next = next.next) == null) { last = null; } ; ToAdd<T, R> toAdd = new ToAdd<T, R>(this); R out = processor.process(res, toAdd); toAdd.finish(); return out; } /** item in linked list of Objects */ private static final class ListItem<T> { T object; ListItem<T> next; /** @param o the object for this item */ ListItem(T o) { object = o; } } /** Temporary collection that supports only add and addAll operations*/ private static final class ToAdd<T, R> extends Object implements Collection<T> { private QEn<T, R> q; public ToAdd(QEn<T, R> q) { this.q = q; } public void finish() { this.q = null; } public boolean add(T o) { q.put(o); return true; } public boolean addAll(Collection<? extends T> c) { q.put(c); return true; } private String msg() { return "Only add and addAll are implemented"; // NOI18N } public void clear() { throw new UnsupportedOperationException(msg()); } public boolean contains(Object o) { throw new UnsupportedOperationException(msg()); } public boolean containsAll(Collection c) { throw new UnsupportedOperationException(msg()); } public boolean isEmpty() { throw new UnsupportedOperationException(msg()); } public Iterator<T> iterator() { throw new UnsupportedOperationException(msg()); } public boolean remove(Object o) { throw new UnsupportedOperationException(msg()); } public boolean removeAll(Collection c) { throw new UnsupportedOperationException(msg()); } public boolean retainAll(Collection c) { throw new UnsupportedOperationException(msg()); } public int size() { throw new UnsupportedOperationException(msg()); } public Object[] toArray() { throw new UnsupportedOperationException(msg()); } public <X> X[] toArray(X[] a) { throw new UnsupportedOperationException(msg()); } } // end of ToAdd } // end of QEn /** Filtering enumeration */ private static final class FilEn<T, R> extends Object implements Enumeration<R> { /** marker object stating there is no nexte element prepared */ private static final Object EMPTY = new Object(); /** enumeration to filter */ private Enumeration<? extends T> en; /** element to be returned next time or {@link #EMPTY} if there is * no such element prepared */ private R next = empty(); /** the set to use as filter */ private Processor<T, R> filter; /** * @param en enumeration to filter */ public FilEn(Enumeration<? extends T> en, Processor<T, R> filter) { this.en = en; this.filter = filter; } /** @return true if there is more elements in the enumeration */ public boolean hasMoreElements() { if (next != empty()) { // there is a object already prepared return true; } while (en.hasMoreElements()) { // read next next = filter.process(en.nextElement(), null); if (next != null) { // if the object is accepted return true; } ; } next = empty(); return false; } /** @return next object in the enumeration * @exception NoSuchElementException can be thrown if there is no next object * in the enumeration */ public R nextElement() { if ((next == EMPTY) && !hasMoreElements()) { throw new NoSuchElementException(); } R res = next; next = empty(); return res; } @SuppressWarnings("unchecked") private R empty() { return (R) EMPTY; } } // end of FilEn /** Returns true from contains if object is not null */ private static class RNulls<T> implements Processor<T, T> { public T process(T original, Collection<T> toAdd) { return original; } } // end of RNulls }