Java Tips
Total: 22115
, Today: 3
, Yesterday: 3
Posted by aterai at
Last-modified:
概要
JDK
のインストール、Java Swing
のデバッグ方法、環境変数で実行するjava.exe
を切り替えるバッチファイルなどのメモの一覧です。
Ubuntu に、oracle-java8 をインストール
apt-get install
でインストール
sudo add-apt-repository ppa:webupd8team/java sudo apt-get update sudo apt-get install oracle-java8-installer sudo update-alternatives --config javac
tar.gz
をダウンロードしてインストール- Java SE Downloadsから、
jdk-8uxx-linux-xxxx.tar.gz
をダウンロード
- Java SE Downloadsから、
sudo tar zxvf jdk-8u66-linux-i586.tar.gz -C /usr/lib/jvm
export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_66 export PATH=$PATH:$JAVA_HOME/bin
Swing debug agent
- Swingコンポーネントの再描画をJXLayerのDebugPainterを使ってデバッグ
JXLayer
のDebugPainter
を使ってコンポーネントの再描画を可視化するjavaagent
を作成してデバッグを実行
- SwingアプリケーションのLookAndFeelを外部から切り替える
Swing
アプリケーションのLookAndFeel
をagent
を使って外部から切り替えてデバッグを実行
-g
オプションを使用してコンパイル
NetBeans
でソースにブレークポイントを設定し、Swing
コンポーネントのソースにステップインすると、「変数の情報を使用できません。ソースは-g
オプションを使用せずにコンパイルされています」と表示され、値は不明となる- javac
-g
オプション-g ローカル変数を含むすべてのデバッグ情報を生成します。デフォルトでは、行番号およびソース・ファイル情報だけが生成されます。
- java - debug jdk source can't watch variable what it is - Stack Overflowを参考に、
%JAVA_HOME%/src.zip/javax/swing
以下のソースをコピーし、以下のようなバッチを実行@echo off setlocal rem set RT_JAR=%JAVA_HOME%\jre\lib\rt.jar set RT_JAR=rt.jar dir /B /S /X src\*.java > filelist.txt "%JAVA_HOME%\bin\javac" -g -classpath "%RT_JAR%" -sourcepath src -d debug @filelist.txt > log.txt 2>&1 "%JAVA_HOME%\bin\jar" cf0 rt_debug.jar debug/*
- 生成された
rt_debug.jar
を、%JAVA_HOME%\lib\endorsed
(なければ管理者になって作成)にコピー- Java推奨標準優先メカニズム
- 「この機能は非推奨であり、今後のリリースで削除される予定です。」、
JDK 9
では使用できない?
その他
- 環境変数JAVA_HOMEを変更して使用するJDKを切り替える
- 環境変数
JAVA_HOME
を変更するバッチファイルを作成して、コマンドプロンプトで使用するJDK
を切り替える
- 環境変数
- Rhinoでgoogle-prettify.jsを実行する
Rhino
でgoogle-prettify.js
を実行し、ソースコードをハイライトされたHtml
(google sites
用)に変換する
- JNIでJFrameのHWNDを取得
JNI
(Java Native Interface
)でJFrame
(SunAwtFrame
)のHWND
(ウィンドウハンドル)を取得する
- Java API Doc の「日本語、英語」をブックマークレットで切り替える
環境変数
- http://cr.openjdk.java.net/~gbenson/zero-08/raw_files/new/hotspot/src/share/vm/utilities/vmError.cpp
// List of environment variables that should be reported in error log file. const char *env_list[] = { // All platforms "JAVA_HOME", "JRE_HOME", "JAVA_TOOL_OPTIONS", "_JAVA_OPTIONS", "CLASSPATH", "JAVA_COMPILER", "PATH", "USERNAME", // Env variables that are defined on Solaris/Linux "LD_LIBRARY_PATH", "LD_PRELOAD", "SHELL", "DISPLAY", "HOSTTYPE", "OSTYPE", "ARCH", "MACHTYPE", // defined on Linux "LD_ASSUME_KERNEL", "_JAVA_SR_SIGNUM", // defined on Windows "OS", "PROCESSOR_IDENTIFIER", "_ALT_JAVA_HOME_DIR", (const char *)0 };
コマンドプロンプトからデフォルトのロケールを変更
> javac -J-Duser.language=en Test.java
> java -Duser.language=en Test
- 国際化についての FAQ
アプリケーションの外部からデフォルトのロケールを設定できますか。 使用している Java プラットフォームの実装によって異なります。通常、初期のデフォルトロケールは、ホストオペレーティングシステムのロケールによって決まります。Sun の JRE のバージョン 1.4 以降では、コマンド行から user.language、user.country、および user.variant の各システムプロパティを設定することで、初期のデフォルトロケールを変更できます。たとえば、初期のデフォルトロケールとして Locale("th", "TH", "TH") を選択するには、次のコマンドを使用します。 java -Duser.language=th -Duser.country=TH -Duser.variant=TH MainClass この機能を使用できない実行環境もあるため、この機能はテスト目的だけに使用してください。
コード整形
個人的に、Java
のソースコードのインデントは、エディタでは4space
、Web
サイトにソースコードを表示する場合は2space
にしているので、xyzzy
のfilter-buffer
(C-x #
)でastyle
を呼び出して以下のように整形。
astyle --style=java --mode=java --indent=spaces=2
コマンドラインなどから、ファイルを指定する場合も同様。
> astyle --style=java --mode=java --indent=spaces=4 MainPanel.java
Markdown
形式のStack Overflow
などにソースコードを貼り付ける場合は、以下のようにして、行頭にタブ(またはスペース4
つ)を追加。
astyle --style=java --mode=java --indent=spaces=2 < Hoge.java | sed -e "s/^\(.*\)$/\t\1/" > /dev/clipboard astyle --style=java --mode=java --indent=spaces=2 | sed -e "s/^\(.*\)$/\t\1/" astyle --style=java --mode=java --indent=spaces=2 | sed -e "s/\A\(.*\)\z/ \1/"
astyle
astyle --style=java --mode=java --indent=spaces=4 --pad-oper --pad-header --unpad-paren
キャストの後にスペースを入れる方法は?
int h = (int)(.5 + baseline / height); //(int)の後に空白を入れたい... int h = (int) (.5 + baseline / height);
asyle 2.04
$ astyle --version Artistic Style Version 2.04
- 以下の様なソースコード(最後の
}
の直後にEOF
)をastyle
で変換すると、余計な}
が追加される?
class Hoge
{
public static void main(String[] args)
{
System.out.println("aaaaaaa");
}
}
- Artistic Style / Bugs / #305 Last character always repeated in output when reading from stdin
次バージョンで修正される模様修正済み
FileInputStream / FileOutputStream でメモリリーク
- 恐怖の JVM 大量メモリ消費!メモリリークの謎を追え!! - Cybozu Inside Out | サイボウズエンジニアのブログ
- JDK-8080225 FileInputStream cleanup should be improved. - Java Bug System
- FileInputStream / FileOutputStream Considered Harmful | CloudBees
- via: Inspired by Actual Events: Java Finalizer and Java File Input/Output Streams
FileInputStream
やFileOutputStream
は、finalize()
メソッドをオーバーライドしている(FinalReference
に登録されてしまう)のでclose()
メソッドを呼んだ後でもフルGC
が発生するまでメモリ上に残り続けるFiles.newInputStream(...)
やFiles.newOutputStream(...)
に置き換える必要がある
- FileInputStream / FileOutputStream Considered Harmful : java
Files.newInputStream(...)
(ChannelInputStream
?)はskip()
がすこし遅いらしい?
ClassLoader#getResourceAsStream(...)
は?
偶数・奇数の判断
public class EvenOddTest {
public static void main(String... args) {
for (int i = 0; i < 5; i++) {
if (i % 2 == 0) {
System.out.format("%d is even%n", i);
} else {
System.out.format("%d is odd%n", i);
}
if ((i & 1) == 0) { // ビット演算子の & は、== より優先順位が低いので(i & 1)と囲む必要がある
System.out.format("%d is even%n", i);
} else {
System.out.format("%d is odd%n", i);
}
}
}
}
正の数と負の数を反転
- How do you Invert signed numbers? | Oracle Community
- 15.15.4. Unary Minus Operator - / Chapter 15. Expressions
public class InvertSignedNumbersTest {
private static void print(int i) {
System.out.println(i);
System.out.format(" :%d\n", -i);
System.out.format(" :%d\n", ~i + 1);
System.out.format(" :%d\n", (i > 0 ? -1 : 1) * Math.abs(i));
System.out.format(" :%d\n", ~--i);
}
public static void main(String... args) {
print(256);
print(-256);
print(0);
print(-0);
print(Integer.MAX_VALUE);
print(Integer.MIN_VALUE + 1);
print(Integer.MIN_VALUE);
}
}
Objects.compare(...)
/**
* Returns 0 if the arguments are identical and {@code
* c.compare(a, b)} otherwise.
* Consequently, if both arguments are {@code null} 0
* is returned.
*
* <p>Note that if one of the arguments is {@code null}, a {@code
* NullPointerException} may or may not be thrown depending on
* what ordering policy, if any, the {@link Comparator Comparator}
* chooses to have for {@code null} values.
*
* @param <T> the type of the objects being compared
* @param a an object
* @param b an object to be compared with {@code a}
* @param c the {@code Comparator} to compare the first two arguments
* @return 0 if the arguments are identical and {@code
* c.compare(a, b)} otherwise.
* @see Comparable
* @see Comparator
*/
public static <T> int compare(T a, T b, Comparator<? super T> c) {
return (a == b) ? 0 : c.compare(a, b);
}
- java - What is the purpose of the Objects.compare() method? - Stack Overflow
- 確かに
Objects.compare(...)
の使いどころが分からない TableSorter.java
の以下のようなコードが短くなるか?と考えたが、//@see https://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableSorterDemoProject/src/components/TableSorter.java public int compareTo(Object o) { int row1 = modelIndex; int row2 = ((Row) o).modelIndex; for (Iterator it = sortingColumns.iterator(); it.hasNext();) { Directive directive = (Directive) it.next(); int column = directive.column; Object o1 = tableModel.getValueAt(row1, column); Object o2 = tableModel.getValueAt(row2, column); int comparison = 0; // Define null less than everything, except null. if (o1 == null && o2 == null) { comparison = 0; } else if (o1 == null) { comparison = -1; } else if (o2 == null) { comparison = 1; } else { comparison = getComparator(column).compare(o1, o2); } if (comparison != 0) { return directive.direction == DESCENDING ? -comparison : comparison; } } return 0; }
- 確かに
- 以下のように
Objects.compare(...)
を使用すると、テーブルモデルの値にnull
が存在する場合、ソートでNullPointerException
が発生する - Java Comparatorメモ(Hishidama's Java Comparator Memo)を参考に、
Comparator.nullsFirst(comparator)
と合わせて使用すれば、NullPointerException
は発生しない
//@see https://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableSorterDemoProject/src/components/TableSorter.java
public int compareTo(Object o) {
int row1 = modelIndex;
int row2 = ((Row) o).modelIndex;
for (Iterator it = sortingColumns.iterator(); it.hasNext();) {
Directive directive = (Directive) it.next();
int column = directive.column;
Object o1 = tableModel.getValueAt(row1, column);
Object o2 = tableModel.getValueAt(row2, column);
@SuppressWarnings("unchecked")
Comparator<Object> comparator = getComparator(column);
int comparison = Objects.compare(o1, o2, comparator);
//int comparison = Objects.compare(o1, o2, Comparator.nullsFirst(comparator));
if (comparison != 0) {
return directive.direction == DESCENDING ? ~comparison + 1 : comparison;
}
}
return 0;
}
無名匿名クラスとラムダ式の中でのthisキーワード
- 15.27.2. Lambda Body - Chapter 15. Expressions
- Javaラムダ式メモ(Hishidama's Java8 Lambda Expression Memo)
- 単純に無名匿名クラスをラムダ式に置き換えると、「
static
でないメソッドgetClass()
をstatic
コンテキストから参照することはできません」とコンパイルエラーになる場合があるMainPanel.java:43: error: non-static method getClass() cannot be referenced from a static context splashScreen.getContentPane().add(new JLabel(new ImageIcon(getClass().getResource("splash.png"))));
- 無名匿名クラス中の
this
キーワードは、無名匿名クラスのインスタンスを指すが、ラムダ式はラムダ式を定義したメソッドが属しているクラスのインスタンスを指すため
- 無名匿名クラス中の
this.getClass()
ではなく、MainPanel.class.getClass()
のようにclass
リテラルを使用して回避
import java.awt.*;
import java.beans.*;
import javax.swing.*;
public final class MainPanel extends JPanel {
private MainPanel() {
super(new BorderLayout());
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
add(new JScrollPane(new JTree()));
setPreferredSize(new Dimension(320, 240));
}
public static void main(String... args) {
/*
final JFrame frame = new JFrame();
final JDialog splashScreen = new JDialog(frame, Dialog.ModalityType.DOCUMENT_MODAL);
final JProgressBar progress = new JProgressBar();
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
splashScreen.setUndecorated(true);
splashScreen.getContentPane().add(new JLabel(new ImageIcon(getClass().getResource("splash.png"))));
splashScreen.getContentPane().add(progress, BorderLayout.SOUTH);
splashScreen.pack();
splashScreen.setLocationRelativeTo(null);
splashScreen.setVisible(true);
}
});
/*/
JFrame frame = new JFrame();
JDialog splashScreen = new JDialog(frame, Dialog.ModalityType.DOCUMENT_MODAL);
JProgressBar progress = new JProgressBar();
EventQueue.invokeLater(() -> {
splashScreen.setUndecorated(true);
splashScreen.getContentPane().add(new JLabel(new ImageIcon(MainPanel.class.getResource("splash.png"))));
//NG: splashScreen.getContentPane().add(new JLabel(new ImageIcon(getClass().getResource("splash.png"))));
splashScreen.getContentPane().add(progress, BorderLayout.SOUTH);
splashScreen.pack();
splashScreen.setLocationRelativeTo(null);
splashScreen.setVisible(true);
});
//*/
SwingWorker<Void, Void> worker = new Task() {
@Override public void done() {
splashScreen.dispose();
}
};
worker.addPropertyChangeListener(e -> {
if ("progress".equals(e.getPropertyName())) {
progress.setValue((Integer) e.getNewValue());
}
});
worker.execute();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
EventQueue.invokeLater(() -> frame.setVisible(true));
}
}
class Task extends SwingWorker<Void, Void> {
@Override public Void doInBackground() {
int current = 0;
int lengthOfTask = 120;
while (current < lengthOfTask && !isCancelled()) {
try {
Thread.sleep(50);
} catch (InterruptedException ie) {
ie.printStackTrace();
return null;
}
setProgress(100 * current++ / lengthOfTask);
}
return null;
}
}
Launch Single-File Source-Code Programs
Java 11
では、1
つの.java
ファイルをjava
コマンドで実行可能になった- 例えば以下のようなコードを
./TreeRootVisible/src/java/example/MainPanel.java
に生成した場合、package
は考慮しなくても実行可能:
package example;
import java.awt.*;
import javax.swing.*;
public final class MainPanel extends JPanel {
private MainPanel() {
super(new BorderLayout());
JTree tree = new JTree();
tree.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
tree.setRootVisible(false);
JCheckBox check = new JCheckBox("JTree#setRootVisible(...)");
check.addActionListener(e -> tree.setRootVisible(((JCheckBox) e.getSource()).isSelected()));
add(check, BorderLayout.NORTH);
add(new JScrollPane(tree));
setPreferredSize(new Dimension(320, 240));
}
public static void main(String... args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
createAndShowGui();
}
});
}
public static void createAndShowGui() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
Toolkit.getDefaultToolkit().beep();
}
JFrame frame = new JFrame("@title@");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
> sdk use java 11.0.3-amzn
> cd ./TreeRootVisible/src/java/example/
> java MainPanel.java # OK
> cd ..
> java example/MainPanel.java # OK
- 画像などのリソースを
.java
ファイルと同じディレクトリに配置し、ImageIcon icon = new ImageIcon(getClass().getResource("test.png"));
で参照する場合:
> sdk use java 11.0.3-amzn
> cd ./Zoom/src/java/example/
> ls
MainPanel.java test.png
> java MainPanel.java # NG
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
> cd ..
> java example/MainPanel.java # OK
コメント
}}