Collections.singletonList() 源码与用法

Collections.singletonList() 源码与用法

方法注释: 

 /**
     * Returns an immutable list containing only the specified object.
     * The returned list is serializable.
     *
     * @param  <T> the class of the objects in the list
     * @param o the sole object to be stored in the returned list.
     * @return an immutable list containing only the specified object.
     * @since 1.3
     */

这个方法主要用于只有一个元素的优化,减少内存分配,无需分配额外的内存,可以从SingletonList内部类看得出来,由于只有一个element,因此可以做到内存分配最小化,相比之下ArrayList的DEFAULT_CAPACITY=10个。

//SingletonList类的源码
    private static class SingletonList<E>
        extends AbstractList<E>
        implements RandomAccess, Serializable {

        private static final long serialVersionUID = 3093736618740652951L;

        private final E element;

        SingletonList(E obj)                {element = obj;}

        public Iterator<E> iterator() {
            return singletonIterator(element);
        }

        public int size()                   {return 1;}

        public boolean contains(Object obj) {return eq(obj, element);}

        public E get(int index) {
            if (index != 0)
              throw new IndexOutOfBoundsException("Index: "+index+", Size: 1");
            return element;
        }

        // Override default methods for Collection
        @Override
        public void forEach(Consumer<? super E> action) {
            action.accept(element);
        }
        @Override
        public boolean removeIf(Predicate<? super E> filter) {
            throw new UnsupportedOperationException();
        }
        @Override
        public void replaceAll(UnaryOperator<E> operator) {
            throw new UnsupportedOperationException();
        }
        @Override
        public void sort(Comparator<? super E> c) {
        }
        @Override
        public Spliterator<E> spliterator() {
            return singletonSpliterator(element);
        }
    }
//普通写法
    List<MyBean> beans= MyService.getInstance().queryBean(param);
    if (CollectionUtils.isEmpty(beans)) {
      beans= new ArrayList<>();
      MyBean bean= new MyBean(param);
      beans.add(bean);
    }
//优化写法
    List<MyBean> beans= MyService.getInstance().queryBean(param);
    if (CollectionUtils.isEmpty(beans)) {
      MyBean bean= new MyBean(param);
      beans= Collections.singletonList(bean);
    }

其他特殊容器类

public static <T> Set<T> singleton(T o);

public static <T> List<T> singletonList(T o);

public static <K,V> Map<K,V> singletonMap(K key, V value);
 
// 或者直接调用常量 EMPTY_LIST
public static final <T> List<T> emptyList();

//或者直接调用常量 EMPTY_MAP
public static final <K,V> Map<K,V> emptyMap();

//或者直接调用常量 EMPTY_SET
public static final <T> Set<T> emptySet()

需要注意的是,以上6个方法返回的容器类均是immutable,即只读的,如果调用修改接口,将会抛出UnsupportedOperationException

### Java 动态加载并编译外部 Java 源文件的方法 Java 提供了一套标准 API 来支持动态编译和加载外部源代码。以下是关于如何实现这一功能的具体说明。 #### 使用 `javax.tools.JavaCompiler` 进行动态编译 Java SE 自带的工具包提供了 `javax.tools.JavaCompiler` 接口,用于在运行时编译 `.java` 文件。该接口允许开发者指定输入源文件路径以及目标字节码输出位置[^1]。 下面是一个完整的示例程序: ```java import javax.tools.*; import java.io.File; import java.net.URL; import java.net.URLClassLoader; public class DynamicCompileAndLoad { public static void main(String[] args) throws Exception { // 定义要编译的源文件路径 File sourceFile = new File("Dog.java"); // 创建 Java 编译器实例 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // 准备诊断收集器来捕获错误消息 DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); // 配置编译选项 StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(java.util.Collections.singletonList(sourceFile)); // 执行编译操作 boolean success = compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits).call(); fileManager.close(); if (!success) { for (Diagnostic<?> diagnostic : diagnostics.getDiagnostics()) { System.err.format("Error on line %d in %s%n", diagnostic.getLineNumber(), diagnostic.getSource().toUri()); } throw new RuntimeException("Compilation failed"); } // 加载已编译的类 URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{new File(".").toURI().toURL()}); Class<?> clazz = classLoader.loadClass("Dog"); // 实例化并调用方法 Object instance = clazz.getDeclaredConstructor().newInstance(); clazz.getMethod("cry").invoke(instance); classLoader.close(); } } ``` 上述代码实现了以下几个核心步骤: 1. **定义源文件**:指定了待编译的 `.java` 文件路径。 2. **获取编译器实例**:通过 `ToolProvider.getSystemJavaCompiler()` 获得当前 JVM 的默认编译器。 3. **配置管理器**:使用 `StandardJavaFileManager` 处理文件读取写入。 4. **执行编译任务**:调用 `compiler.getTask(...)` 并传递必要的参数以启动编译过程。 5. **处理编译结果**:如果编译失败,则打印详细的错误日志;否则继续下一步骤。 6. **动态加载类**:利用自定义的 `URLClassLoader` 将生成的字节码加载到内存中。 7. **反射调用方法**:借助反射机制创建对象并调用其成员函数[^2]。 #### 注意事项 - 确保运行环境具备访问 JDK 工具的能力(即存在有效的 `javac` 可执行命令)。仅安装 JRE 是不够的。 - 如果需要跨平台兼容性或者更复杂的构建逻辑,建议考虑集成第三方库如 Apache Ant 或 Maven Embedder。 - 对于大规模项目而言,频繁地重新编译可能带来性能开销,在实际应用中应谨慎评估利弊。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值