聞こえないJavaエンジニアが適当に書き連ねていく

つらつらとメモしたり日頃の溜まっている想いを吐き出す場所です。

半角英字の結合をしたらJava8より遅くなった件の調査【原因不明】 #Java9 #String

これの続編です。 結論から言うと謎が深まっただけです。 tadashi.hatenablog.com

LATIN1/UTF16 の判定が追加になっている、と書いてあるので、判定用の値を取得する coder()メソッドの結果を見てみることにしました。 d.hatena.ne.jp

ソースはこちらです。
※リフレクションを使っています。

https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/src/main/java/jmhTest/StringTest.java

package jmhTest;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class StringTest {

    private static String[] list = {"a","b","c","d","e","f","g","h","i", "j"};

    public static void main(String... args) {

//        String[] val = {"", "a", "1", "あ"};
//        for(String str : val) {
//            checkCoder(str);
//        }

        test1StringLine();

    }

    private static void checkCoder(String str) {

        System.out.println("------");

        Class<String> c = String.class;
        try {

            Method m = c.getDeclaredMethod("coder");
            m.setAccessible(true);

            byte b = (byte)m.invoke(str);
            System.out.println(str + " coder(): "+b);

            Field f = c.getDeclaredField("coder");
            f.setAccessible(true);
            byte b1 = f.getByte(str);

            System.out.println(str + " coder: "+b1);


        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }


    }


    public static void test1StringLine() {

        int i = 0;
        String str0 = list[i];
        checkCoder(str0);

        i++;
        String str1 = list[i];
        checkCoder(str1);
        i++;
        String str2 = list[i];
        checkCoder(str2);
        i++;
        String str3 = list[i];
        checkCoder(str3);
        i++;
        String str4 = list[i];
        checkCoder(str4);
        i++;
        String str5 = list[i];
        checkCoder(str5);
        i++;
        String str6 = list[i];
        checkCoder(str6);
        i++;
        String str7 = list[i];
        checkCoder(str7);
        i++;
        String str8 = list[i];
        checkCoder(str8);
        i++;
        String str9 = list[i];
        checkCoder(str9);

        String str = str0 + str1 + str2 + str3 + str4 + str5 + str6 + str7 + str8 + str9;

        checkCoder(str);
    }

}

遅くなる理由は、LATIN1で判定して違う、ということでUTF-16の処理になるために処理時間が遅延しているのでは、と推測しました。
さて、結果はというと…

------
a coder(): 0
a coder: 0
------
b coder(): 0
b coder: 0
------
c coder(): 0
c coder: 0
------
d coder(): 0
d coder: 0
------
e coder(): 0
e coder: 0
------
f coder(): 0
f coder: 0
------
g coder(): 0
g coder: 0
------
h coder(): 0
h coder: 0
------
i coder(): 0
i coder: 0
------
j coder(): 0
j coder: 0
------
abcdefghij coder(): 0
abcdefghij coder: 0

coderの値が0ならLATIN1、1ならUTF-16と判定されるロジックなのですが、LATIN1と判定されているようです。
うーん、なんで半角数字同様のパフォーマンスが出てくれないのだろう…?

正式版Java9で文字列の結合の速度を確認する #Java9 #String

これは何?

2017/9/21にJava9が正式にリリースされました。 Java9ではStringのあれこれが変わったと聞いていますが、そんなことはどうでもいいのです。
維持屋にとっては、バージョンアップ後のパフォーマンスがどうなるのか、が重要なのです!!(極論)

前提

これと同じプログラムを使ってテストしました。 qiita.com

@YujiSoftware さんのブログで、VMオプションについて記載されていたのでそれについても試しています。

d.hatena.ne.jp

githubのソースの場所はこちら。 github.com

jmhの起動方法などはこちらにまとめています。 https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/command.txt

テストした端末のスペックなどは以下の通りです。

  • Windows10 64bit
  • Intel® Core™ i7-2820QM CPU @ 2.30GHz
  • メモリは8GM

結果

注釈

  • スマホからだと見づらいので、パソコンにするか、横にして画面を広げるか、などをお勧めします。
  • Scoreの数字が大きいほど、パフォーマンスがいいと言えます。

半角英字

VM version: JDK 1.8.0_144, VM 25.144-b01

Benchmark                             Mode  Cnt    Score   Error  Units
StringLineHankaku.call1StringLine     thrpt   10  141.099 ± 1.144  ops/s
StringLineHankaku.call2StringConcat   thrpt   10   35.888 ± 0.221  ops/s
StringLineHankaku.call3StringBuffer   thrpt   10   97.689 ± 0.812  ops/s
StringLineHankaku.call4StringBuilder  thrpt   10   98.916 ± 3.052  ops/s

結果全文 https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/MyBenchmarkStringLineHankakuJava8Result_20170923.txt

VM version: JDK 9-ea, VM 9-ea+134(Early Access版)

Benchmark                             Mode  Cnt    Score   Error  Units
StringLineHankaku.call1StringLine     thrpt   10  90.187 ± 2.961  ops/s
StringLineHankaku.call2StringConcat   thrpt   10  46.822 ± 3.277  ops/s
StringLineHankaku.call3StringBuffer   thrpt   10  68.937 ± 2.796  ops/s
StringLineHankaku.call4StringBuilder  thrpt   10  78.742 ± 2.665  ops/s

結果全文 https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/MyBenchmarkStringLineHankakuJava9Result.txt

VM version: JDK 9, VM 9+181

VM options: なし

Benchmark                             Mode  Cnt    Score   Error  Units
StringLineHankaku.call1StringLine     thrpt   10  92.795 ±  2.711  ops/s
StringLineHankaku.call2StringConcat   thrpt   10  27.106 ± 17.205  ops/s
StringLineHankaku.call3StringBuffer   thrpt   10  53.108 ± 21.248  ops/s
StringLineHankaku.call4StringBuilder  thrpt   10  62.540 ± 21.275  ops/s

結果全文 https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/MyBenchmarkStringLineHankakuJava9Result_20170923.txt

VM options: -XX:-CompactStrings -DCompactStringEnabled=false

Benchmark                             Mode  Cnt    Score   Error  Units
StringLineHankaku.call1StringLine     thrpt   10  108.819 ± 4.212  ops/s
StringLineHankaku.call2StringConcat   thrpt   10   50.795 ± 0.952  ops/s
StringLineHankaku.call3StringBuffer   thrpt   10   56.127 ± 0.568  ops/s
StringLineHankaku.call4StringBuilder  thrpt   10  104.129 ± 1.707  ops/s

結果全文 https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/MyBenchmarkStringLineHankakuJava9Result_20170923_withOption.txt

半角数字

VM version: JDK 1.8.0_144, VM 25.144-b01

Benchmark                            Mode  Cnt    Score    Error  Units
StringLineNumber.call1StringLine     thrpt   10  112.127 ± 34.207  ops/s
StringLineNumber.call2StringConcat   thrpt   10   71.693 ±  0.270  ops/s
StringLineNumber.call3StringBuffer   thrpt   10  103.061 ±  1.590  ops/s
StringLineNumber.call4StringBuilder  thrpt   10   88.149 ± 35.149  ops/s

結果全文

https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/MyBenchmarkStringLineNumberJava8Result_20170923.txt

VM version: JDK 9-ea, VM 9-ea+134(Early Access版)

Benchmark                            Mode  Cnt    Score    Error  Units
StringLineNumber.call1StringLine     thrpt   10  245.689 ± 13.801  ops/s
StringLineNumber.call2StringConcat   thrpt   10  132.742 ±  9.051  ops/s
StringLineNumber.call3StringBuffer   thrpt   10   49.300 ±  1.349  ops/s
StringLineNumber.call4StringBuilder  thrpt   10   52.594 ±  2.545  ops/s

結果全文

https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/MyBenchmarkStringLineNumberJava8Result.txt

VM version: JDK 9, VM 9+181

VM options: なし

Benchmark                            Mode  Cnt    Score     Error  Units
StringLineNumber.call1StringLine     thrpt   10  187.399 ± 111.698  ops/s
StringLineNumber.call2StringConcat   thrpt   10  103.961 ±  50.983  ops/s
StringLineNumber.call3StringBuffer   thrpt   10   33.543 ±  21.675  ops/s
StringLineNumber.call4StringBuilder  thrpt   10   51.688 ±   0.346  ops/s

結果全文

https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/MyBenchmarkStringLineNumberJava9Result_20170923.txt

VM options: -XX:-CompactStrings -DCompactStringEnabled=false

Benchmark                            Mode  Cnt    Score    Error  Units
StringLineNumber.call1StringLine     thrpt   10  238.952 ± 12.086  ops/s
StringLineNumber.call2StringConcat   thrpt   10  107.838 ±  3.610  ops/s
StringLineNumber.call3StringBuffer   thrpt   10  101.667 ± 97.174  ops/s
StringLineNumber.call4StringBuilder  thrpt   10  177.984 ±  3.698  ops/s

結果全文

https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/MyBenchmarkStringLineNumberJava9Result_20170923_withOption.txt

全角文字

VM version: JDK 1.8.0_144, VM 25.144-b01

Benchmark                             Mode  Cnt    Score   Error  Units
StringLineZenkaku.call1StringLine     thrpt   10  141.133 ± 1.504  ops/s
StringLineZenkaku.call2StringConcat   thrpt   10   36.212 ± 0.202  ops/s
StringLineZenkaku.call3StringBuffer   thrpt   10   97.025 ± 2.155  ops/s
StringLineZenkaku.call4StringBuilder  thrpt   10   99.454 ± 1.509  ops/s

結果全文 https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/MyBenchmarkStringLineZenkakuJava8Result_20170923.txt

VM version: JDK 9-ea, VM 9-ea+134(Early Access版)

Benchmark                             Mode  Cnt   Score   Error  Units
StringLineZenkaku.call1StringLine     thrpt   10  92.686 ± 0.299  ops/s
StringLineZenkaku.call2StringConcat   thrpt   10  49.554 ± 0.684  ops/s
StringLineZenkaku.call3StringBuffer   thrpt   10  56.950 ± 6.474  ops/s
StringLineZenkaku.call4StringBuilder  thrpt   10  69.917 ± 0.210  ops/s

結果全文 https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/MyBenchmarkStringLineZenkakuJava9Result.txt

VM version: JDK 9, VM 9+181

VM options: なし

Benchmark                             Mode  Cnt   Score   Error  Units
StringLineZenkaku.call1StringLine     thrpt   10  93.176 ± 1.204  ops/s
StringLineZenkaku.call2StringConcat   thrpt   10  48.488 ± 0.728  ops/s
StringLineZenkaku.call3StringBuffer   thrpt   10  55.984 ± 6.048  ops/s
StringLineZenkaku.call4StringBuilder  thrpt   10  63.517 ± 0.586  ops/s

結果全文

https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/MyBenchmarkStringLineZenkakuJava9Result_20170923.txt

VM options: -XX:-CompactStrings -DCompactStringEnabled=false

Benchmark                             Mode  Cnt    Score   Error  Units
StringLineZenkaku.call1StringLine     thrpt   10  109.511 ± 1.972  ops/s
StringLineZenkaku.call2StringConcat   thrpt   10   50.061 ± 2.419  ops/s
StringLineZenkaku.call3StringBuffer   thrpt   10   55.549 ± 0.624  ops/s
StringLineZenkaku.call4StringBuilder  thrpt   10  104.124 ± 1.103  ops/s

結果全文

https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/MyBenchmarkStringLineZenkakuJava9Result_20170923_withOption.txt

まとめ

  • 数値でない場合の結合速度は爆速になるどころか、遅くなっている。

    • @YujiSoftware さんのブログを読む限りでは、半角英字は速くなってもいいはずなのだが…テストプログラムの書き方の問題であろうか?
  • VMオプションを付けると、StringBuilderもStringと同等のパフォーマンスになることがある模様。

    • Java9に挙げた結果、パフォーマンスが遅くなって困るときはVMオプションの付与を検討してもいいかも。[要検証]

お願い

  • 違う結果が出たよ、というのがありましたらテスト方法含めてどこかにまとめたうえで教えてください。勉強しに行きます。

JasperReportsを使うときのライブラリについて

クラスメソッド様のブログにはいつもお世話になっております。

dev.classmethod.jp

2013年に出たブログですが、今でもたまにたどり着くこのページ。 依存ライブラリの部分がmavenだと若干古くなっているようなのでメモとして残しておく。

JasperReports LibraryはPDFを出力する場合にitextを利用しますが、この時に依存しているバージョンはLGPLである2.1系の最新バージョンである2.1.7にJasperReportsで独自のパッチを当てた、2.1.7.js2です。このバージョンはMavenのcentral repositoryに存在しないため、Jaspersoftのリポジトリを追加しなければなりません。

最新版(6.4.1)だと itext-2.1.7.js6 がMavenのcentral repositoryに存在するようで、リポジトリの追加は不要。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>xxxx.yyy</groupId>
    <artifactId>test1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>test1</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <javac.target>1.7</javac.target>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/net.sf.jasperreports/jasperreports -->
        <dependency>
            <groupId>net.sf.jasperreports</groupId>
            <artifactId>jasperreports</artifactId>
            <version>6.4.1</version>
        </dependency>
    </dependencies>
</project>

このページを参考に依存関係を確認する。

d.hatena.ne.jp

確認結果は以下の通り。

[INFO] xxxx.xxxx:test1:jar:0.0.1-SNAPSHOT
[INFO] +- junit:junit:jar:3.8.1:test
[INFO] \- net.sf.jasperreports:jasperreports:jar:6.4.1:compile
[INFO]    +- commons-beanutils:commons-beanutils:jar:1.9.3:compile
[INFO]    +- commons-collections:commons-collections:jar:3.2.2:compile
[INFO]    +- commons-digester:commons-digester:jar:2.1:compile
[INFO]    +- commons-logging:commons-logging:jar:1.1.1:compile
[INFO]    +- com.lowagie:itext:jar:2.1.7.js6:compile
[INFO]    |  \- org.bouncycastle:bcprov-jdk15on:jar:1.52:compile
[INFO]    +- org.jfree:jcommon:jar:1.0.23:compile
[INFO]    +- org.jfree:jfreechart:jar:1.0.19:compile
[INFO]    +- org.eclipse.jdt.core.compiler:ecj:jar:4.3.1:compile
[INFO]    +- org.codehaus.castor:castor-xml:jar:1.3.3:compile
[INFO]    |  +- org.codehaus.castor:castor-core:jar:1.3.3:compile
[INFO]    |  +- commons-lang:commons-lang:jar:2.6:compile
[INFO]    |  +- javax.inject:javax.inject:jar:1:compile
[INFO]    |  +- stax:stax:jar:1.2.0:compile
[INFO]    |  |  \- stax:stax-api:jar:1.0.1:compile
[INFO]    |  \- javax.xml.stream:stax-api:jar:1.0-2:compile
[INFO]    +- com.fasterxml.jackson.core:jackson-core:jar:2.1.4:compile
[INFO]    +- com.fasterxml.jackson.core:jackson-databind:jar:2.1.4:compile
[INFO]    +- com.fasterxml.jackson.core:jackson-annotations:jar:2.1.4:compile
[INFO]    +- org.apache.lucene:lucene-core:jar:4.5.1:compile
[INFO]    +- org.apache.lucene:lucene-analyzers-common:jar:4.5.1:compile
[INFO]    +- org.apache.lucene:lucene-queryparser:jar:4.5.1:compile
[INFO]    |  +- org.apache.lucene:lucene-queries:jar:4.5.1:compile
[INFO]    |  \- org.apache.lucene:lucene-sandbox:jar:4.5.1:compile
[INFO]    |     \- jakarta-regexp:jakarta-regexp:jar:1.4:compile
[INFO]    +- org.olap4j:olap4j:jar:0.9.7.309-JS-3:compile
[INFO]    +- com.google.zxing:core:jar:3.2.1:compile
[INFO]    \- com.ibm.icu:icu4j:jar:57.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 53.129 s
[INFO] Finished at: 2017-08-18T10:41:44+09:00
[INFO] Final Memory: 14M/64M
[INFO] ------------------------------------------------------------------------

以上。

SXSSFWorkbookの不具合 #apachePoi

qiita.com

知らなかったので再現プログラムを書いてみた。

import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

public class WriteTest {

    public static void main(String[] args) {

        String outputFilePath = "out.xlsx";
        Workbook book = null;
        FileOutputStream fout = null;

        try {
            book = new SXSSFWorkbook();

            Font font = book.createFont();
            font.setFontName("MS ゴシック");
            font.setFontHeightInPoints((short) 9);

            CellStyle style = book.createCellStyle();
            style.setWrapText(true);

            Sheet sheet = book.createSheet();

            Row row = sheet.createRow(0);
            Cell cell0 = row.createCell(0);
            cell0.setCellValue("aaa\r\nbbb");
            cell0.setCellStyle(style);

            Cell cell1 = row.createCell(1);
            cell1.setCellValue("aaa\rbbb");
            cell1.setCellStyle(style);

            Cell cell2 = row.createCell(2);
            cell2.setCellValue("aaa\nbbb");
            cell2.setCellStyle(style);

            Cell cell3 = row.createCell(3);
            cell3.setCellValue("aaa\\nbbb");
            cell3.setCellStyle(style);
            
            fout = new FileOutputStream(outputFilePath);
            book.write(fout);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                book.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

処理結果はこうなり、A1セルの改行が2回行われていることが確認出来る。

f:id:su_zu_ki_1010:20170818100746p:plain

原因となるコードはpoi-ooxml-3.xx.jarの org.apache.poi.xssf.streaming.SheetDataWriter.javaの371行目から379行目の部分。 ※3.17-beta1でも直っていないことを確認した。

// Special characters
case '\n':
case '\r':
    if (counter > last) {
        _out.write(chars, last, counter - last);
    }
    _out.write("&#xa;");
    last = counter + 1;
    break;

#xa;はxml文書で改行コードを表すらしい。

www.4d.com

当面の対応は、\r\nを\r、あるいは\nに置換するしかなさそうだけど、本対応はapacheにバグレポートを書くことだろうなぁ。 githubだったらissueに書けばいいんだろうけど、apache poiはsubversionで活動されているので報告先がわからない…。

というか、SXSSFWorkbookってあまり使われていないのかな。

今日学んだことの覚書

TeraTermマクロでウィンドウサイズを変える

dispstr #$1b"[8;42;130t"

42と130は任意の数字にする。

srad.jp

DB2をインストール後、5005エラーが出る時の対処法

db2systray -clean

このコマンドを打てばいいのだけど、OSによってはそれでも5005エラーが出る。 その時は、コマンドプロンプト管理者権限で開いて実行すればよい。

www-01.ibm.com

Linuxコマンドメモ<find+grepの組み合わせ>

コマンド

find ./* -newermt '20170803 08:00' | xargs grep 検索ワード

これで2017/8/3の8時以降に更新されたファイルの中から、検索ワードが存在するファイルのみを抽出できる。

参考

findで具体的な日付、時間で検索するnewerXYオプション - システム開発メモ

d.hatena.ne.jp

rfs.jp

Eclipse Oxygenをダウンロードしたい

eclipse.org トップページのDONLOWADを踏むとインストーラがダウンロードされてしまう。

そんなんじゃなくて、従来の色々なバージョンのeclipseが選択できる画面からダウンロードしたいんだ!
そんな人向け。

eclipse.org

遷移方法は トップページを開く
 ↓
「GETTEING STARTED」 をクリック
 ↓
「DONLOWAD ECLIPSE IDE」 のボタンをクリック
 ↓
薄く出ている、「Download Packages」のリンクをクリック
 ↓
慣れ親しんだページに遷移できる。