Tag Archives: API

[repost ]Chrome JavaScript APIs

original:https://developer.chrome.com/apps/api_index

Chrome provides apps with many special-purpose APIs like chrome.runtime andchrome.alarms.

Name Description Since
accessibilityFeatures Use the chrome.accessibilityFeaturesAPI to manage Chrome’s accessibility features. This API relies on theChromeSetting prototype of the type APIfor getting and setting individual accessibility features. In order to get feature states the extension must requestaccessibilityFeatures.readpermission. For modifying feature state, the extension needsaccessibilityFeatures.modifypermission. Note thataccessibilityFeatures.modify does not imply accessibilityFeatures.readpermission. 37
alarms Use the chrome.alarms API to schedule code to run periodically or at a specified time in the future. 22
app.runtime Use the chrome.app.runtime API to manage the app lifecycle. The app runtime manages app installation, controls the event page, and can shut down the app at anytime. 23
app.window Use the chrome.app.window API to create windows. Windows have an optional frame with title bar and size controls. They are not associated with any Chrome browser windows. See the Window State Sample for a demonstration of these options. 23
bluetooth Use the chrome.bluetooth API to connect to a Bluetooth device. All functions report failures via chrome.runtime.lastError. 37
bluetoothLowEnergy The chrome.bluetoothLowEnergy API is used to communicate with Bluetooth Smart (Low Energy) devices using the Generic Attribute Profile (GATT). 37
bluetoothSocket Use the chrome.bluetoothSocket API to send and receive data to Bluetooth devices using RFCOMM and L2CAP connections. 37
commands Use the commands API to add keyboard shortcuts that trigger actions in your extension, for example, an action to open the browser action or send a command to the extension. 35
contextMenus Use the chrome.contextMenus API to add items to Google Chrome’s context menu. You can choose what types of objects your context menu additions apply to, such as images, hyperlinks, and pages. 6
events The chrome.events namespace contains common types used by APIs dispatching events to notify you when something interesting happens. 21
fileSystem Use the chrome.fileSystem API to create, read, navigate, and write to the user’s local file system. With this API, Chrome Apps can read and write to a user-selected location. For example, a text editor app can use the API to read and write local documents. All failures are notified via chrome.runtime.lastError. 23
gcm Use chrome.gcm to enable apps and extensions to send and receive messages through the Google Cloud Messaging Service. 35
hid Use the chrome.hid API to interact with connected HID devices. This API provides access to HID operations from within the context of an app. Using this API, apps can function as drivers for hardware devices. Errors generated by this API are reported by setting runtime.lastError and executing the function’s regular callback. The callback’s regular parameters will be undefined in this case. 38
i18n Use the chrome.i18n infrastructure to implement internationalization across your whole app or extension. 5
identity Use the chrome.identity API to get OAuth2 access tokens. 29
idle Use the chrome.idle API to detect when the machine’s idle state changes. 6
mediaGalleries Use the chrome.mediaGalleries API to access media files (audio, images, video) from the user’s local disks (with the user’s consent). 23
notifications Use the chrome.notifications API to create rich notifications using templates and show these notifications to users in the system tray. 28
permissions Use the chrome.permissions API to request declared optional permissions at run time rather than install time, so users understand why the permissions are needed and grant only those that are necessary. 16
power Use the chrome.power API to override the system’s power management features. 27
pushMessaging The chrome.pushMessaging API is deprecated since Chrome 38, and will no longer be supported in Chrome 41. Switch tochrome.gcm to take advantage of Google Cloud Messaging. 24
runtime Use the chrome.runtime API to retrieve the background page, return details about the manifest, and listen for and respond to events in the app or extension lifecycle. You can also use this API to convert the relative path of URLs to fully-qualified URLs. 22
serial Use the chrome.serial API to read from and write to a device connected to a serial port. 23
socket Use the chrome.socket API to send and receive data over the network using TCP and UDP connections. Note: Starting with Chrome 33, this API is deprecated in favor of the sockets.udp, sockets.tcp andsockets.tcpServer APIs. 24
sockets.tcp Use the chrome.sockets.tcp API to send and receive data over the network using TCP connections. This API supersedes the TCP functionality previously found in thechrome.socket API. 33
sockets.tcpServer Use the chrome.sockets.tcpServer API to create server applications using TCP connections. This API supersedes the TCP functionality previously found in thechrome.socket API. 33
sockets.udp Use the chrome.sockets.udp API to send and receive data over the network using UDP connections. This API supersedes the UDP functionality previously found in the “socket” API. 33
storage Use the chrome.storage API to store, retrieve, and track changes to user data. 20
syncFileSystem Use the chrome.syncFileSystem API to save and synchronize data on Google Drive. This API is NOT for accessing arbitrary user docs stored in Google Drive. It provides app-specific syncable storage for offline and caching usage so that the same data can be available across different clients. ReadManage Data for more on using this API. 27
system.cpu Use the system.cpu API to query CPU metadata. 32
system.display Use the system.display API to query display metadata. 30
system.memory The chrome.system.memory API. 32
system.network Use the chrome.system.network API. 33
system.storage Use the chrome.system.storage API to query storage device information and be notified when a removable storage device is attached and detached. 30
tts Use the chrome.tts API to play synthesized text-to-speech (TTS). See also the relatedttsEngine API, which allows an extension to implement a speech engine. 14
types The chrome.types API contains type declarations for Chrome. 13
usb Use the chrome.usb API to interact with connected USB devices. This API provides access to USB operations from within the context of an app. Using this API, apps can function as drivers for hardware devices. Errors generated by this API are reported by setting runtime.lastError and executing the function’s regular callback. The callback’s regular parameters will be undefined in this case. 26

These APIs are only available in the Chrome Beta and Dev channels:

Name Description
extensionTypes The chrome.extensionTypes API contains type declarations for Chrome extensions.

These APIs are only available in the Chrome Dev channel:

Name Description
audio The chrome.audio API is provided to allow users to get information about and control the audio devices attached to the system. This API is currently only implemented for ChromeOS.
copresence Use the chrome.copresence API to communicate with other nearby devices using Google’s copresence service.
copresenceSocket Use the chrome.copresenceSocket API to create persistent sockets to send data to and receive from data nearby devices.
fileSystemProvider Use the chrome.fileSystemProvider API to create file systems, that can be accessible from the file manager on Chrome OS.
location Use the chrome.location API to retrieve the geographic location of the host machine. This API is a version of theHTML Geolocation API that is compatible with event pages.
wallpaper Use the chrome.wallpaper API to change the ChromeOS wallpaper.

Chrome also has experimental APIs, some of which will become supported APIs in future releases of Chrome.

Unless the doc says otherwise, methods in the chrome.* APIs are asynchronous: they return immediately, without waiting for the operation to finish. If you need to know the outcome of an operation, then you pass a callback function into the method. For more information, watch this video:

[repost ]从 Java 代码到 Java 堆:理解和优化您的应用程序的内存使用

original:https://www.ibm.com/developerworks/cn/java/j-codetoheap/

简介: 本文将为您提供 Java™ 代码内存使用情况的深入见解,包括将 int 值置入一个Integer 对象的内存开销、对象委托的成本和不同集合类型的内存效率。您将了解到如何确定应用程序中的哪些位置效率低下,以及如何选择正确的集合来改进您的代码。

优化应用程序代码的内存使用并不是一个新主题,但是人们通常并没有很好地理解这个主题。本文将简要介绍 Java 进程的内存使用,随后深入探讨您编写的 Java 代码的内存使用。最后,本文将展示提高代码内存效率的方法,特别强调了 HashMap 和 ArrayList等 Java 集合的使用。

背景信息:Java 进程的内存使用

参考知识

如需进一步了解 Java 应用程序的进程内存使用,请参阅 Andrew Hall 撰写的 developerWorks 文章 “内存详解”。这篇文章介绍了 内存详解 以及 AIX® 提供的布局和用户空间,以及 Java 堆和本机堆之间的交互。

通过在命令行中执行 java 或者启动某种基于 Java 的中间件来运行 Java 应用程序时,Java 运行时会创建一个操作系统进程,就像您运行基于 C 的程序时那样。实际上,大多数 JVM 都是用 C 或者 C++ 语言编写的。作为操作系统进程,Java 运行时面临着与其他进程完全相同的内存限制:架构提供的寻址能力以及操作系统提供的用户空间。

架构提供的内存寻址能力依赖于处理器的位数,举例来说,32 位或者 64 位,对于大型机来说,还有 31 位。进程能够处理的位数决定了处理器能寻址的内存范围:32 位提供了 2^32 的可寻址范围,也就是 4,294,967,296 位,或者说 4GB。而 64 位处理器的可寻址范围明显增大:2^64,也就是 18,446,744,073,709,551,616,或者说 16 exabyte(百亿亿字节)。

处理器架构提供的部分可寻址范围由 OS 本身占用,提供给操作系统内核以及 C 运行时(对于使用 C 或者 C++ 编写的 JVM 而言)。OS 和 C 运行时占用的内存数量取决于所用的 OS,但通常数量较大:Windows 默认占用的内存是 2GB。剩余的可寻址空间(用术语来表示就是用户空间)就是可供运行的实际进程使用的内存。

对于 Java 应用程序,用户空间是 Java 进程占用的内存,实际上包含两个池:Java 堆和本机(非 Java)堆。Java 堆的大小由 JVM 的 Java 堆设置控制:-Xms 和 -Xmx 分别设置最小和最大 Java 堆。在按照最大的大小设置分配了 Java 堆之后,剩下的用户空间就是本机堆。图 1 展示了一个 32 位 Java 进程的内存布局:
图 1. 一个 32 位 Java 进程的内存布局示例
一个 32 位 Java 进程的内存布局示例视图

在 图 1 中,可寻址范围总共有 4GB,OS 和 C 运行时大约占用了其中的 1GB,Java 堆占用了将近 2GB,本机堆占用了其他部分。请注意,JVM 本身也要占用内存,就像 OS 内核和 C 运行时一样,而 JVB 占用的内存是本机堆的子集。

回页首

Java 对象详解

在您的 Java 代码使用 new 操作符创建一个 Java 对象的实例时,实际上分配的数据要比您想的多得多。例如,一个 int 值与一个Integer 对象(能包含 int 值的最小对象)的大小比率是 1:4,这个比率可能会让您感到吃惊。额外的开销源于 JVM 用于描述 Java 对象的元数据,在本例中也就是 Integer

根据 JVM 的版本和供应的不同,对象元数据的数量也各有不同,但其中通常包括:

  • :一个指向类信息的指针,描述了对象类型。举例来说,对于 java.lang.Integer 对象,这是 java.lang.Integer 类的一个指针。
  • 标记:一组标记,描述了对象的状态,包括对象的散列码(如果有),以及对象的形状(也就是说,对象是否是数组)。
  • :对象的同步信息,也就是说,对象目前是否正在同步。

对象元数据后紧跟着对象数据本身,包括对象实例中存储的字段。对于 java.lang.Integer 对象,这就是一个 int

如果您正在运行一个 32 位 JVM,那么在创建 java.lang.Integer 对象实例时,对象的布局可能如图 2 所示:
图 2. 一个 32 位 Java 进程的 java.lang.Integer 对象的布局示例
一个 32 位 Java 进程的 java.lang.Integer 对象的布局示例

如 图 2 所示,有 128 位的数据用于存储 int 值内的 32 位数据,而对象元数据占用了其余 128 位。

回页首

Java 数组对象详解

数组对象(例如一个 int 值数组)的形状和结构与标准 Java 对象相似。主要差别在于数组对象包含说明数组大小的额外元数据。因此,数据对象的元数据包括:

  • :一个指向类信息的指针,描述了对象类型。举例来说,对于 int 字段数组,这是 int[] 类的一个指针。
  • 标记:一组标记,描述了对象的状态,包括对象的散列码(如果有),以及对象的形状(也就是说,对象是否是数组)。
  • :对象的同步信息,也就是说,对象目前是否正在同步。
  • 大小:数组的大小。

图 3 展示了一个 int 数组对象的布局示例:
图 3. 一个 32 位 Java 进程的 int 数组对象的布局示例
一个 32 位进程的 int 数组对象的布局示例

如 图 3 所示,有 160 位的数据用于存储 int 值内的 32 位数据,而数组元数据占用了其余 160 位。对于 byteint 和 long 等原语,从内存的方面考虑,单项数组比对应的针对单一字段的包装器对象(ByteInteger 或 Long)的成本更高。

回页首

更为复杂数据结构详解

良好的面向对象设计与编程鼓励使用封装(提供接口类来控制数据访问)和委托(使用 helper 对象来实施任务)。封装和委托会使大多数数据结构的表示形式中包含多个对象。一个简单的示例就是 java.lang.String 对象。java.lang.String 对象中的数据是一个字符数组,由管理和控制对字符数组的访问的 java.lang.String 对象封装。图 4 展示了一个 32 位 Java 进程的java.lang.String 对象的布局示例:
图 4. 一个 32 位 Java 进程的 java.lang.String 对象的布局示例
一个 32 位 Java 进程的 java.lang.String 对象的布局示例

如 图 4 所示,除了标准对象元数据之外,java.lang.String 对象还包含一些用于管理字符串数据的字段。通常情况下,这些字段是散列值、字符串大小计数、字符串数据偏移量和对于字符数组本身的对象引用。

这也就意味着,对于一个 8 个字符的字符串(128 位的 char 数据),需要有 256 位的数据用于字符数组,224 位的数据用于管理该数组的 java.lang.String 对象,因此为了表示 128 位(16 个字节)的数据,总共需要占用 480 位(60 字节)。开销比例为 3.75:1。

总体而言,数据结构越是复杂,开销就越高。下一节将具体讨论相关内容。

回页首

32 位和 64 位 Java 对象

之前的示例中的对象大小和开销适用于 32 位 Java 进程。在 背景信息:Java 进程的内存使用 一节中提到,64 位处理器的内存可寻址能力比 32 位处理器高得多。对于 64 位进程,Java 对象中的某些数据字段的大小(特别是对象元数据或者表示另一个对象的任何字段)也需要增加到 64 位。其他数据字段类型(例如 intbyte 和 long )的大小不会更改。图 5 展示了一个 64 位 Integer 对象和一个 int 数组的布局:
图 5. 一个 64 位进程的 java.lang.Integer 对象和 int 数组的布局示例
一个 64 位 Java 进程的 java.lang.Integer 对象和 int 数组的布局示例

图 5 表明,对于一个 64 位 Integer 对象,现在有 224 位的数据用于存储 int 字段所用的 32 位,开销比例是 7:1。对于一个 64 位单元素 int 数组,有 288 位的数据用于存储 32 位 int 条目,开销比例是 9:1。这在实际应用程序中产生的影响在于,之前在 32 位 Java 运行时中运行的应用程序若迁移到 64 位 Java 运行时,其 Java 堆内存使用量会显著增加。通常情况下,增加的数量是原始堆大小的 70% 左右。举例来说,一个在 32 位 Java 运行时中使用 1GB Java 堆的 Java 应用程序在迁移到 64 位 Java 运行时之后,通常需要使用 1.7GB 的 Java 堆。

请注意,这种内存增加并非仅限于 Java 堆。本机堆内存区使用量也会增加,有时甚至要增加 90% 之多。

表 1 展示了一个应用程序在 32 位和 64 位模式下运行时的对象和数组字段大小:
表 1. 32 位和 64 位 Java 运行时的对象中的字段大小

字段类型 字段大小(位)
对象 数组
32 位 64 位 32 位 64 位
boolean 32 32 8 8
byte 32 32 8 8
char 32 32 16 16
short 32 32 16 16
int 32 32 32 32
float 32 32 32 32
long 32 32 64 64
double 32 32 64 64
对象字段 32 64 (32*) 32 64 (32*)
对象元数据 32 64 (32*) 32 64 (32*)

* 对象字段的大小以及用于各对象元数据条目的数据的大小可通过 压缩引用或压缩 OOP 技术减小到 32 位。

压缩引用和压缩普通对象指针 (OOP)

IBM 和 Oracle JVM 分别通过压缩引用 (-Xcompressedrefs) 和压缩 OOP (-XX:+UseCompressedOops) 选项提供对象引用压缩功能。利用这些选项,即可在 32 位(而非 64 位)中存储对象字段和对象元数据值。在应用程序从 32 位 Java 运行时迁移到 64 位 Java 运行时的时候,这能消除 Java 堆内存使用量增加 70% 的负面影响。请注意,这些选项对于本机堆的内存使用无效,本机堆在 64 位 Java 运行时中的内存使用量仍然比 32 位 Java 运行时中的使用量高得多。

回页首

Java 集合的内存使用

在大多数应用程序中,大量数据都是使用核心 Java API 提供的标准 Java Collections 类来存储和管理的。如果内存占用对于您的应用程序极为重要,那么就非常有必要了解各集合提供的功能以及相关的内存开销。总体而言,集合功能的级别越高,内存开销就越高,因此使用提供的功能多于您需要的功能的集合类型会带来不必要的额外内存开销。

其中部分最常用的集合如下:

除了 HashSet 之外,此列表是按功能和内存开销进行降序排列的。(HashSet 是包围一个 HashMap 对象的包装器,它提供的功能比HashMap 少,同时容量稍微小一些。)

Java 集合:HashSet

HashSet 是 Set 接口的实现。Java Platform SE 6 API 文档对于 HashSet 的描述如下:

一个不包含重复元素的集合。更正式地来说,set(集)不包含元素 e1 和 e2 的配对 e1.equals(e2),而且至多包含一个空元素。正如其名称所表示的那样,这个接口将建模数学集抽象。

HashSet 包含的功能比 HashMap 要少,只能包含一个空条目,而且无法包含重复条目。该实现是包围 HashMap 的一个包装器,以及管理可在 HashMap 对象中存放哪些内容的 HashSet 对象。限制 HashMap 功能的附加功能表示 HashSet 的内存开销略高。

图 6 展示了 32 位 Java 运行时中的一个 HashSet 的布局和内存使用:
图 6. 32 位 Java 运行时中的一个 HashSet 的内存使用和布局
32 位 Java 运行时中的一个 HashSet 的内存使用和布局

图 6 展示了一个 java.util.HashSet 对象的 shallow 堆(独立对象的内存使用)以及保留堆(独立对象及其子对象的内存使用),以字节为单位。shallow 堆的大小是 16 字节,保留堆的大小是 144 字节。创建一个 HashSet 时,其默认容量(也就是该集中可以容纳的条目数量)将设置为 16 个条目。按照默认容量创建 HashSet,而且未在该集中输入任何条目时,它将占用 144 个字节。与HashMap 的内存使用相比,超出了 16 个字节。表 2 显示了 HashSet 的属性:
表 2. 一个 HashSet 的属性

默认容量 16 个条目
空时的大小 144 个字节
开销 16 字节加 HashMap 开销
一个 10K 集合的开销 16 字节加 HashMap 开销
搜索/插入/删除性能 O(1):所用时间是一个常量时间,无论要素数量如何都是如此(假设无散列冲突)

 

Java 集合:HashMap

HashMap 是 Map 接口的实现。Java Platform SE 6 API 文档对于 HashMap 的描述如下:

一个将键映射到值的对象。一个映射中不能包含重复的键;每个键仅可映射到至多一个值。

HashMap 提供了一种存储键/值对的方法,使用散列函数将键转换为存储键/值对的集合中的索引。这允许快速访问数据位置。允许存在空条目和重复条目;因此,HashMap 是 HashSet 的简化版。

HashMap 将实现为一个 HashMap$Entry 对象数组。图 7 展示了 32 位 Java 运行时中的一个 HashMap 的内存使用和布局:
图 7. 32 位 Java 运行时中的一个 HashMap 的内存使用和布局
32 位 Java 运行时中的一个 HashMap 的内存使用和布局

如 图 7 所示,创建一个 HashMap 时,结果是一个 HashMap 对象以及一个采用 16 个条目的默认容量的 HashMap$Entry 对象数组。这提供了一个 HashMap,在完全为空时,其大小是 128 字节。插入 HashMap 的任何键/值对都将包含于一个 HashMap$Entry 对象之中,该对象本身也有一定的开销。

大多数 HashMap$Entry 对象实现都包含以下字段:

  • int KeyHash
  • Object next
  • Object key
  • Object value

一个 32 字节的 HashMap$Entry 对象用于管理插入集合的数据键/值对。这就意味着,一个 HashMap 的总开销包含 HashMap 对象、一个HashMap$Entry 数组条目和与各条目对应的 HashMap$Entry 对象的开销。可通过以下公式表示:

HashMap 对象 + 数组对象开销 + (条目数量 * (HashMap$Entry 数组条目 + HashMap$Entry 对象))

对于一个包含 10,000 个条目的 HashMap 来说,仅仅 HashMapHashMap$Entry 数组和 HashMap$Entry 对象的开销就在 360K 左右。这还没有考虑所存储的键和值的大小。

表 3 展示了 HashMap 的属性:
表 3. 一个 HashMap 的属性

默认容量 16 个条目
空时的大小 128 个字节
开销 64 字节加上每个条目 36 字节
一个 10K 集合的开销 ~360K
搜索/插入/删除性能 O(1):所用时间是一个常量时间,无论要素数量如何都是如此(假设无散列冲突)

 

Java 集合:Hashtable

Hashtable 与 HashMap 相似,也是 Map 接口的实现。Java Platform SE 6 API 文档对于 Hashtable 的描述如下:

这个类实现了一个散列表,用于将键映射到值。对于非空对象,可以将它用作键,也可以将它用作值。

Hashtable 与 HashMap 极其相似,但有两项限制。无论是键还是值条目,它均不接受空值,而且它是一个同步集合。相比之下,HashMap 可以接受空值,且不是同步的,但可以利用 Collections.synchronizedMap() 方法来实现同步。

Hashtable 的实现同样类似于 HashMap,也是条目对象的数组,在本例中即 Hashtable$Entry 对象。图 8 展示了 32 位 Java 运行时中的一个 Hashtable 的内存使用和布局:
图 8. 32 位 Java 运行时中的一个 Hashtable 的内存使用和布局
32 位 Java 运行时中的一个 Hashtable 的内存使用和布局

图 8 显示,创建一个 Hashtable 时,结果会是一个占用了 40 字节的内存的 Hashtable 对象,另有一个默认容量为 11 个条目的Hashtable$entry 数组,在 Hashtable 为空时,总大小为 104 字节。

Hashtable$Entry 存储的数据实际上与 HashMap 相同:

  • int KeyHash
  • Object next
  • Object key
  • Object value

这意味着,对于 Hashtable 中的键/值条目,Hashtable$Entry 对象也是 32 字节,而 Hashtable 开销的计算和 10K 个条目的集合的大小(约为 360K)与 HashMap 类似。

表 4 显示了 Hashtable 的属性:
表 4. 一个 Hashtable 的属性

默认容量 11 个条目
空时的大小 104 个字节
开销 56 字节加上每个条目 36 字节
一个 10K 集合的开销 ~360K
搜索/插入/删除性能 O(1):所用时间是一个常量时间,无论要素数量如何都是如此(假设无散列冲突)

 

如您所见,Hashtable 的默认容量比 HashMap 要稍微小一些(分别是 11 与 16)。除此之外,两者之间的主要差别在于 Hashtable 无法接受空键和空值,而且是默认同步的,但这可能是不必要的,还有可能降低集合的性能。

Java 集合:LinkedList

LinkedList 是 List 接口的链表实现。Java Platform SE 6 API 文档对于 LinkedList 的描述如下:

一种有序集合(也称为序列)。此接口的用户可以精确控制将各元素插入列表时的位置。用户可以按照整数索引(代表在列表中的位置)来访问元素,也可以搜索列表中的元素。与其他集合 (set) 不同,该集合 (collection) 通常允许存在重复的元素。

实现是 LinkedList$Entry 对象链表。图 9 展示了 32 位 Java 运行时中的 LinkedList 的内存使用和布局:
图 9. 32 位 Java 运行时中的一个 LinkedList 的内存使用和布局
32 位 Java 运行时中的一个 LinkedList 的内存使用和布局

图 9 表明,创建一个 LinkedList 时,结果将得到一个占用 24 字节内存的 LinkedList 对象以及一个 LinkedList$Entry 对象,在LinkedList 为空时,总共占用的内存是 48 个字节。

链表的优势之一就是能够准确调整其大小,且无需重新调整。默认容量实际上就是一个条目,能够在添加或删除条目时动态扩大或缩小。每个 LinkedList$Entry 对象仍然有自己的开销,其数据字段如下:

  • Object previous
  • Object next
  • Object value

但这比 HashMap 和 Hashtable 的开销低,因为链表仅存储单独一个条目,而非键/值对,由于不会使用基于数组的查找,因此不需要存储散列值。从负面角度来看,在链表中查找的速度要慢得多,因为链表必须依次遍历才能找到需要查找的正确条目。对于较大的链表,结果可能导致漫长的查找时间。

表 5 显示了 LinkedList 的属性:
表 5. 一个 LinkedList 的属性

默认容量 1 个条目
空时的大小 48 个字节
开销 24 字节加上每个条目 24 字节
一个 10K 集合的开销 ~240K
搜索/插入/删除性能 O(n):所用时间与元素数量线性相关。

 

Java 集合:ArrayList

ArrayList 是 List 接口的可变长数组实现。Java Platform SE 6 API 文档对于 ArrayList 的描述如下:

一种有序集合(也称为序列)。此接口的用户可以精确控制将各元素插入列表时的位置。用户可以按照整数索引(代表在列表中的位置)来访问元素,也可以搜索列表中的元素。与其他集合 (set) 不同,该集合 (collection) 通常允许存在重复的元素。

不同于 LinkedListArrayList 是使用一个 Object 数组实现的。图 10 展示了一个 32 位 Java 运行时中的 ArrayList 的内存使用和布局:
图 10. 32 位 Java 运行时中的一个 ArrayList 的内存使用和布局
32 位 Java 运行时中的一个 ArrayList 的内存使用和布局

图 10 表明,在创建 ArrayList 时,结果将得到一个占用 32 字节内存的 ArrayList 对象,以及一个默认大小为 10 的 Object 数组,在 ArrayList 为空时,总计占用的内存是 88 字节。这意味着 ArrayList 无法准确调整大小,因此拥有一个默认容量,恰好是 10 个条目。

表 6 展示了一个 ArrayList 的属性:
表 6. 一个 ArrayList 的属性

默认容量 10
空时的大小 88 个字节
开销 48 字节加上每个条目 4 字节
一个 10K 集合的开销 ~40K
搜索/插入/删除性能 O(n):所用时间与元素数量线性相关

 

其他类型的 “集合”

除了标准集合之外,StringBuffer 也可以视为集合,因为它管理字符数据,而且在结构和功能上与其他集合相似。Java Platform SE 6 API 文档对于 StringBuffer 的描述如下:

线程安全、可变的字符序列……每个字符串缓冲区都有相应的容量。只要字符串缓冲区内包含的字符序列的长度不超过容量,就不必分配新的内部缓冲区数组。如果内部缓冲区溢出,则会自动为其扩大容量。

StringBuffer 是作为一个 char 数组来实现的。图 11 展示了一个 32 位 Java 运行时中的 StringBuffer 的内存使用和布局:
图 11. 32 位 Java 运行时中的一个 StringBuffer 的内存使用和布局
32 位 Java 运行时中的一个 StringBuffer 的内存使用和布局

图 11 展示,创建一个 StringBuffer 时,结果将得到一个占用 24 字节内存的 StringBuffer 对象,以及一个默认大小为 16 的字符数组,在 StringBuffer 为空时,数据总大小为 72 字节。

与集合相似,StringBuffer 拥有默认容量和重新调整大小的机制。表 7 显示了 StringBuffer 的属性:
表 7. 一个 StringBuffer 的属性

默认容量 16
空时的大小 72 个字节
开销 24 个字节
一个 10K 集合的开销 24 个字节
搜索/插入/删除性能 不适用

 

回页首

集合中的空白空间

拥有给定数量对象的各种集合的开销并不是内存开销的全部。前文的示例中的度量假设集合已经得到了准确的大小调整。然而,对于大多数集合来说,这种假设都是不成立的。大多数集合在创建时都指定给定的初始容量,数据将置入集合之中。这也就是说,集合拥有的容量往往大于集合中存储的数据容量,这造成了额外的开销。

考虑一个 StringBuffer 的示例。其默认容量是 16 个字符条目,大小为 72 字节。初始情况下,72 个字节中未存储任何数据。如果您在字符数组中存储了一些字符,例如 "MY STRING" ,那么也就是在 16 个字符的数组中存储了 9 个字符。图 12 展示了 32 位 Java 运行时中的一个包含 "MY STRING" 的 StringBuffer 的内存使用和布局:
图 12. 32 位 Java 运行时中的一个包含 "MY STRING" 的 StringBuffer 的内存使用
32 位运行时中的一个包含 'MY STRING' 的 StringBuffer 的内存使用

如 图 12 所示,数组中有 7 个可用的字符条目未被使用,但占用了内存,在本例中,这造成了 112 字节的额外开销。对于这个集合,您在 16 的容量中存储了 9 个条目,因而填充率 为 0.56。集合的填充率越低,因多余容量而造成的开销就越高。

回页首

集合的扩展和重新调整

在集合达到容量限制时,如果出现了在集合中存储额外条目的请求,那么会重新调整集合,并扩展它以容纳新条目。这将增加容量,但往往会降低填充比,造成更高的内存开销。

各集合所用的扩展算法各有不同,但一种通用的做法就是将集合的容量加倍。这也是 StringBuffer 采用的方法。对于前文示例中的StringBuffer,如果您希望将 " OF TEXT" 添加到缓冲区中,生成 "MY STRING OF TEXT",则需要扩展集合,因为新的字符集合拥有 17 个条目,当前容量 16 无法满足其要求。图 13 展示了所得到的内存使用:
图 13. 32 位 Java 运行时中的一个包含 "MY STRING OF TEXT" 的 StringBuffer 的内存使用
32 位运行时中的一个包含 'MY STRING OF TEXT' 的 StringBuffer 的内存使用

现在,如 图 13 所示,您得到了一个 32 个条目的字符数组,但仅仅使用了 17 个条目,填充率为 0.53。填充率并未显著下滑,但您现在需要为多余的容量付出 240 字节的开销。

对于小字符串和集合,低填充率和多余容量的开销可能并不会被视为严重问题,而在大小增加时,这样的问题就会愈加明显,代价也就愈加高昂。例如,如果您创建了一个 StringBuffer,其中仅包含 16MB 的数据,那么(在默认情况下)它将使用大小设置为可容纳 32MB 数据的字符数组,这造成了以多余容量形式存在的 16MB 的额外开销。

回页首

Java 集合:汇总

表 8 汇总了集合的属性:
表 8. 集合属性汇总

集合 性能 默认容量 空时的大小 10K 条目的开销 准确设置大小? 扩展算法
HashSet O(1) 16 144 360K x2
HashMap O(1) 16 128 360K x2
Hashtable O(1) 11 104 360K x2+1
LinkedList O(n) 1 48 240K +1
ArrayList O(n) 10 88 40K x1.5
StringBuffer O(1) 16 72 24 x2

 

Hash 集合的性能比任何 List 的性能都要高,但每条目的成本也要更高。由于访问性能方面的原因,如果您正在创建大集合(例如,用于实现缓存),那么最好使用基于 Hash 的集合,而不必考虑额外的开销。

对于并不那么注重访问性能的较小集合而言,List 则是合理的选择。ArrayList 和 LinkedList 集合的性能大体相同,但其内存占用完全不同:ArrayList 的每条目大小要比 LinkedList 小得多,但它不是准确设置大小的。List 要使用的正确实现是 ArrayList 还是LinkedList 取决于 List 长度的可预测性。如果长度未知,那么正确的选择可能是 LinkedList,因为集合包含的空白空间更少。如果大小已知,那么 ArrayList 的内存开销会更低一些。

选择正确的集合类型使您能够在集合性能与内存占用之间达到合理的平衡。除此之外,您可以通过正确调整集合大小来最大化填充率、最小化未得到利用的空间,从而最大限度地减少内存占用。

回页首

集合的实际应用:PlantsByWebSphere 和 WebSphere Application Server Version 7

在 表 8 中,创建一个包含 10,000 个条目、基于 Hash 的集合的开销是 360K。考虑到,复杂的 Java 应用程序常常使用大小为数 GB 的 Java 堆运行,因此这样的开销看起来并不是非常高,当然,除非使用了大量集合。

表 9 展示了在包含五个用户的负载测试中运行 WebSphere® Application Server Version 7 提供的 PlantsByWebSphere 样例应用程序时,Java 堆使用的 206MB 中的集合对象使用量:
表 9. WebSphere Application Server v7 中的 PlantsByWebSphere 的集合使用量

集合类型 实例数量 集合总开销 (MB)
Hashtable 262,234 26.5
WeakHashMap 19,562 12.6
HashMap 10,600 2.3
ArrayList 9,530 0.3
HashSet 1,551 1.0
Vector 1,271 0.04
LinkedList 1,148 0.1
TreeMap 299 0.03
总计 306,195 42.9

 

通过 表 9 可以看到,这里使用了超过 30 万个不同的集合,而且仅集合本身(不考虑其中包含的数据)就占用了 206MB 的 Java 堆用量中的 42.9MB(21%)。这就意味着,如果您能更改集合类型,或者确保集合的大小更加准确,那么就有可能实现可观的内存节约。

回页首

通过 Memory Analyzer 查找低填充率

IBM Java 监控和诊断工具(Memory Analyzer 工具是在 IBM Support Assistant 中提供的)可以分析 Java 集合的内存使用情况(请参阅 参考资料 部分)。其功能包括分析集合的填充率和大小。您可以使用这样的分析来识别需要优化的集合。

Memory Analyzer 中的集合分析位于 Open Query Browser -> Java Collections 菜单中,如图 14 所示:
图 14. 在 Memory Analyzer 中分析 Java 集合的填充率
在 Memory Analyzer 中分析 Java 集合的填充率

在判断当前大小超出需要的大小的集合时,图 14 中选择的 Collection Fill Ratio 查询是最有用的。您可以为该查询指定多种选项,这些选项包括:

  • 对象:您关注的对象类型(集合)
  • 分段:用于分组对象的填充率范围

将对象选项设置为 “java.util.Hashtable”、将分段选项设置为 “10”,之后运行查询将得到如图 15 所示的输出结果:
图 15. 在 Memory Analyzer 中对 Hashtable 的填充率分析
在 Memory Analyzer 中对 Hashtable 的分析

图 15 表明,在 java.util.Hashtable 的 262,234 个实例中,有 127,016 (48.4%) 的实例完全未空,几乎所有实例都仅包含少量条目。

随后便可识别这些集合,方法是选择结果表中的一行,右键单击并选择 list objects -> with incoming references,查看哪些对象拥有这些集合,或者选择 list objects -> with outgoing references,查看这些集合中包含哪些条目。图 16 展示了查看对于空Hashtable 的传入引用的结果,图中展开了一些条目:
图 16. 在 Memory Analyzer 中对于空 Hashtable 的传入引用的分析 
在 Memory Analyzer 中对于空 Hashtable 的传入引用的分析

图 16 表明,某些空 Hashtable 归 javax.management.remote.rmi.NoCallStackClassLoader 代码所有。

通过查看 Memory Analyzer 左侧面板中的 Attributes 视图,您就可以看到有关 Hashtable 本身的具体细节,如图 17 所示:
图 17. 在 Memory Analyzer 中检查空 Hashtable 
在 Memory Analyzer 中检查孔 Hashtable

图 17 表明,Hashtable 的大小为 11(默认大小),而且完全是空的。

对于 javax.management.remote.rmi.NoCallStackClassLoader 代码,可以通过以下方法来优化集合使用:

  • 延迟分配 Hashtable:如果 Hashtable 为空是经常发生的普遍现象,那么仅在存在需要存储的数据时分配 Hashtable 应该是一种合理的做法。
  • 将 Hashtable 分配为准确的大小:由于使用默认大小,因此完全可以使用更为准确的初始大小。

这些优化是否适用取决于代码的常用方式以及通常存储的是哪些数据。

PlantsByWebSphere 示例中的空集合

表 10 展示了分析 PlantsByWebSphere 示例中的集合来确定哪些集合为空时的分析结果:
表 10. WebSphere Application Server v7 中 PlantsByWebSphere 的空集合使用量

集合类型 实例数量 空实例 空实例百分比
Hashtable 262,234 127,016 48.4
WeakHashMap 19,562 19,465 99.5
HashMap 10,600 7,599 71.7
ArrayList 9,530 4,588 48.1
HashSet 1,551 866 55.8
Vector 1,271 622 48.9
总计 304,748 160,156 52.6

 

表 10 表明,平均而言,超过 50% 的集合为空,也就是说通过优化集合使用能够实现可观的内存占用节约。这种优化可以应用于应用程序的各个级别:应用于 PlantsByWebSphere 示例代码中、应用于 WebSphere Application Server 中,以及应用于 Java 集合类本身。

在 WebSphere Application Server 版本 7 与版本 8 之间,我们做出了一些努力来改进 Java 集合和中间件层的内存效率。举例来说,java.util.WeahHashMap 实例的开销中,有很大一部分比例源于其中包含用来处理弱引用的 java.lang.ref.ReferenceQueue 实例。图 18 展示了 32 位 Java 运行时中的一个 WeakHashMap 的内存布局:
图 18. 32 位 Java 运行时中的一个 WeakHashMap 的内存布局
32 位 Java 运行时中的一个 WeakHashMap 的内存布局

图 18 表明,ReferenceQueue 对象负责保留占用 560 字节的数据,即便在 WeakHashMap 为空、不需要 ReferenceQueue 的情况下也是如此。对于 PlantsByWebSphere 示例来说,在空 WeakHashMap 的数量为 19,465 的情况下,ReferenceQueue 对象将额外增加 10.9MB 的非必要数据。在 WebSphere Application Server 版本 8 和 IBM Java 运行时的 Java 7 发布版中,WeakHashMap 得到了一定的优化:它包含一个 ReferenceQueue,这又包含一个 Reference 对象数组。该数组已经更改为延迟分配,也就是说,仅在向ReferenceQueue 添加了对象的情况下执行分配。

回页首

结束语

在任何给定应用程序中,都存在着数量庞大(或许达到惊人的程度)的集合,复杂应用程序中的集合数量可能会更多。使用大量集合往往能够提供通过选择正确的集合、正确地调整其大小(或许还能通过延迟分配集合)来实现有时极其可观的内存占用节约的范围。这些决策最好在设计和开发的过程中制定,但您也可以利用 Memory Analyzer 工具来分析现有应用程序中存在内存占用优化潜力的部分。

 

参考资料

学习

获得产品和技术

讨论

  • IBM 的 Java 应用程序故障诊断:阅读 Chris Bailey 和他的同事撰写的这篇博客文章,获得有关 IBM 提供的 Java 应用程序故障诊断工具的新闻和信息。
  • 加入 developerWorks 中文社区。与其他 developerWorks 用户联系,浏览开发人员推动的博客、论坛、小组和 wiki。

关于作者

Chris BaileyChris Bailey 是位于英国的 Hursley Park Development Lab 的 IBM Java Technology Center 团队成员。作为 IBM Java 服务和支持组织的技术架构师,他负责支持 IBM SDK for Java 用户交付成功的应用程序部署。Chris 还参与收集和评估新需求,交付新调试功能和工具,改进文档并提高 IBM SDK for Java 的质量。

 

Lucene 3.0.3 API overview

original:http://lucene.apache.org/java/3_0_3/api/all/index.html

Apache Lucene is a high-performance, full-featured text search engine library.

See:
Description

 

Core
org.apache.lucene Top-level package.
org.apache.lucene.analysis API and code to convert text into indexable/searchable tokens.
org.apache.lucene.analysis.standard A fast grammar-based tokenizer constructed with JFlex.
org.apache.lucene.analysis.tokenattributes
org.apache.lucene.document The logical representation of a Document for indexing and searching.
org.apache.lucene.index Code to maintain and access indices.
org.apache.lucene.messages For Native Language Support (NLS), system of software internationalization.
org.apache.lucene.queryParser A simple query parser implemented with JavaCC.
org.apache.lucene.search Code to search indices.
org.apache.lucene.search.function
Programmatic control over documents scores.
org.apache.lucene.search.payloads
The payloads package provides Query mechanisms for finding and using payloads.
org.apache.lucene.search.spans The calculus of spans.
org.apache.lucene.store Binary i/o API, used for all index data.
org.apache.lucene.util Some utility classes.
org.apache.lucene.util.cache

 

Demo
org.apache.lucene.demo
org.apache.lucene.demo.html

 

contrib: Analysis
org.apache.lucene.analysis.ar Analyzer for Arabic.
org.apache.lucene.analysis.br Analyzer for Brazilian Portuguese.
org.apache.lucene.analysis.cjk Analyzer for Chinese, Japanese, and Korean, which indexes bigrams (overlapping groups of two adjacent Han characters).
org.apache.lucene.analysis.cn Analyzer for Chinese, which indexes unigrams (individual chinese characters).
org.apache.lucene.analysis.cn.smart
Analyzer for Simplified Chinese, which indexes words.
org.apache.lucene.analysis.cn.smart.hhmm
SmartChineseAnalyzer Hidden Markov Model package.
org.apache.lucene.analysis.compound A filter that decomposes compound words you find in many Germanic languages into the word parts.
org.apache.lucene.analysis.compound.hyphenation The code for the compound word hyphenation is taken from the Apache FOP project.
org.apache.lucene.analysis.cz Analyzer for Czech.
org.apache.lucene.analysis.de Analyzer for German.
org.apache.lucene.analysis.el Analyzer for Greek.
org.apache.lucene.analysis.fa Analyzer for Persian.
org.apache.lucene.analysis.fr Analyzer for French.
org.apache.lucene.analysis.miscellaneous Miscellaneous TokenStreams
org.apache.lucene.analysis.ngram Character n-gram tokenizers and filters.
org.apache.lucene.analysis.nl Analyzer for Dutch.
org.apache.lucene.analysis.payloads
Provides various convenience classes for creating payloads on Tokens.
org.apache.lucene.analysis.position Filter for assigning position increments.
org.apache.lucene.analysis.query Automatically filter high-frequency stopwords.
org.apache.lucene.analysis.reverse Filter to reverse token text.
org.apache.lucene.analysis.ru Analyzer for Russian.
org.apache.lucene.analysis.shingle Word n-gram filters
org.apache.lucene.analysis.sinks
Implementations of the SinkTokenizer that might be useful.
org.apache.lucene.analysis.th Analyzer for Thai.

 

contrib: Ant
org.apache.lucene.ant Ant task to create Lucene indexes.

 

contrib: Benchmark
org.apache.lucene.benchmark

The benchmark contribution contains tools for benchmarking Lucene using standard, freely available corpora.

org.apache.lucene.benchmark.byTask
Benchmarking Lucene By Tasks.
org.apache.lucene.benchmark.byTask.feeds Sources for benchmark inputs: documents and queries.
org.apache.lucene.benchmark.byTask.programmatic Sample performance test written programmatically – no algorithm file is needed here.
org.apache.lucene.benchmark.byTask.stats Statistics maintained when running benchmark tasks.
org.apache.lucene.benchmark.byTask.tasks Extendable benchmark tasks.
org.apache.lucene.benchmark.byTask.utils Utilities used for the benchmark, and for the reports.
org.apache.lucene.benchmark.quality Search Quality Benchmarking.
org.apache.lucene.benchmark.quality.trec Utilities for Trec related quality benchmarking, feeding from Trec Topics and QRels inputs.
org.apache.lucene.benchmark.quality.utils Miscellaneous utilities for search quality benchmarking: query parsing, submission reports.
org.apache.lucene.benchmark.stats
org.apache.lucene.benchmark.utils

 

contrib: Collation
org.apache.lucene.collation CollationKeyFilter and ICUCollationKeyFilter convert each token into its binary CollationKey using the provided Collator, and then encode the CollationKey as a String using IndexableBinaryStringTools, to allow it to be stored as an index term.

 

contrib: DB
com.sleepycat.db
org.apache.lucene.store.db Berkeley DB 4.3 based implementation of Directory.
org.apache.lucene.store.je Berkeley DB Java Edition based implementation of Directory.

 

contrib: Fast Vector Highlighter
org.apache.lucene.search.vectorhighlight This is an another highlighter implementation.

 

contrib: Highlighter
org.apache.lucene.search.highlight The highlight package contains classes to provide “keyword in context” features typically used to highlight search terms in the text of results pages.

 

contrib: Instantiated
org.apache.lucene.store.instantiated InstantiatedIndex, alternative RAM store for small corpora.

 

contrib: Lucli
lucli Lucene Command Line Interface

 

contrib: Memory
org.apache.lucene.index.memory High-performance single-document main memory Apache Lucene fulltext search index.

 

contrib: Misc
org.apache.lucene.misc
org.apache.lucene.queryParser.analyzing QueryParser that passes Fuzzy-, Prefix-, Range-, and WildcardQuerys through the given analyzer.
org.apache.lucene.queryParser.precedence QueryParser designed to handle operator precedence in a more sensible fashion than the default QueryParser.

 

contrib: Queries
org.apache.lucene.search.similar Document similarity query generators.

 

contrib: Query Parser
org.apache.lucene.queryParser.complexPhrase QueryParser which permits complex phrase query syntax eg “(john jon jonathan~) peters*”
org.apache.lucene.queryParser.core Contains the core classes of the flexible query parser framework
org.apache.lucene.queryParser.core.builders Contains the necessary classes to implement query builders
org.apache.lucene.queryParser.core.config Contains the base classes used to configure the query processing
org.apache.lucene.queryParser.core.messages Contains messages usually used by query parser implementations
org.apache.lucene.queryParser.core.nodes Contains query nodes that are commonly used by query parser implementations
org.apache.lucene.queryParser.core.parser Contains the necessary interfaces to implement text parsers
org.apache.lucene.queryParser.core.processors Interfaces and implementations used by query node processors
org.apache.lucene.queryParser.core.util Utility classes to used with the Query Parser
org.apache.lucene.queryParser.standard Contains the implementation of the Lucene query parser using the flexible query parser frameworks
org.apache.lucene.queryParser.standard.builders Standard Lucene Query Node Builders
org.apache.lucene.queryParser.standard.config Standard Lucene Query Configuration
org.apache.lucene.queryParser.standard.nodes Standard Lucene Query Nodes
org.apache.lucene.queryParser.standard.parser Lucene Query Parser
org.apache.lucene.queryParser.standard.processors Lucene Query Node Processors

 

contrib: RegEx
org.apache.lucene.search.regex Regular expression Query.
org.apache.regexp This package exists to allow access to useful package protected data within Jakarta Regexp.

 

contrib: Snowball
org.apache.lucene.analysis.snowball TokenFilter and Analyzer implementations that use Snowball stemmers.

 

contrib: Spatial
org.apache.lucene.spatial.geohash Support for Geohash encoding, decoding, and filtering.
org.apache.lucene.spatial.geometry
org.apache.lucene.spatial.geometry.shape
org.apache.lucene.spatial.tier Support for filtering based upon geographic location.
org.apache.lucene.spatial.tier.projections

 

contrib: SpellChecker
org.apache.lucene.search.spell Suggest alternate spellings for words.

 

contrib: Surround Parser
org.apache.lucene.queryParser.surround.parser This package contains the QueryParser.jj source file for the Surround parser.
org.apache.lucene.queryParser.surround.query This package contains SrndQuery and its subclasses.

 

contrib: Swing
org.apache.lucene.swing.models Decorators for JTable TableModel and JList ListModel encapsulating Lucene indexing and searching functionality.

 

contrib: Wikipedia
org.apache.lucene.wikipedia.analysis Tokenizer that is aware of Wikipedia syntax.

 

contrib: WordNet
org.apache.lucene.wordnet This package uses synonyms defined by WordNet.

 

contrib: XML Query Parser
org.apache.lucene.xmlparser Parser that produces Lucene Query objects from XML streams.
org.apache.lucene.xmlparser.builders

 

Other Packages
org.tartarus.snowball
org.tartarus.snowball.ext

 

Apache Lucene is a high-performance, full-featured text search engine library. Here’s a simple example how to use Lucene for indexing and searching (using JUnit to check if the results are what we expect):

    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT);

    // Store the index in memory:
    Directory directory = new RAMDirectory();
    // To store an index on disk, use this instead:
    //Directory directory = FSDirectory.open("/tmp/testindex");
    IndexWriter iwriter = new IndexWriter(directory, analyzer, true,
                                          new IndexWriter.MaxFieldLength(25000));
    Document doc = new Document();
    String text = "This is the text to be indexed.";
    doc.add(new Field("fieldname", text, Field.Store.YES,
        Field.Index.ANALYZED));
    iwriter.addDocument(doc);
    iwriter.close();
    
    // Now search the index:
    IndexSearcher isearcher = new IndexSearcher(directory, true)// read-only=true
    // Parse a simple query that searches for "text":
    QueryParser parser = new QueryParser("fieldname", analyzer);
    Query query = parser.parse("text");
    ScoreDoc[] hits = isearcher.search(query, null, 1000).scoreDocs;
    assertEquals(1, hits.length);
    // Iterate through the results:
    for (int i = 0; i < hits.length; i++) {
      Document hitDoc = isearcher.doc(hits[i].doc);
      assertEquals("This is the text to be indexed.", hitDoc.get("fieldname"));
    }
    isearcher.close();
    directory.close();

The Lucene API is divided into several packages:

To use Lucene, an application should:

  1. Create Documents by adding Fields;
  2. Create an IndexWriter and add documents to it with addDocument();
  3. Call QueryParser.parse() to build a query from a string; and
  4. Create an IndexSearcher and pass the query to its search() method.

Some simple examples of code which does this are:

To demonstrate these, try something like:

java -cp lucene.jar:lucene-demo.jar org.apache.lucene.demo.IndexFiles rec.food.recipes/soups
adding rec.food.recipes/soups/abalone-chowder
  [ … ]java -cp lucene.jar:lucene-demo.jar org.apache.lucene.demo.SearchFiles
Query: chowder
Searching for: chowder
34 total matching documents
1. rec.food.recipes/soups/spam-chowder
  [ … thirty-four documents contain the word “chowder” … ]

Query: "clam chowder" AND Manhattan
Searching for: +"clam chowder" +manhattan
2 total matching documents
1. rec.food.recipes/soups/clam-chowder
  [ … two documents contain the phrase “clam chowder” and the word “manhattan” … ]
[ Note: “+” and “-” are canonical, but “AND”, “OR” and “NOT” may be used. ]

The IndexHTML demo is more sophisticated.  It incrementally maintains an index of HTML files, adding new files as they appear, deleting old files as they disappear and re-indexing files as they change.

java -cp lucene.jar:lucene-demo.jar org.apache.lucene.demo.IndexHTML -create java/jdk1.1.6/docs/relnotes
adding java/jdk1.1.6/docs/relnotes/SMICopyright.html
  [ … create an index containing all the relnotes ]rm java/jdk1.1.6/docs/relnotes/smicopyright.html

java -cp lucene.jar:lucene-demo.jar org.apache.lucene.demo.IndexHTML java/jdk1.1.6/docs/relnotes
deleting java/jdk1.1.6/docs/relnotes/SMICopyright.html

OpenOffice Spreadsheet common

original:http://wiki.services.openoffice.org/wiki/Spreadsheet_common#Content_type_detection

Contents

[hide]

Common spreadsheet operations

See also working_with_documents

Current document

Dim oDoc As Object
oDoc = ThisComponent

Load existing document

Dim oDoc As Object
oDoc = StartDesktop.loadComponentFromURL( ConvertToURL( "/home/robert/abc.xls" ), "_blank", _
        0, Array() )

Document type check:

Function IsSpreadsheetDocument( oDoc As Object ) As Boolean
   IsSpreadsheetDocument = oDoc.supportsService( "com.sun.star.sheet.SpreadsheetDocument" )
End Function

Working with sheets

Active sheet

Function fnActiveSheet
ThisComponent.getCurrentController.getActiveSheet
end function

Number of sheets

thisComponent.getSheets.getCount

Get sheet by index

Dim oSheet As Object

oSheet = thisComponent.getSheets.getByIndex( 0 )
' or in OOo BASIC
oSheet = oDoc.Sheets( 0 )

Get sheet by name

Dim oSheet As Object

oSheet = thisComponent.getSheets.getByName( "Sheet1" )

Iterate over all sheets

'iterate over all sheets
Dim oSheet As Object
Dim eSheets As Object
eSheets = oDoc.getSheets.createEnumeration

While eSheets.hasMoreElements
        oSheet = eSheets.nextElement()

        ' here you can work your sheet
        MsgBox "Next sheet name is " & oSheet.getName & "."
Wend

Create new sheet

' create new sheet
oDoc = thisComponent
oSheet = oDoc.createInstance( "com.sun.star.sheet.Spreadsheet" )
oDoc.Sheets.insertByName( "new sheet", oSheet )

Working with rows, columns

Row, Column selection

Dim oRow As Object
Dim oColumn As Object

' get first row
oRow = oSheet.getRows.getByIndex( 0 )

' get column B
oColumn = oSheet.getColumns.getByIndex( 1 )

Column Properties

' column width (in 100ths of mm)
oColumn.setPropertyValue("Width", 100)

' optimal width
oColumn.setPropertyValue("OptimalWidth", True)

' hidden / visible
oColumn.setPropertyValue("IsVisible", False)

' page break?
oColumn.setPropertyValue("IsStartOfNewPage", False)

Row properties

' row height (in 100ths of mm)
oRow.setPropertyValue("Height", 100)

' optimal height
oRow.setPropertyValue("OptimalHeight", True)

' hidden / visible
oRow.setPropertyValue("IsVisible", False)

' page break?
oRow.setPropertyValue("IsStartOfNewPage", False)

Insert, delete row

' insert 2 rows at the 4th position (still counting from 0)
oSheet.getRows.insertByIndex( 3, 2 )

' remove 3 lines from the 7th line
oSheet.getRows.removeByIndex( 6, 3 )

Insert, delete column

' insert 2 columns into the fourth (D) column
oSheet.getColumns.insertByIndex( 3, 2 )

' remove 3 columns from the G column
oSheet.getColumns.removeByIndex( 6, 3 )

Working with cells

Cell object

Dim oCell As Object

' select A1 (first number = column, second number = row)
oCell = oSheet.getCellByPosition( 0, 0 )

'Activecell (error check in case the current selection isn't a cell)
'on error resume next
oCell = ThisComponent.getCurrentSelection

'Get a named cell - in this case the name is "Date"
oCell = thisComponent.NamedRanges.getByName("Date").getReferredCells

Each cell can contain text, number or formula:

' modify text
oCell.String = "This is A1 cell"
' Old form: oCell.setPropertyValue("String", "This is A1 cell" )

' modify number
oCell.Value = 100
' Old form: oCell.setPropertyValue("Value", 100)

'Setting a cell to a fixed date and time (format the cell for date and/or time as desired)
oCell.Value = now
' Old form: oCell.setPropertyValue("Value", now)

' modify formula
oCell.Formula = "=A2+A3"
' Old form: oCell.setPropertyValue("Formula", "=A2+A3")

Content type detection

Select Case oCell.Type
        Case com.sun.star.table.CellContentType.EMPTY
                ' oCell is empty

        Case com.sun.star.table.CellContentType.VALUE
                ' oCell contains number

        Case com.sun.star.table.CellContentType.TEXT
                ' oCell contains string

        Case com.sun.star.table.CellContentType.FORMULA
                ' oCell contains formula
End Select

Cell range

CellRangeAddress is a simple structure with five elements:

  • Sheet
  • StartColumn
  • StartRow
  • EndColumn
  • EndRow

CellRangeAddress is obviously used to modify more than one cell.

Insert cells

Following example insert cells at B2:C3 range. Any existing values in the specified range are moved downwards.

Dim oRange As New com.sun.star.table.CellRangeAddress

' first sheet and B2:C3 range
oRange.Sheet = 0
oRange.StartColumn = 1
oRange.StartRow = 1
oRange.EndColumn = 2
oRange.EndRow = 2

oSheet.insertCells( oRange, com.sun.star.sheet.CellInsertMode.DOWN )

Possible values for the second argument are:

  • NONE
  • DOWN the cells are moved downwards
  • RIGHT the cells are moved to the right
  • ROWS the rows are moved downwards
  • COLUMNS the columns are moved to the right

Remove cells

Following example remove cells at B2:C3 range. Any existing values in the specified range are moved upwards.

Dim oRange As New com.sun.star.table.CellRangeAddress

' first sheet and B2:C3 range
oRange.Sheet = 0
oRange.StartColumn = 1
oRange.StartRow = 1
oRange.EndColumn = 2
oRange.EndRow = 2

oSheet.removeCells( oRange, com.sun.star.sheet.CellInsertMode.UP )

Possible values for the second argument are:

  • NONE
  • UP the cells are moved upwards
  • LEFT the cells are moved to the left
  • ROWS the rows are moved upwards
  • COLUMNS the columns are moved to the left

Move, copy cells

CellAddress is a new object, which will helps you identify the cell address and contains three elements:

  • Sheet
  • Column
  • Row

Following example will move the A2:B3 cells to the A1.

oRange As New com.sun.star.table.CellRangeAddress

' A2:B3 on the first sheet
oRange.Sheet = 0
oRange.StartColumn = 1
oRange.StartRow = 1
oRange.EndColumn = 2
oRange.EndRow = 2

Dim oAddress As New com.sun.star.table.CellAddress

' A1 on the first sheet
oAddress.Sheet = 0
oAddress.Column = 0
oAddress.Row = 0

' move the selected range to new position
oSheet.moveRange( oAddress, oRange )

' copy the selected range to new position
oSheet.copyRange( oAddress, oRange )

Range selection by name

You can create range address with cell names:

oRange = oSheet.getCellRangeByName( "B2:C3" )

You can select cells from the range in the same way as from the sheet. Following example returns cell B2:

oCell = oRange.getCellByPosition( 0, 0 )

The cell position is counted from the upper left corner of the range, not of the sheet.

Content deletion

Dim nFlags As Long

oRange = oSheet.getCellRangeByName( "B2:C3" )

nFlags = com.sun.star.sheet.CellFlags.STRING + _
        com.sun.star.sheet.CellFlags.STYLES

oRange.clearContents( nFlags )

Available flags listed below:

  • VALUE numerical value
  • DATETIME date or time
  • STRING strings
  • ANNOTATION comments
  • FORMULA formulas
  • HARDATTR direct formatting of cells
  • STYLES indirect formatting
  • OBJECTS drawing objects connected to cells
  • EDITATTR formatting that applies to parts of the cells

Formatting

The following examples can be applied to either a Cell or a RangeAddress.

See working_with_styles#number_formats for information on changing number formats.

Background color, shadows

Shadow is defined in the structure com.sun.star.table.ShadowFormat, which has four elements.

  • Color shadow color
  • Location shadow location
  • ShadowWidth shadow width
  • IsTransparent shadow transparency

Possible values for Location are:

  • NONE
  • TOP_LEFT
  • TOP_RIGHT
  • BOTTOM_LEFT
  • BOTTOM_RIGHT
' cell background color
oCell.setPropertyValue( "CellBackColor", RGB( 0, 0, 0 ) )

' cell background transparency
oCell.setPropertyValue( "IsCellBackgroundTransparent", False )

' cell shadow
Dim oShadow As New com.sun.star.table.ShadowFormat

oShadow.Location = com.sun.star.table.ShadowLocation.BOTTOM_RIGHT
oShadow.Color = RGB(255, 255, 0)
oShadow.ShadowWidth = 50
oShadow.IsTransparent = False

oCell.setPropertyValue( "ShadowFormat", oShadow )

Justification

Horizontal

Each cell contains property HoriJustify with possible values (com.sun.star.table.CellHoriJustify):

  • STANDARD
  • LEFT
  • CENTER
  • RIGHT
  • BLOCK
  • REPEAT
' horizontal justification - right
oCell.setPropertyValue( "HoriJustify", com.sun.star.table.CellHoriJustify.RIGHT )

Vertical

Each cell contains property VertJustify with possible values (com.sun.star.table.CellVertJustify):

  • STANDARD
  • TOP
  • CENTER
  • BOTTOM
' vertical justification - center
oCell.setPropertyValue( "VertJustify", com.sun.star.table.CellVertJustify.CENTER )

Orientation

Each cell contains property Orientation with possible values (com.sun.star.table.CellOrientation):

  • STANDARD
  • TOPBOTTOM
  • BOTTOMTOP
  • STACKED
' orientation - STACKED
oCell.setPropertyValue( "Orientation", com.sun.star.table.CellOrientation.STACKED )

Wrapping, rotation

Each cell contains property IsTextWrapped (Boolean) and RotateAngle (Long) for better justification.

' wrapped text
oCell.setPropertyValue( "IsTextWrapped", True )

' vertical text
oCell.setPropertyValue( "RotateAngle", 90 )

Example: Setting currently selected cells to current date and time

sub subSetDate
oDoc = thisComponent
oSelection = oDoc.getCurrentSelection
nFormat = fnGetNumberFormatId(oDoc,"DD/MM/YY")
if HasUnoInterfaces(oSelection, "com.sun.star.lang.XServiceInfo") then
	if oSelection.supportsService("com.sun.star.sheet.SheetCellRanges") then
		'More than one range selected
		subSetRanges(oSelection, vValue, nFormat)
	elseif oSelection.supportsService("com.sun.star.table.CellRange") then
		'Only one range but more than one cell
		subSetRange(oSelection, now, nFormat)
	elseif oSelection.supportsService("com.sun.star.sheet.SheetCell") then
		'only one cell selected
		subSetCell(oSelection, now, nFormat)	
	end if
end if
end sub

sub subSetRanges(oRanges, vValue, nFormat)
for i = 0 to oRanges.getCount -1
	subSetRange(oRanges.getByIndex(i), vValue, nFormat)
next
end sub

sub subSetRange(oRange, vValue, nFormat)
for i = 0 to oRange.getColumns.getCount - 1
	for j = 0 to oRange.getRows.getCount - 1
		subSetCell(oRange.getCellByPosition(i,j), vValue, nFormat)
	next
next
end sub

sub subSetCell(oCell, vValue, nFormat)
oCell.value=vValue
oCell.setPropertyValue("NumberFormat", nFormat)
end sub

function fnGetNumberFormatId(oDoc, sNumberFormat)
sCharLocale = oDoc.getPropertyValue("CharLocale")
nFormatId = oDoc.getNumberFormats.queryKey(sNumberFormat, sCharLocale, false)
if nFormatId = -1 then 'Not yet defined
        nFormatId = oDoc.getNumberFormats.addNew(sNumberFormat, sCharLocale)
end if
fnGetNumberFormatId = nFormatId
end function