---
title: Java Tips
author: aterai
keywords: [Java, install, JAVA_HOME]
description: JDKのインストール、Java Swingのデバッグ方法、環境変数で実行するjava.exeを切り替えるバッチファイルなどのメモ
pubdate: 2011-01-25
---
#contents

* 概要 [#summary]
`JDK`のインストール、`Java Swing`のデバッグ方法、環境変数で実行する`java.exe`を切り替えるバッチファイルなどのメモの一覧です。

* Ubuntu に、oracle-java8 をインストール [#JdkInUbuntu]
- `apt-get install`でインストール
-- [http://www.webupd8.org/2012/01/install-oracle-java-jdk-7-in-ubuntu-via.html Install Oracle Java 7 in Ubuntu via PPA Repository ~ Web Upd8: Ubuntu / Linux blog]

 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`をダウンロードしてインストール
-- [http://www.oracle.com/technetwork/java/javase/downloads/index.html Java SE Downloads]から、`jdk-8uxx-linux-xxxx.tar.gz` をダウンロード

 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[#DebugPainterAgent]
- [[Swingコンポーネントの再描画をJXLayerのDebugPainterを使ってデバッグ>Tips/DebugPainterAgent]]
-- `JXLayer`の`DebugPainter`を使ってコンポーネントの再描画を可視化する`javaagent`を作成してデバッグを実行
- [[SwingアプリケーションのLookAndFeelを外部から切り替える>Tips/LookAndFeelDebugAgent]]
-- `Swing`アプリケーションの`LookAndFeel`を`agent`を使って外部から切り替えてデバッグを実行

* `-g`オプションを使用してコンパイル [#DebugWatchVariable]
- `NetBeans`でソースにブレークポイントを設定し、`Swing`コンポーネントのソースにステップインすると、「変数の情報を使用できません。ソースは `-g`オプションを使用せずにコンパイルされています」と表示され、値は不明となる
- [https://docs.oracle.com/javase/jp/8/docs/technotes/tools/windows/javac.html javac] `-g`オプション
 -g ローカル変数を含むすべてのデバッグ情報を生成します。デフォルトでは、行番号およびソース・ファイル情報だけが生成されます。
- [https://stackoverflow.com/questions/18255474/debug-jdk-source-cant-watch-variable-what-it-is java - debug jdk source can't watch variable what it is - Stack Overflow]を参考に、`%JAVA_HOME%/src.zip/javax/swing`以下のソースをコピーし、以下のようなバッチを実行
#code{{
@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`(なければ管理者になって作成)にコピー
-- [https://docs.oracle.com/javase/jp/8/docs/technotes/guides/standards/index.html Java推奨標準優先メカニズム]
-- 「この機能は非推奨であり、今後のリリースで削除される予定です。」、`JDK 9`では使用できない?

* その他 [#etc]
- [[環境変数JAVA_HOMEを変更して使用するJDKを切り替える>Tips/SetJAVA_HOME]]
-- 環境変数`JAVA_HOME`を変更するバッチファイルを作成して、コマンドプロンプトで使用する`JDK`を切り替える
- [[Rhinoでgoogle-prettify.jsを実行する>Tips/GooglePrettifyRhino]]
-- `Rhino`で`google-prettify.js`を実行し、ソースコードをハイライトされた`Html`(`google sites`用)に変換する
- [[JNIでJFrameのHWNDを取得>Tips/JNI_HWND]]
-- `JNI`(`Java Native Interface`)で`JFrame`(`SunAwtFrame`)の`HWND`(ウィンドウハンドル)を取得する
- Java API Doc の「日本語、英語」をブックマークレットで切り替える
-- [[Java API Doc の「日本語、英語」をブックマークレットで切り替える>JavaScript/APIDocEnJa]]に移動

* 環境変数 [#EnvironmentVariables]
- http://cr.openjdk.java.net/~gbenson/zero-08/raw_files/new/hotspot/src/share/vm/utilities/vmError.cpp
#code{{
// 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
};
}}

- [https://docs.oracle.com/javase/jp/8/docs/platform/jvmti/jvmti.html#tooloptions JAVA_TOOL_OPTIONS - JVM(TM) Tool Interface 1.2.3]

* コマンドプロンプトからデフォルトのロケールを変更 [#DefaultLocale]
 > javac -J-Duser.language=en Test.java

 > java -Duser.language=en Test

//- [http://java.sun.com/javase/technologies/core/basic/intl/faq_ja.jsp#set-default-locale Java 国際化 FAQ]
- [https://docs.oracle.com/javase/jp/1.4/guide/intl/faq.html 国際化についての 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
 
 この機能を使用できない実行環境もあるため、この機能はテスト目的だけに使用してください。

* コード整形 [#CodeBeautifier]
個人的に、`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]
 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 [#bug]
 $ astyle --version
 Artistic Style Version 2.04

- 以下の様なソースコード(最後の`}`の直後に`EOF`)を`astyle`で変換すると、余計な`}`が追加される?

#code{{
class Hoge
{
    public static void main(String[] args)
    {
        System.out.println("aaaaaaa");
    }
}
}}

- [http://sourceforge.net/p/astyle/bugs/305/ Artistic Style / Bugs / #305 Last character always repeated in output when reading from stdin]
-- %%次バージョンで修正される模様%% 修正済み

* FileInputStream / FileOutputStream でメモリリーク [#FileInputStreamMemoryLeak]
- [http://blog.cybozu.io/entry/8218 恐怖の JVM 大量メモリ消費!メモリリークの謎を追え!! - Cybozu Inside Out | サイボウズエンジニアのブログ]
- [https://bugs.openjdk.org/browse/JDK-8080225 JDK-8080225 FileInputStream cleanup should be improved. - Java Bug System]
- [https://www.cloudbees.com/blog/fileinputstream-fileoutputstream-considered-harmful FileInputStream / FileOutputStream Considered Harmful | CloudBees]
-- via: [http://marxsoftware.blogspot.jp/2017/04/java-finalizer-file-io-streams.html Inspired by Actual Events: Java Finalizer and Java File Input/Output Streams]
-- `FileInputStream`や`FileOutputStream`は、`finalize()`メソッドをオーバーライドしている(`FinalReference`に登録されてしまう)ので`close()`メソッドを呼んだ後でもフル`GC`が発生するまでメモリ上に残り続ける
-- `Files.newInputStream(...)`や`Files.newOutputStream(...)`に置き換える必要がある
- [https://www.reddit.com/r/java/comments/64k16e/fileinputstream_fileoutputstream_considered/ FileInputStream / FileOutputStream Considered Harmful : java]
-- `Files.newInputStream(...)`(`ChannelInputStream`?)は`skip()`がすこし遅いらしい?
- `ClassLoader#getResourceAsStream(...)`は?

* 偶数・奇数の判断 [#EvenAndOdd]
#code{{
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);
      }
    }
  }
}
}}

* 正の数と負の数を反転 [#InvertSignedNumbers]
- [https://community.oracle.com/thread/1253898 How do you Invert signed numbers? | Oracle Community]
- [https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.15.4 15.15.4. Unary Minus Operator - / Chapter 15. Expressions]

#code{{
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(...) [#ObjectsCompare]
- [https://docs.oracle.com/javase/jp/8/docs/api/java/util/Objects.html#compare-T-T-java.util.Comparator- Objects.compare(...) (Java Platform SE 8)]

#code{{
    /**
     * 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);
    }
}}

- [https://stackoverflow.com/questions/32722171/what-is-the-purpose-of-the-objects-compare-method java - What is the purpose of the Objects.compare() method? - Stack Overflow]
-- 確かに`Objects.compare(...)`の使いどころが分からない
-- `TableSorter.java`の以下のようなコードが短くなるか?と考えたが、
#code{{
//@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`が発生する
- [https://www.ne.jp/asahi/hishidama/home/tech/java/comparator.html#nulls Java Comparatorメモ(Hishidama's Java Comparator Memo)]を参考に、`Comparator.nullsFirst(comparator)`と合わせて使用すれば、`NullPointerException`は発生しない

#code{{
//@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キーワード [#LambdaThisReference]
- [https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27.2 15.27.2. Lambda Body - Chapter 15. Expressions]
-- via: [https://stackoverflow.com/questions/24202236/lambda-this-reference-in-java Lambda this reference in java - Stack Overflow]
- [https://www.ne.jp/asahi/hishidama/home/tech/java/lambda Javaラムダ式メモ(Hishidama's Java8 Lambda Expression Memo)]
- 単純に無名匿名クラスをラムダ式に置き換えると、「`static`でないメソッド`getClass()`を`static`コンテキストから参照することはできません」とコンパイルエラーになる場合がある
#code{{
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`リテラルを使用して回避
-- [https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.8.2 15.8.2. Class Literals - Chapter 15. Expressions]

#code{{
import java.awt.*;
import java.beans.*;
import javax.swing.*;

public final class MainPanel extends JPanel {
  private MainPanel() {
    super(new BorderLayout());
    try {
      Thread.sleep(3000); //dummy task
      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 [#JEP330]
- `Java 11`では、`1`つの`.java`ファイルを`java`コマンドで実行可能になった
- 例えば以下のようなコードを`./TreeRootVisible/src/java/example/MainPanel.java`に生成した場合、`package`は考慮しなくても実行可能:

#code{{
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);
  }
}
}}

#code{{
> 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"));`で参照する場合:

#code{{
> 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
}}

* コメント [#comment]
#comment
- [[Nitpick]]を[[Javadoc]]以下に分割して移動。 -- &user(aterai); &new{2011-11-11 (金) 16:57:12};
- `Javadoc`翻訳を[[Javadoc]]に移動。 -- &user(aterai); &new{2011-11-11 (金) 16:57:12};
- `JRuby`関係のメモを[[JRuby]]に移動。 -- &user(aterai); &new{2011-11-11 (金) 16:57:12};

#comment

}}