BigDecimalがゼロかどうか?
BigDecimalがゼロかどうかの判定が意外とめんどくさいのと、
やりかたがいろいろあるので記事書くことにしました。
ダメなやり方
BigDecimal value = new BigDecimal("0.0"); if ( value.equals(BigDecimal.ZERO) ) System.out.println("true"); else System.out.println("false");
scaleが違うと一致とみなさないのでうまくいかない。
(scaleまで比較してほしいなら正しい)
よく見るやり方※1
BigDecimal value = new BigDecimal("0.0"); if ( value.compareTo(BigDecimal.ZERO)==0 ) System.out.println("true"); else System.out.println("false");
これだとscale関係なく0かどうか判定で来てハッピー!
さらに、
今日見つけたやり方※2
BigDecimal value = new BigDecimal("0.0"); if ( value.signum()==0 ) System.out.println("true"); else System.out.println("false");
※1と結果は同じ。
速度的にはcompareTo:signum⇒10:6ぐらいの感じだった。
ゼロかどうか?正かどうか?負かどうか?を判定するならsignum()使った方が速いっぽい。
ただ職場で使うなら何やってるかわかりやすいcompareTo使う*1かなー。
*1:日本語にしたらそれぞれcompareToは「ZEROと比べて差がないなら0」signumは「符号がなければ0」だから前者の方がまだマシかと。
javaで円グラフの描画(awtで描画)
参考はこちら
Javaサンプルソース【アンチエイリアスで円グラフをきれいに表示】『愛のJava256本ノック』
JAVAについて質問です☆JFrameを使って円グラフを作... - Yahoo!知恵袋
import static java.awt.RenderingHints.KEY_ANTIALIASING; import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.util.Random; public class PieChartPainter { private final Random r = new Random(); /** * 円グラフ描画 * * @param graphics * @param pieSize * 円グラフ直径 * @param width * 描画範囲幅 * @param height * 描画範囲高さ * @param data * グラフデータ */ public void paint(Graphics graphics, int pieSize, int width, int height, int[] data) { if (graphics instanceof Graphics2D) { // アンチエイリアス ((Graphics2D) graphics).setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON); } // 配列の和 int sum = sum(data); // 割合計算 int tmp[] = new int[data.length]; for (int i = 0; i < data.length; i++) { tmp[i] = (int) (((double) data[i] / sum) * 360.0); } // 誤差調整 int cnt = 0; while (sum(tmp) != 360) { try { tmp[cnt++] += 1; } catch (Exception e) { break; } } // グラフ描画 sum = 90; for (int i = 0; i < tmp.length; i++) { graphics.setColor(getColor(i)); // 描画 graphics.fillArc((width / 2) - (pieSize / 2), (height / 2) - (pieSize / 2), pieSize, pieSize, sum, -tmp[i]); sum -= tmp[i]; } } private int sum(int data[]) { int sum = 0; for (int element : data) { sum += element; } return sum; } protected Color getColor(int index) { return new Color(r.nextInt(0xff), r.nextInt(0xff), r.nextInt(0xff)); } }
import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.util.Arrays; import java.util.Random; import javax.swing.JFrame; import javax.swing.JPanel; public class Sample extends JFrame { class SamplePanel extends JPanel { public static final int WIDTH = 400; public static final int HEIGHT = 400; private final Random r = new Random(); private final int SIZE = 300; SamplePanel() { setPreferredSize(new Dimension(WIDTH, HEIGHT)); setBackground(Color.WHITE); } /** * paintComponent() */ @Override public void paintComponent(Graphics g) { super.paintComponent(g); int[] data; { int cnt = r.nextInt(10) + 2; int[] tmp = new int[cnt]; for (int i = 0; i < tmp.length; i++) { tmp[i] = r.nextInt(100); } Arrays.sort(tmp); data = new int[cnt]; for (int i = 0; i < data.length; i++) { data[i] = tmp[data.length - i - 1]; } } PieChartPainter painter = new PieChartPainter(); painter.paint(g, SIZE, WIDTH, HEIGHT, data); } } Sample() { add(new SamplePanel()); pack(); setTitle("円グラフ"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); setVisible(true); } /** * 実行 */ public static void main(String[] args) { new Sample(); } }
特定の扇だけ切り離したい。
こういうの
/** * 円グラフ描画 * * @param graphics * @param pieSize * 円グラフ直径 * @param width * 描画範囲幅 * @param height * 描画範囲高さ * @param data * グラフデータ * @param highlightIndex * indexの扇だけ離す */ public void paint(Graphics graphics, double pieSize, double width, double height, int[] data, int highlightIndex) { if (graphics instanceof Graphics2D) { // アンチエイリアス ((Graphics2D) graphics).setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON); } // 配列の和 int sum = sum(data); // 割合計算 int tmp[] = new int[data.length]; for (int i = 0; i < data.length; i++) { tmp[i] = (int) (((double) data[i] / sum) * 360.0); } // 誤差調整 int cnt = 0; while (sum(tmp) != 360) { try { tmp[cnt++] += 1; } catch (Exception e) { break; } } // グラフ描画 sum = 90; for (int i = 0; i < tmp.length; i++) { graphics.setColor(getColor(i)); if (i == highlightIndex) { // highlight int c = sum - (tmp[i] / 2); double r = Math.toRadians(c); double addX = (Math.cos(r) * pieSize) / 20;// 1/20離す double addY = (Math.sin(r) * pieSize) / 20;// 1/20離す // 描画 graphics.fillArc((int) (((width / 2) - (pieSize / 2)) + addX), (int) (((height / 2) - (pieSize / 2)) - addY), (int) pieSize, (int) pieSize, sum, -tmp[i]); } else { // 描画 graphics.fillArc((int) ((width / 2) - (pieSize / 2)), (int) ((height / 2) - (pieSize / 2)), (int) pieSize, (int) pieSize, sum, -tmp[i]); } sum -= tmp[i]; } }
Enumのabstract method
javaのEnumってabstract methodが書けるね。
こんなのだね。
public class Otameshi { public enum E { A { @Override void method() { System.out.println("A method"); } }, B { @Override void method() { System.out.println("B method"); } }; abstract void method(); } public static void main(String[] args) { for (E e : E.values()) { e.method(); } } }
で、なんとなく気になってクラスファイルを覗いたら案の定クラスがEnum宣言分増えてたよ。
つまり、
public class Otameshi { public enum E { A { @Override void method() { System.out.println("A method"); } }, B { @Override void method() { System.out.println("B method"); } }; abstract void method(); } public static void main(String[] args) { for (E e : E.values()) { System.out.println(e.getClass()); } } }
ってやると
class Otameshi$E$1
class Otameshi$E$2
ってなる。
try-with-resourcesと等価コード
try-with-resourcesの使い方を昨日初めて知りましたorz
残念なあまりバイトコードまで読んで等価のコードを読み取ってみたよ*1。
とりあえず
try (InputStream input = new FileInputStream("ファイル.txt")) { // 処理 }
な書き方ができるのがtry-with-resources
いままでは
InputStream input = new FileInputStream("ファイル.txt"); try { // 処理 } finally { input.close(); }
って書いてたね*2。
でもこの二つは等価じゃないみたい。
バイトコードから読み取った感じだと、
Throwable e1 = null; Throwable e2 = null; try { InputStream input = new FileInputStream("ファイル.txt"); try { // 処理 } catch (Throwable e) { e1 = e; throw e1; } finally { if (input != null) { input.close(); } } } catch (Throwable e) { e2 = e; if (e1 == null) { e1 = e2; } else { if (e1 == e2) { e1.addSuppressed(e2); } } throw e1; }
のような感じ。
#超厳密にいうと、変数宣言*3とtry catch finallyの範囲の指定*4がjavaコードから書くのはたぶん不可能だったりする。
基本的にバイトコードのほうが効率的になっている
org.eclipse.jface.text.rules.IRule
EclipseプラグインのEditor作るとき色つけたくて
ScannerでIRuleをポイポイぶっこんだので、
使って覚えたことを書きます。*1
標準クラス
NumberRule | 数字文字列のルール |
WordRule | 指定文字列のルール 使い方はこっち見るといい Eclipseプラグイン DMDLEditor キーワード(Hishidama's Eclipse Plugin DMDLEditor Memo) |
MultiLineRule | 開始文字と終了文字を指定したルール。行を跨いでscanする |
SingleLineRule | 開始文字と終了文字を指定したルール。こっちは行を跨がない |
WhitespaceRule | 空白のルール。スキップとかに使うのかな? |
自力で作った場合
evaluateで対象文字数分scanner.read()して、
対象だったらそのままITokenを返す。
そうするとevaluateに入ってきた文字列indexから
index+(scanner.read()回数分)までの文字をITokenで装飾してくれる。
対象でなければ、scanner.unread();で開始文字まで戻して、
Token.UNDEFINEDでも返しておく。(たぶん何でもいい)
scanner.unread()で正しく戻さないと、次のルールの開始位置がずれたりしちゃうので注意。
一文字(?マーク)だけ判断するクラスを張ってみる。
public class QuestionRule implements IRule { protected IToken fToken; public QuestionRule(IToken token) { Assert.isNotNull(token); fToken = token; } /* * @see IRule#evaluate(ICharacterScanner) */ @Override public IToken evaluate(ICharacterScanner scanner) { int c = scanner.read(); if (c == '?') { return fToken; } scanner.unread(); return Token.UNDEFINED; } }
Eclipseプラグインで作ったEditorで外部ファイルを開きたい。
普通に「エディター付きプラグイン」で作ったエディタだとプロジェクト外のファイル開くとエラーになる。
TextEditorから継承されたクラスの
setDocumentProvider(new TextFileDocumentProvider());
にしたら行けた。
IDocumentPartitionerが設定できなくなるけど、
僕は今、IDocumentPartitionerの使い道がわからないので別に困らない。
Eclipseプラグイン作成
最近、Eclipseプラグインを作った。
とりあえず初歩の初歩だけど、jarにするまでの手順を書く。
(使ってるのはEclipse3.7の日本語化です。)
プロジェクトを作る
Eclipseから、
「ファイル」→「新規」→「プラグイン・プロジェクト」
「プロジェクト名」を決めて「次へ」。
「ID」に適当にいれる。(アクティベーターのパッケージ名とかにするといい感じかも。)
「名前」に何プラグインなのかいれる。
「アクティベーター*1」にプラグインのアクティベータークラス名をいれる。
「次へ」。
次に選ぶのはテンプレート。
テンプレートを選んで作成すればかなり簡単に始められる。
いくつか試した奴だけ下記に説明する。
インクリメンタル・プロジェクト・ビルダー付きプラグイン | Eclipseのビルドに乗っけて何かやれるプラグインを作るならここから始めるのがいい。 |
エディター付きプラグイン | 何かのファイルのエディターを作るならここから始めるのがいい。 |
ビュー付きプラグイン | Eclipseの「ウィンドウ」→「ビューの表示」で出てくるビューを作るならここから始めるのがいい。 |
Hello,Worldコマンド | Eclipseのメニュー・ツールバーにアクションを乗っけたいならここから始めるのがいい。 |
カスタム・プラグイン・ウィザード | 複合的にいろんなテンプレートをいっぺんに使いたい場合はここから始める。 普通のテンプレートには無い「設定ページ」があったりする。 (実は後でどうにでもなるので、作る範囲が決まってなければメイン部分のテンプレートで始めるといい) |
この次は、どのテンプレートを選んだかで入力項目が違うので勘で入れてく。
どうしてもわからなければ、一旦捨てプロジェクト作って試すといいと思う。
「完了」するとプロジェクトができてる。
javaじゃないファイル
いくつかよくわからないファイルができてると思う。
基本的にはEclipseさんがUIで入力できるようにしてくれているので
気にせず突き進んでもいいけど、
一応なんとなくわかることだけ書く。
MANIFEST.MF | プラグインのIDとか名前とか持ってる。 他には、入ってなきゃいけないプラグイン(依存関係)とか jar使ったりするならここに書かれる。 |
plugin.xml | どんなプラグイン拡張があるか、それぞれどのクラスで動くか、ここに書いてある。 エディターがあって、このクラスですよ。とか、 ビューがあって、このクラスですよ。とか。 |
build.properties | たぶんエクスポートの時に必要。 「javacDefaultEncoding.. = UTF-8」って追記しないと プラグインのエクスポートでエラー*2になることがある。 |
デバッグ
plugin.xml(MANIFEST.MF)をダブルクリックすると、
プラグイン情報用のUIがエディタ領域に出てくる。
「概要」タブの右チョイ下に
「Eclipseアプリケーションをデバッグモードで起動」をクリックするとデバッグできる。