服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服务器之家 - 编程语言 - JAVA教程 - Java接口中尽量避免使用数组

Java接口中尽量避免使用数组

2019-12-25 13:44goldensun JAVA教程

这篇文章主要介绍了Java接口中尽量避免使用数组的建议,根据实际示例展示了接口中使用数组而造成的影响程序速度的现象,需要的朋友可以参考下

 如果你发现在一个接口使用有如下定义方法:
 

?
1
public String[] getParameters();

那么你应该认真反思。数组不仅仅老式,而且我们有合理的理由避免暴露它们。在这篇文章中,我将试图总结在Java API中使用数组的缺陷。首先从最出人意料的一个例子开始。
数组导致性能不佳

你可能认为使用数组是最快速的,因为数组是大多数collection实现的底层数据结构。使用一个纯数组怎么会比使用一个包含数组的对象性能更低?


让我们先从这个看起来很熟悉的普遍的习惯用法开始:
 

?
1
2
3
public String[] getNames() {
 return namesList.toArray( new String[ namesList.size() ] );
}

这个方法从一个用来在其内部保存数据的可变集合处创建了一个数据. 它通过提供一个确切大小的数组来尝试优化数组的创建. 有趣的是,这一“优化”使得其比下面的更简单的版本速度还要慢(请看图表中绿色VS橘色条):
 

?
1
2
3
public String[] getNames() {
 return namesList.toArray( new String[ 0 ] );
}

不过,如果方法返回的是一个List, 创建防御式的副本又更加的快了 (红条):
 

?
1
2
3
public List<String> getNames() {
 return new ArrayList( namesList );
}

不同之处在于一个ArrayList将它的数据项放在一个Object[]数组中,并且使用的是无类型的toArray方法,其比有类型的方法要快很多(蓝条). 这是类型安全的,因为无类型的数组时封装在由编译器检查的泛型类型ArrayList<T>中的.

Java接口中尽量避免使用数组

这个图标展示了一个在Java 7上n=5的参考标准. 不过,更多的数据项或者是另外一个VM情况系啊,这幅图片并不会改变太多. CPU的开销可能并不会太剧烈,但是会有增长. 机会有一个数组的使用者应该将其转换到一个集合中去,以便利用它做任何事情, 然后将结果转换回一个数组,来送进另外一个接口的方法中,诸如此类做法.

是用一个简单的ArrayList,而不是一个数组来提升性能,无需再动太多的手脚. ArrayList 为封装的数组增加了32字节的恒定开销. 例如,一个有十个对象的数组需要104字节,一个ArrayList 136字节.

使用 集合,你甚至可能决定返回内部列表的一个不可修改的版本:
 

?
1
2
3
public List<String> getNames() {
 return Collections.unmodifiableList( namesList );
}

此操作会在固定的市价运行,因此他比任何上述其它的方法都要快很多(黄条). 其同一个防御式的拷贝不同。一个不可修改的集合将会在你的内部数据变化时跟着变化。如果变化发生了,客户端会在迭代数据项时运行到一个ConcurrentModificationException中. 可以认为它是一个糟糕的设计,接口提供了一个在运行时抛出一个UnsupportedOperationException. 不过,至少对于内部的使用,这个方法对于一个防御式的拷贝而言,会是一个高性能的选择 - 一些不可能使用数组实现的东西.

数组定义一个结构,而不是一个接口

Java 是一门面向对象的语言。面向对象的核心概念就是提供一些方法来访问和操作它们的数据,而不是直接对数据域进行操作. 这些方法创建一个接口来描述你可以在对象上面做的事情.

由于java已经对性能做了设计,原生类型和数组已经被融合进了类型系统之中. 对象可以使用数组来在内容高效地存储数据. 然而,即使通过数组来呈现一个可变集合的元素,它们也不会提供任何方法来访问和操作这些元素. 事实上,除了直接访问的替换元素之外,在数组上你没有多少其它事情可以做. 数组甚至连toString 和 equals 都没有一个有意义的实现, 而集合却有:
 

?
1
2
3
4
5
6
7
8
9
10
11
12
String[] array = { "foo", "bar" };
List<String> list = Arrays.asList( array );
 
System.out.println( list );
// -> [foo, bar]
System.out.println( array );
// -> [Ljava.lang.String;@6f548414
 
list.equals( Arrays.asList( "foo", "bar" ) )
// -> true
array.equals( new String[] { "foo", "bar" } )
// -> false

不同于数组,集合的 API 提供了许多有用的方法来访问元素. 用户可以检查包含的元素,提取子列表或者计算交集. 集合可以向数据层添加特定的特性, 诸如线程安全,同时将实现原理保持在内部可见.

通过使用一个数据,你定义了数据被保存在内存中的哪个地方. 通过使用一个集合,你定义了用户可以在数据上做的操作.

数组不是类型安全的

如果你依赖于编译器检查的类型安全,小心对象数组. 下面的代码会在运行时奔溃,但是编译器找不出问题所在:

?
1
2
Number[] numbers = new Integer[10];
numbers[0] = Long.valueOf( 0 ); // throws ArrayStoreException

原因是数组是“协变式”的, 比如,如果 T 是S 的一个子类型, 那么 T[] 就会是 S[] 的一个子类型. Joshua Bloch 在其著作 Effective Java 涵盖了所有的理论, 每一个Java开发者必读.

归因于这个行为,暴露数组类型的接口允许返回声明数组类型的一个子类型, 导致了一个怪异的运行时异常.


Bloch 同时也解释说,数组与泛型类型不兼容. 因为数组会在运行时强制要求有类型信息,而泛型则会在编译时被检查,泛型类型不能被放到数组中.

  •     一般而言,数组和泛型不能很好的融合。如果你发现自己在融合它们而得到了一个编译时错误或者警告,那你的第一反应应该是用list去替换数组.

- Joshua Bloch, Effective Java (第二版), 第29条
总结

数组底层的语言构造、它们会被用在实现中,但是它们不应该想其它的类暴露. 在一个接口方法中使用数组违背了面向对象的原则,它会导致违和的API,并且它也可能给类型安全和性能造成短板.

延伸 · 阅读

精彩推荐
  • JAVA教程Java中BigDecimal类的简单用法

    Java中BigDecimal类的简单用法

    这篇文章主要介绍了Java中BigDecimal类的简单用法,是Java应用程序开发中非常实用的技巧,本文以实例形式对此进行了简单的分析,需要的朋友可以参考下 ...

    shichen20141462019-11-29
  • JAVA教程Scala 操作Redis使用连接池工具类RedisUtil

    Scala 操作Redis使用连接池工具类RedisUtil

    这篇文章主要介绍了Scala 操作Redis使用连接池工具类RedisUtil,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    Gavin-Feng6672019-06-29
  • JAVA教程Java开发者结合Node.js编程入门教程

    Java开发者结合Node.js编程入门教程

    这篇文章主要介绍了Java开发者结合Node.js编程入门教程,我将先向您展示如何使用Java EE创建一个简单的Rest服务来读取 MongoDB数据库。然后我会用node.js来实现...

    java教程网4872019-11-28
  • JAVA教程Jar打包用法详解

    Jar打包用法详解

    这篇文章主要介绍了Jar打包用法,详解分析了jar打包命令的各种常见用法及参数含义,非常具有实用价值,需要的朋友可以参考下 ...

    shichen20142452019-12-06
  • JAVA教程java实现系统托盘示例

    java实现系统托盘示例

    桌面的系统托盘即当程序最小化或者关闭按钮程序并没有退出,而是最小化在任务状态区域,下面是使用java实现系统托盘示例 ...

    java教程网1392019-11-13
  • JAVA教程java实现计算周期性提醒的示例

    java实现计算周期性提醒的示例

    本文分享一个java实现计算周期性提醒的示例,可以计算父亲节、母亲节这样的节日,也可以定义如每月最好一个周五,以方便安排会议 ...

    Java教程网1262019-11-18
  • JAVA教程java中vector与hashtable操作实例分享

    java中vector与hashtable操作实例分享

    java中vector与hashtable操作实例,有需要的朋友可以参考一下 ...

    java教程网4032019-11-03
  • JAVA教程Servlet 过滤器详细介绍

    Servlet 过滤器详细介绍

    这篇文章介绍了Servlet 过滤器,有需要的朋友可以参考一下 ...

    java技术网4772019-10-17