カテゴリー: Java

StringBuilderってどうよ?

StringBuilderの効果ってどうなのか?というところに疑問を持ったので、調べてみることにした。

Javaの文字列結合はStringBuilderでいいのか

結論的には、

・複数ステートメントで
・結合される側の文字列を複数スレッドで共有しない場合は
メモリアロケーションの回数が少ないStringBuilderが一番高速で文字列結合できる

なのだが、どのような処理になっているのでこうなる!というのが書かれていて、非常に参考になった。

スレッドを使ったときは不具合が起きるというのは、以下のページに書いてある。

【Java】+演算子、StringBuilder、StringBufferの違い(実際に測ってみた。)

StringBuilderとStringBufferの使い分けについても書いてあるので、これも参考に。

以下はVB(.NET)のStringBuilderについての記載。

Visual Basic で StringBuilder を使うべき場合とその利点

こちらもJavaと同じような話。(SE2年目でこの記載は凄いなぁ。うちの社員にもこういう人欲しい。)

使い方については、

意外と知られてないStringBuilderに関する初歩的なTips【Java・C#】

なんか、どうでしょう。
インスタンスをコロコロ変えたくないなぁと思っているので、こういうのはありがたい。

が、少し待て!

男(かどうか知らんが)がすなる時間計測といふものを女もしてみむとてするなり・・・

VC#(.NET Framework4.8)でやってみた。
<1> Length=0でクリアする
<2> 新たなインスタンスを作る
<3> Clearを使う(C#はClearメソッドがある)

        static void Main(string[] args) {
            var sw = new System.Diagnostics.Stopwatch();

            // <1>
            for (int j = 0; j < 10; j++) {
                sw.Start();
                StringBuilder sb1 = new StringBuilder("");
                for (int i = 0; i < 999999; i++) {
                    sb1.Length = 0;
                    sb1.Append(i.ToString());
                }
                sw.Stop();
                Console.WriteLine($"1) {sw.ElapsedMilliseconds}ms");
            }

            // <2>
            for (int j=0;j<10;j++) {
                sw.Restart();
                for (int i = 0; i < 999999; i++) {
                    StringBuilder sb2 = new StringBuilder("");
                    sb2.Append(i.ToString());
                }
                sw.Stop();
                Console.WriteLine($"2) {sw.ElapsedMilliseconds}ms");
            }

            // <3>
            StringBuilder sb3 = new StringBuilder("");
            for (int j = 0; j < 10; j++) {
                sw.Restart();
                for (int i = 0; i < 999999; i++) {
                    sb3.Clear();
                    sb3.Append(i.ToString());
                }
                sw.Stop();
                Console.WriteLine($"3) {sw.ElapsedMilliseconds}ms");
            }
        }

結果発表!

<1> Length=0でクリアする <2> 新たなインスタンスを作る <3> Clearを使う
1) 693ms 2) 1440ms 3) 583ms
1) 1303ms 2) 1495ms 3) 503ms
1) 2398ms 2) 1455ms 3) 472ms
1) 3421ms 2) 1401ms 3) 514ms
1) 4656ms 2) 784ms 3) 520ms
1) 5780ms 2) 692ms 3) 500ms
1) 6798ms 2) 580ms 3) 498ms
1) 7786ms 2) 599ms 3) 519ms
1) 8868ms 2) 553ms 3) 485ms
1) 9937ms 2) 643ms 3) 469ms

<1> Length=0でクリアだと、処理速度がどんどん上がっていくので、嫌な感じ。
<2> 新たなインスタンスを作るは、<1>より速くて<3>と同等かもしくは遅いレベル。
<3> Clearを使うのが一番コンスタントに速い。

Javaは試していないので申し訳ないのだが、VC#ならば、用意されているClearメソッドを利用したほうがインスタンスを毎度作るよりは速いということになる。

色々調べてみるものだ、うん。
「無知の知」というのは大事だなぁと思う午後のひと時であった・・・

PostgreSQL覚書 RETURNIG *

UPDATE、INSERT、DELETE文の最後に「RETURNING *」を加えてやると、「更新件数が返ってくる」というのをネット上で見たのだが、厳密にはどうやらそうではないらしいのでメモっておく。

INSERT .... RETURNING *

と書くとINSERTしたデータ行がすべて返ってくるのであって、件数が返ってくるわけではないのだ。
結局、

INSERT .... RETURNING {キー項目}

みたいに書いて、返ってきたデータの行数から更新件数を導きだす必要があるのだ。
だから、Javaなんかだと、SQL文を実行後のResultSetのgetRowメソッドを使う。
例)

int kensu = rs.getRow();

みたいに、返ってきたデータの行数を取得してやるのだ。

中途半端な日本語を書かれると、こういう勘違いをしてしまう。

Struts2覚書 JSP上での変数定義

Struts2でjsp上に変数を定義したいなぁ・・・と思った。
普通はこんな使い方しないんだろうけど、同じ文言が何度も出てくるときに全部直すのは面倒だな、と思ったら、やはりどこかで指定してやるほうが楽だよね!と安易に考え調べた。

 <s:set var="変数名" value="初期値" />

これだ!前にもカウント変数として使ったことがある。
だけど、文字列を設定したことがないんだ。どうすればいい?

<s:set var="baseName" value="'あいうえお'" />

なるほど。ダブルクォーテーションの中にシングルクォーテーションで文字列を括ればよいのか!

Processing覚書 引数付き起動

Processing2.2.1で確認。

Processingで作成したexeを引数渡しで起動させる場合、というので調べてみたが、一番よさげなのは下記のURLの説明とサンプルだと思った。

uncertain world「Processingをコマンドラインから引数つきで実行する方法」

特に良いと感じたのは引数を「xxx=yyyy」という記載で渡すところ。

というのは、Processingで開発中のときにRUNするときと、Exportしてexe起動させるときでは、引数の数が違っている。
前者だと引数の最初に、「–sketch-path=XXXXX」が入っていて、後者だと入らない。
なので、引数の何番目を見て、ウンチャラカンチャラ・・・みたいなことはできない訳。

void setup() {
  for (String a : args) {
   String[] a2 = a.split("=");
   if (a2[0].trim().equals("para1")) {
    ・・・処理・・・  
   } else if (a2[0].trim().equals("para2")) {
    ・・・処理・・・  
   }
  }
}

と、こういう感じで、setupメソッド内に、引数取得処理を入れておく。

起動させるときは、

Prog.exe para1=1 para2=ABC

ってな感じでパラメータを渡してやればよい。

Java覚書 サーバ名からMACアドレスを取得

Windows上で動いている場合にしか利用できない方法だけど、メモ。

JavaでサーバのMACアドレスを簡単に取得する方法を漁ってみたのだが、結局は「ARPコマンドを実行する」ぐらいしかないようである。
なので、ちょっとガックシきてしまった。

1) target に サーバ名を設定。
2) Windowsコマンド arp に、targetサーバのIPアドレスを設定して実行。
3) コマンドプロンプトの出力からtargetサーバのIPアドレスのMACアドレスを取得

    String target = "ここにサーバ名を設定";
    String adr= "";
    try {
      // 1)
      InetAddress ip = InetAddress.getByName(target);
      // 2)
      ProcessBuilder pb = new ProcessBuilder("arp", "-a", ip.getHostAddress());
      pb.redirectErrorStream(true);
      Process proc = pb.start();
      proc.waitFor();
      // 3)
      InputStream is = proc.getInputStream();
      BufferedReader br = new BufferedReader(new InputStreamReader(is));
      try {
        for (;;) {
          String line= br.readLine();
          if (line == null) break;
          if (line.indexOf(ip.getHostAddress()) >= 0) {
            adr = buf.substring(23,45).trim();
          }
        }
      } finally {
        br.close();
      }
      if (res.length() > 0) {
        System.out.println("Server ["+ target+ "] , IP [" + ip.getHostAddress() + "] , MAC [" + adr + "]");
      }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
    }

参考URL
きしだのはてな「JavaでMACアドレスを取得する」
ひしだま’s 技術メモページ「Java > 外部プロセス起動」

Processing覚書 SQLite接続

Processing開発。
BezierSQLibライブラリを使ってSQLiteのDBにつないでいるのだが、1つ問題が。

というのも、エラーになったときExceptionが発生しない。
ライブラリ内部で例外処理までしてるのは兎も角、結果がエラーになってもエラーを判別できるフラグがない。
DBにLockがかかってる時にUPDATEしても、コンソールにエラーメッセージは出るが、それだけ・・・
Rollbackするタイミングがつかめない。
このままではマズイ。困った。

こうなったら、直接jdbcライブラリを利用しよう!となった。

プログラムソースのpdeファイルが入っているフォルダの下に「data」フォルダを作って、その中にDBファイルの「test.db」を入れる。
「data」フォルダと同じ並びに「code」フォルダを作って、その中にライブラリ「sqlite-jdbc-***.jar」ファイルを入れておく。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

// ------------------- ( 略 ) -------------------

void getData() {
  Connection con = null;
  Statement stmt = null;
  try {
    Class.forName("org.sqlite.JDBC");
    con = DriverManager.getConnection("jdbc:sqlite:"+ dataPath("test.db"));
    println("Opened database successfully");
    
    stmt = con.createStatement();
    stmt.executeUpdate("INSERT INTO m_users (user_cd ,user_name) VALUES ('1010101', 'Lily');");
    stmt.close();
    con.close();
  } catch ( Exception e ) {
    println( e.getClass().getName() + ":" + e.getMessage());
  }
}

Macでいけたから、あとはWindowsでも確認しよう。

Java覚書 ExcelのSLOPE関数をJava化してみる

回帰直線の傾きを求めるExcelのSLOPE関数をJavaで作成してみる。

public class Main {
    public static void main(String[] args) throws Exception {
        // y値のみで、かつ、int型
        int y[] = new int[]{70,80,30,40,50,20};
        slope(y);
        // x,y値で、かつ、float型
        float[][] xy = { {2.5F,10.3F}
                        , {3.0F,24.3F}
                        , {3.2F,30.5F}
                        , {5.0F,42.5F}
                        , {6.1F,53.4F}
                        , {8.9F,48.8F}
                       };
        slope(xy);
    }
    
    // 回帰直線の傾きを算出(int型 y値のみ渡す)
    static float slope(int val[]) {
        float[][] f = new float[val.length][2];
        int i = 0;
        for(int v : val) {
            f[i][0] = (float)i;
            f[i][1] = (float)v;
            i++;
        }
        return slope(f);
    }
    
    // 回帰直線の傾きを算出(float型 x, y値を渡す)
    static float slope(float[][] val) {
    float sumX = 0;
    float sumY = 0;
    float sumXX = 0;
    float sumXY = 0;
    float n = val.length;
    for(int i = 0; i < val.length; i++){
       float x = (float)val[i][0];
       float y = (float)val[i][1];
       sumX += x;
       sumY += y;
       sumXX += x*x;
       sumXY += x*y;
     }
     System.out.println("a : " + (float) (n*sumXY-sumX*sumY)  / (float) (n*sumXX-sumX*sumX));
     System.out.println("b : " + (float) (sumXX*sumY - sumXY*sumX) / (float) (n*sumXX - sumX*sumX));
     return (float) (n*sumXY-sumX*sumY)  / (float) (n*sumXX-sumX*sumX);
    }
}

Processing3 Javaで動かしてみる

Processingで作成したpdeファイルをJavaにしてみようと思ったが、うまくいかないので、基本的なところから少しずつ試していく。

Processing3を入れて、JRE1.8をいれて、Eclipse上でごねごね。
ネットで調べたとおり、setupのところにsizeメソッドを入れたら怒られて、しょうがないからsettingsメソッドをつくってそっちに入れたら、なんか足りん!と怒られて、こんな感じにしたら、とりあえず斜めに線は引けた。

package test;

import processing.core.PApplet;

public class Test extends PApplet {

	public void settings() {
		size(600, 600, JAVA2D);
	}
	public void setup() {
		background(200, 50, 60);
		smooth();
		strokeWeight(5);
	}

	public void draw() {
		line(0, 0, width, height);
	}

	public static void main(String _args[]) {
		PApplet.main(new String[] { test.Test.class.getName() });
	}
}

先は長そうだ。

Java覚書 月加算・月末

月末を出すときは、加算前の日を1日にしておいて、加算後-1日するのが自分の常套手段。
(どの言語でも大体このロジックは使えるし)

import java.util.Calendar;

public class Main {
    public static void main(String[] args) throws Exception {

        // 指定日からnヶ月後の月末を出力
        int y = 2012;
        int m = 12;
        int d = 14;
        int n = 2;
        
        Calendar cal = Calendar.getInstance();

        cal .set(y,m - 1, d);
        dispDate(calendar);
    
        cal .set(y,m - 1, 1);
        cal .add(Calendar.MONTH, n + 1);
        cal .add(Calendar.DATE, -1);
        dispDate(cal);
    }

  private static void dispDate(Calendar cal ){
    int year = cal .get(Calendar.YEAR);
    int month = cal .get(Calendar.MONTH) + 1;
    int day = cal .get(Calendar.DATE);

    StringBuffer sb = new StringBuffer();
    sb.append(year + "年" + month + "月" + day + "日");
    
    System.out.println(new String(sb));

    }
}

Struts2 ForとかDoとかWhileとか・・・

まぁとりあえず、ぐるぐる回したいときね。

あるんですよ。

鍵のついたキーホルダーの端っこを指にはめ込んで、鍵をぐるぐる意味もなく回したりね。

いや、そんな話でなくて・・・iterator

ソフトウェア技術ドキュメントを勝手に翻訳 iterator

ex) 1,2,3,4,5と順に・・・

<s:iterator status=”stat” value=”{1,2,3,4,5}” >

これなんかは、{1,3,6,10} とか括弧の中身を変えてしまうと、また違った使い方ができる。

ex) とりあえず5回

<s:iterator status=”stat” value=”(5).{ #this }” >

(5)ってところを変数つかって(data_max)とかできちゃうよね。

って、forつくりゃいいじゃんか!って思うんだけどね。
まぁ、人それぞれ、言語もそれぞれってことです。

Java覚書 LinkedHashMap繰り返し

HashMapの繰り返し処理の方法

// LinkedHashMapの繰り返し(同値が見つかったらキーを返す)
private String getKey(LinkedHashMap<String,String> hmap
			, String targetVal) {
	for (Map.Entry<String, String> ent : hmap.entrySet()) {
		if (ent.getValue().toString().equals(targetVal)) {
			return ent.getKey().toString();
		}
	}
	return null;
}