append是什么意思java_为什么StringBuilder#append(int)在Java 7中比在Java 8中更快?

在调查

little debate w.r.t.使用“”和

Integer.toString(int)将整数原语转换为字符串我写了这个

JMH microbenchmark:

@Fork(1)

@OutputTimeUnit(TimeUnit.MILLISECONDS)

@State(Scope.Benchmark)

public class IntStr {

protected int counter;

@GenerateMicroBenchmark

public String integerToString() {

return Integer.toString(this.counter++);

}

@GenerateMicroBenchmark

public String stringBuilder0() {

return new StringBuilder().append(this.counter++).toString();

}

@GenerateMicroBenchmark

public String stringBuilder1() {

return new StringBuilder().append("").append(this.counter++).toString();

}

@GenerateMicroBenchmark

public String stringBuilder2() {

return new StringBuilder().append("").append(Integer.toString(this.counter++)).toString();

}

@GenerateMicroBenchmark

public String stringFormat() {

return String.format("%d", this.counter++);

}

@Setup(Level.Iteration)

public void prepareIteration() {

this.counter = 0;

}

}

我使用默认的JMH选项运行它与我的Linux机器上存在的两个Java虚拟机(最新的Mageia 4 64位,Intel i7-3770 CPU,32GB RAM)。第一个JVM是Oracle JDK提供的

8u5 64位:

java version "1.8.0_05"

Java(TM) SE Runtime Environment (build 1.8.0_05-b13)

Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)

有了这个JVM我得到了我的预期:

Benchmark Mode Samples Mean Mean error Units

b.IntStr.integerToString thrpt 20 32317.048 698.703 ops/ms

b.IntStr.stringBuilder0 thrpt 20 28129.499 421.520 ops/ms

b.IntStr.stringBuilder1 thrpt 20 28106.692 1117.958 ops/ms

b.IntStr.stringBuilder2 thrpt 20 20066.939 1052.937 ops/ms

b.IntStr.stringFormat thrpt 20 2346.452 37.422 ops/ms

也就是说使用StringBuilder类会更慢,因为创建StringBuilder对象和追加空字符串需要额外的开销。使用String.format(String,…)更慢一个数量级左右。

另一方面,分发提供的编译器基于OpenJDK 1.7:

java version "1.7.0_55"

OpenJDK Runtime Environment (mageia-2.4.7.1.mga4-x86_64 u55-b13)

OpenJDK 64-Bit Server VM (build 24.51-b03, mixed mode)

这里的结果很有趣:

Benchmark Mode Samples Mean Mean error Units

b.IntStr.integerToString thrpt 20 31249.306 881.125 ops/ms

b.IntStr.stringBuilder0 thrpt 20 39486.857 663.766 ops/ms

b.IntStr.stringBuilder1 thrpt 20 41072.058 484.353 ops/ms

b.IntStr.stringBuilder2 thrpt 20 20513.913 466.130 ops/ms

b.IntStr.stringFormat thrpt 20 2068.471 44.964 ops/ms

为什么StringBuilder.append(int)出现这么快的JVM?看看StringBuilder类的源代码显示没有什么特别有趣 – 所讨论的方法几乎等同于Integer#toString(int)。有趣的是,添加Integer.toString(int)(stringBuilder2 microbenchmark)的结果似乎不会更快。

这种性能差异是测试线束的一个问题吗?或者我的OpenJDK JVM包含会影响这个特定代码(反)-pattern的优化?

编辑:

为了更直接的比较,我安装了Oracle JDK 1.7u55:

java version "1.7.0_55"

Java(TM) SE Runtime Environment (build 1.7.0_55-b13)

Java HotSpot(TM) 64-Bit Server VM (build 24.55-b03, mixed mode)

结果类似于OpenJDK的结果:

Benchmark Mode Samples Mean Mean error Units

b.IntStr.integerToString thrpt 20 32502.493 501.928 ops/ms

b.IntStr.stringBuilder0 thrpt 20 39592.174 428.967 ops/ms

b.IntStr.stringBuilder1 thrpt 20 40978.633 544.236 ops/ms

看来这是一个更一般的Java 7与Java 8问题。也许Java 7有更积极的字符串优化?

编辑2:

为了完整性,以下是这两个JVM的与字符串相关的VM选项:

对于Oracle JDK 8u5:

$ /usr/java/default/bin/java -XX:+PrintFlagsFinal 2>/dev/null | grep String

bool OptimizeStringConcat = true {C2 product}

intx PerfMaxStringConstLength = 1024 {product}

bool PrintStringTableStatistics = false {product}

uintx StringTableSize = 60013 {product}

对于OpenJDK 1.7:

$ java -XX:+PrintFlagsFinal 2>/dev/null | grep String

bool OptimizeStringConcat = true {C2 product}

intx PerfMaxStringConstLength = 1024 {product}

bool PrintStringTableStatistics = false {product}

uintx StringTableSize = 60013 {product}

bool UseStringCache = false {product}

在Java 8中删除了UseStringCache选项,没有替换,所以我怀疑,使任何区别。其余选项看起来具有相同的设置。

编辑3:

对来自src.zip文件的AbstractStringBuilder,StringBuilder和Integer类的源代码进行并行比较,显示没有什么不重要。除了大量的化妆品和文档的变化,Integer现在有一些支持无符号整数和StringBuilder已被轻微重构,以分享更多的代码与StringBuffer。这些更改似乎不影响StringBuilder#append(int)使用的代码路径,虽然我可能错过了一些东西。

对于IntStr#integerToString()和IntStr#stringBuilder0()生成的汇编代码的比较更有趣。 IntStr#integerToString()生成的代码的基本布局对于两个JVM都是类似的,虽然Oracle JDK 8u5似乎是更积极的w.r.t.在Integer#toString(int)代码中嵌入一些调用。与Java源代码有一个明确的对应关系,即使有最小的汇编经验的人。

然而,IntStr#stringBuilder0()的汇编代码是完全不同的。由Oracle JDK 8u5生成的代码再次与Java源代码直接相关 – 我可以很容易地识别相同的布局。相反,OpenJDK 7生成的代码几乎无法被未经训练的眼睛识别(像我的)。新的StringBuilder()调用被删除,就像在StringBuilder构造函数中创建数组一样。 Additionaly,反汇编插件不能提供对源代码的许多引用,因为它在JDK 8。

我假设这是OpenJDK 7中更激进的优化传递的结果,或者更可能是为某些StringBuilder操作插入手写的低级代码的结果。我不确定为什么这种优化不会发生在我的JVM 8实现或为什么没有实现相同的优化在JVM 7中的Integer#toString(int)。我想有人熟悉JRE源代码的相关部分必须回答这些问题…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用以下代码实现在Java Swing弹出窗口并在TextArea显示文件内容的功能: ```java import java.awt.BorderLayout; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; public class FileViewer extends JFrame implements ActionListener { private JButton openButton; private JTextArea textArea; public FileViewer() { super("File Viewer"); // Create components openButton = new JButton("Open"); openButton.addActionListener(this); textArea = new JTextArea(); JScrollPane scrollPane = new JScrollPane(textArea); // Add components to content pane Container contentPane = getContentPane(); contentPane.add(openButton, BorderLayout.NORTH); contentPane.add(scrollPane, BorderLayout.CENTER); // Set window properties setSize(400, 300); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); } public static void main(String[] args) { // Create and show window FileViewer fileViewer = new FileViewer(); fileViewer.setVisible(true); } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == openButton) { // Create file chooser dialog JFileChooser fileChooser = new JFileChooser(); int result = fileChooser.showOpenDialog(this); if (result == JFileChooser.APPROVE_OPTION) { // Get selected file File file = fileChooser.getSelectedFile(); try { // Read file contents BufferedReader reader = new BufferedReader(new FileReader(file)); String line; StringBuilder sb = new StringBuilder(); while ((line = reader.readLine()) != null) { sb.append(line); sb.append(System.lineSeparator()); } reader.close(); // Set text area contents textArea.setText(sb.toString()); } catch (Exception ex) { ex.printStackTrace(); } } } } } ``` 这段代码会创建一个名为 "File Viewer" 的窗口,其包含一个 "Open" 按钮和一个文本区域。当用户点击 "Open" 按钮时,会弹出一个文件选择器对话框,用户可以选择要读取的文件。然后,程序会读取文件内容并将其显示在文本区域

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值