Lists.java Source code

Java tutorial

Introduction

Here is the source code for Lists.java

Source

/*
 * Copyright 2009 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Utility methods for operating on memory-efficient lists. All lists of size 0
 * or 1 are assumed to be immutable. All lists of size greater than 1 are
 * assumed to be mutable.
 */
public class Lists {

    private static final Class<?> MULTI_LIST_CLASS = ArrayList.class;
    private static final Class<?> SINGLETON_LIST_CLASS = Collections.singletonList(null).getClass();

    public static <T> List<T> add(List<T> list, int index, T toAdd) {
        switch (list.size()) {
        case 0:
            // Empty -> Singleton
            if (index != 0) {
                throw newIndexOutOfBounds(list, index);
            }
            return Collections.singletonList(toAdd);
        case 1: {
            // Singleton -> ArrayList
            List<T> result = new ArrayList<T>(2);
            switch (index) {
            case 0:
                result.add(toAdd);
                result.add(list.get(0));
                return result;
            case 1:
                result.add(list.get(0));
                result.add(toAdd);
                return result;
            default:
                throw newIndexOutOfBounds(list, index);
            }
        }
        default:
            // ArrayList
            list.add(index, toAdd);
            return list;
        }
    }

    public static <T> List<T> add(List<T> list, T toAdd) {
        switch (list.size()) {
        case 0:
            // Empty -> Singleton
            return Collections.singletonList(toAdd);
        case 1: {
            // Singleton -> ArrayList
            List<T> result = new ArrayList<T>(2);
            result.add(list.get(0));
            result.add(toAdd);
            return result;
        }
        default:
            // ArrayList
            list.add(toAdd);
            return list;
        }
    }

    public static <T> List<T> addAll(List<T> list, int index, List<T> toAdd) {
        switch (toAdd.size()) {
        case 0:
            // No-op.
            return list;
        case 1:
            // Add one element.
            return add(list, index, toAdd.get(0));
        default:
            // True list merge, result >= 2.
            switch (list.size()) {
            case 0:
                if (index != 0) {
                    throw newIndexOutOfBounds(list, index);
                }
                return new ArrayList<T>(toAdd);
            case 1: {
                List<T> result = new ArrayList<T>(1 + toAdd.size());
                switch (index) {
                case 0:
                    result.addAll(toAdd);
                    result.add(list.get(0));
                    return result;
                case 1:
                    result.add(list.get(0));
                    result.addAll(toAdd);
                    return result;
                default:
                    throw newIndexOutOfBounds(list, index);
                }
            }
            default:
                list.addAll(index, toAdd);
                return list;
            }
        }
    }

    public static <T> List<T> addAll(List<T> list, List<T> toAdd) {
        switch (toAdd.size()) {
        case 0:
            // No-op.
            return list;
        case 1:
            // Add one element.
            return add(list, toAdd.get(0));
        default:
            // True list merge, result >= 2.
            switch (list.size()) {
            case 0:
                return new ArrayList<T>(toAdd);
            case 1: {
                List<T> result = new ArrayList<T>(1 + toAdd.size());
                result.add(list.get(0));
                result.addAll(toAdd);
                return result;
            }
            default:
                list.addAll(toAdd);
                return list;
            }
        }
    }

    public static <T> List<T> addAll(List<T> list, T... toAdd) {
        switch (toAdd.length) {
        case 0:
            // No-op.
            return list;
        case 1:
            // Add one element.
            return add(list, toAdd[0]);
        default:
            // True list merge, result >= 2.
            switch (list.size()) {
            case 0:
                return new ArrayList<T>(Arrays.asList(toAdd));
            case 1: {
                List<T> result = new ArrayList<T>(1 + toAdd.length);
                result.add(list.get(0));
                result.addAll(Arrays.asList(toAdd));
                return result;
            }
            default:
                list.addAll(Arrays.asList(toAdd));
                return list;
            }
        }
    }

    public static <T> List<T> create() {
        return Collections.emptyList();
    }

    public static <T> List<T> create(T item) {
        return Collections.singletonList(item);
    }

    public static <T> List<T> create(T... items) {
        switch (items.length) {
        case 0:
            return create();
        case 1:
            return create(items[0]);
        default:
            return new ArrayList<T>(Arrays.asList(items));
        }
    }

    public static <T> List<T> normalize(List<T> list) {
        switch (list.size()) {
        case 0:
            return create();
        case 1: {
            if (list.getClass() == SINGLETON_LIST_CLASS) {
                return list;
            }
            return create(list.get(0));
        }
        default:
            if (list.getClass() == MULTI_LIST_CLASS) {
                return list;
            }
            return new ArrayList<T>(list);
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> List<T> normalizeUnmodifiable(List<T> list) {
        if (list.size() < 2) {
            return normalize(list);
        } else {
            return (List<T>) Arrays.asList(list.toArray());
        }
    }

    public static <T> List<T> remove(List<T> list, int toRemove) {
        switch (list.size()) {
        case 0:
            // Empty
            throw newIndexOutOfBounds(list, toRemove);
        case 1:
            // Singleton -> Empty
            if (toRemove == 0) {
                return Collections.emptyList();
            } else {
                throw newIndexOutOfBounds(list, toRemove);
            }
        case 2:
            // ArrayList -> Singleton
            switch (toRemove) {
            case 0:
                return Collections.singletonList(list.get(1));
            case 1:
                return Collections.singletonList(list.get(0));
            default:
                throw newIndexOutOfBounds(list, toRemove);
            }
        default:
            // ArrayList
            list.remove(toRemove);
            return list;
        }
    }

    public static <T> List<T> set(List<T> list, int index, T e) {
        switch (list.size()) {
        case 0:
            // Empty
            throw newIndexOutOfBounds(list, index);
        case 1:
            // Singleton
            if (index == 0) {
                return Collections.singletonList(e);
            } else {
                throw newIndexOutOfBounds(list, index);
            }
        default:
            // ArrayList
            list.set(index, e);
            return list;
        }
    }

    public static <T> List<T> sort(List<T> list, Comparator<? super T> sort) {
        if (list.size() > 1) {
            Collections.sort(list, sort);
        }
        return list;
    }

    private static <T> IndexOutOfBoundsException newIndexOutOfBounds(List<T> list, int index) {
        return new IndexOutOfBoundsException("Index: " + index + ", Size: " + list.size());
    }
}