20200726のJavaに関する記事は12件です。

Windows10からラズパイで実行するjavaFXプログラムをリモートデバッグする方法~環境構築からデバッグ実行まで①~

長いので分けて書く

Windows10でEclipseを使ったクロス開発環境を構築する

1.
以下のサイトから好きなバージョンをダウンロードし適当なフォルダに展開しておく。あまり深いフォルダに入れるのと日本語が入っているフォルダ名は何かとはまるので避ける
https://mergedoc.osdn.jp/
image.png
2.
ここではEclipse4.8Photonを使う。新しすぎるバージョンは古いプラグインとの相性が悪い
image.png
3.
Windows 64bit FullEdition javaを選択
image.png
4.
リンクをクリックしダウンロード
ダウンロード速度が呪い...
image.png
5.
適当なフォルダに展開し、起動
(展開したフォルダ)\pleiades-4.8\pleiades\eclipse\eclipse.exeで起動

6.起動時にプロジェクトの保存先を聞かれるので適当に決める
image.png

7.起動直後の画面
image.png

8.「ファイル」-「新規」-「その他」-「JavaFXプロジェクト」を選択
image.png

9.プロジェクト名にHelloRemoteを入力し、次へをクリック
image.png
10.そのまま「次へ」をクリック
image.png
11.言語を「FXML」へ変更
ルートタイプはAnchorPaneを選んで置く
「完了」をクリック
image.png

Scene BuilderをインストールしEclipseと連携させる

1.ダウンロード
https://gluonhq.com/products/scene-builder/
image.png

image.png

プラットフォームはWindowsインストーラーを選択
ダウンロードボタンを押ししばらく待つとダウンロードできる。
SceneBuilder-11.0.0.msi
インストール....

2.EclipseとSceneBuilderを連携させる
「ウィンドウ」-「設定」-「javaFX」を開き
ScnenBuilder実行可能ファイルを選択し適用
image.png

3.EclipseのパッケージエクスプローラーからSample.fxmlを右クリックしSceneBuilderで開くを実行
image.png

4.SceneBuilderが開く
image.png

5.Document-Hierarchy-AnchorPaneを選択し、MinWidth、MinHeightを640、480に変更
image.png

6.ControlsパネルからButtonをドラッグ&ドロップで配置
image.png

7.Buttonオブジェクトを選択、Codeのfx:idをtestBT、onActionにonTestBTを入力
image.png

8.同様にしてLabelを配置
fx:idはtestLBとしておく
image.png

9.取り敢えず保存しておく
image.png

10.View - ViewSampleControlSkeltonを選択
image.png

11.右下のFullにチェックを入れて、「コピー」
 クリップボードにコピーされる
image.png

12.Eclipseに戻り、パッケージエクスプローラーのSampleController.javaをダブルクリック
image.png
13.全部消してから、クリップボードの内容を張り付け
image.png

14.パッケージエクスプローラーのMain.javaを右クリックしJavaアプリケーションで実行
image.png
15.優先ランチャーの選択
image.png
16.保存
image.png
17.実行されるが何も表示されない
image.png
18.いったん、プログラムを閉じプロジェクトクリーンを実行
これを実行しないとSceneBuilderで保存しただけでは、プロジェクト側に反映されない
image.png
19.再び実行
image.png

プログラムの変更

1.パッケージエクスプローラーのSampleController.javaを開き修正
@FXML
void onTestBT(ActionEvent event) {
Platform.runLater(() ->testLB.setText("HelloFX"));
}
image.png

2.実行  Buttonを押しラベルがHelloFXに変われば問題なし
image.png

次回

このプログラムをラズパイに配置して実行する方法を説明する

2020.0726 kamoshika
当記事と全く関係ないが....主のチャンネルのリンクを貼っておく
https://www.youtube.com/channel/UCbtzwsQhTuUzW3ERoBSYZDw/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windows10からラズパイで実行するjavaFXプログラムをリモートデバッグする方法~環境構築編①~

長いので分けて書く

Windows10でEclipseを使ったクロス開発環境を構築する

1.
以下のサイトから好きなバージョンをダウンロードし適当なフォルダに展開しておく。あまり深いフォルダに入れるのと日本語が入っているフォルダ名は何かとはまるので避ける
https://mergedoc.osdn.jp/
image.png
2.
ここではEclipse4.8Photonを使う。新しすぎるバージョンは古いプラグインとの相性が悪い
image.png
3.
Windows 64bit FullEdition javaを選択
image.png
4.
リンクをクリックしダウンロード
ダウンロード速度が呪い...
image.png
5.
適当なフォルダに展開し、起動
(展開したフォルダ)\pleiades-4.8\pleiades\eclipse\eclipse.exeで起動

6.起動時にプロジェクトの保存先を聞かれるので適当に決める
image.png

7.起動直後の画面
image.png

8.「ファイル」-「新規」-「その他」-「JavaFXプロジェクト」を選択
image.png

9.プロジェクト名にHelloRemoteを入力し、次へをクリック
image.png
10.そのまま「次へ」をクリック
image.png
11.言語を「FXML」へ変更
ルートタイプはAnchorPaneを選んで置く
「完了」をクリック
image.png

Scene BuilderをインストールしEclipseと連携させる

1.ダウンロード
https://gluonhq.com/products/scene-builder/
image.png

image.png

プラットフォームはWindowsインストーラーを選択
ダウンロードボタンを押ししばらく待つとダウンロードできる。
SceneBuilder-11.0.0.msi
インストール....

2.EclipseとSceneBuilderを連携させる
「ウィンドウ」-「設定」-「javaFX」を開き
ScnenBuilder実行可能ファイルを選択し適用
image.png

3.EclipseのパッケージエクスプローラーからSample.fxmlを右クリックしSceneBuilderで開くを実行
image.png

4.SceneBuilderが開く
image.png

5.Document-Hierarchy-AnchorPaneを選択し、MinWidth、MinHeightを640、480に変更
image.png

6.ControlsパネルからButtonをドラッグ&ドロップで配置
image.png

7.Buttonオブジェクトを選択、Codeのfx:idをtestBT、onActionにonTestBTを入力
image.png

8.同様にしてLabelを配置
fx:idはtestLBとしておく
image.png

9.取り敢えず保存しておく
image.png

10.View - ViewSampleControlSkeltonを選択
image.png

11.右下のFullにチェックを入れて、「コピー」
 クリップボードにコピーされる
image.png

12.Eclipseに戻り、パッケージエクスプローラーのSampleController.javaをダブルクリック
image.png
13.全部消してから、クリップボードの内容を張り付け
image.png

14.パッケージエクスプローラーのMain.javaを右クリックしJavaアプリケーションで実行
image.png
15.優先ランチャーの選択
image.png
16.保存
image.png
17.実行されるが何も表示されない
image.png
18.いったん、プログラムを閉じプロジェクトクリーンを実行
これを実行しないとSceneBuilderで保存しただけでは、プロジェクト側に反映されない
image.png
19.再び実行
image.png

プログラムの変更

1.パッケージエクスプローラーのSampleController.javaを開き修正
@FXML
void onTestBT(ActionEvent event) {
Platform.runLater(() ->testLB.setText("HelloFX"));
}
image.png

2.実行  Buttonを押しラベルがHelloFXに変われば問題なし
image.png

次回

このプログラムをラズパイに配置して実行する方法を説明する

2020.0726 kamoshika
当記事と全く関係ないが....主のチャンネルのリンクを貼っておく
https://www.youtube.com/channel/UCbtzwsQhTuUzW3ERoBSYZDw/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Apache + Tomcat + PebbleをMacのローカルで構築した

About

※この記事はセキュリティ度外視の課題専用の内容です。予めご了承ください。

大学の課題でApacheを設定、SSL化し、Apacheと連携させたTomcatからPebbleを起動させたので備忘録です。
Apacheの設定部分やローカルでのSSL化は省略します。
ちなみにSSL化については以下の記事に記載しました。
https://qiita.com/Raluer/items/02b848437844ba3cbb6c

httpd.confの編集

以下のLoadModuleをコメントアウト

/usr/local/etc/httpd/httpd.conf
LoadModule proxy_module libexec/apache2/mod_proxy.so
LoadModule proxy_ajp_module libexec/apache2/mod_proxy_ajp.so

ファイル末尾に以下の一文を追加
外部のコンフィグファイルに記載したAJP通信用の設定(これから作ります)を読み込み。

/usr/local/etc/httpd.conf
Include /usr/local/etc/httpd/extra/httpd-proxy.conf

httpd-proxy.confの編集

ターミナル上で/usr/local/etc/httpd/extra/にて

/usr/local/etc/extra
$ sudo vim httpd-proxy.conf

するとvimが起動して新規ファイルの作成になるので、以下のコードをコピペする。

/usr/local/etc/extra/httpd-proxy.conf
<Location /pebble >
  ProxyPass ajp://localhost:8009/pebble
  Order allow,deny
  Allow from all
</Location>

これでApache側の設定はオールオッケー
ここからTomcatを入れていきます。

Tomcatインストール

公式サイトから、好きなバージョンを選んで「Download」を押す。
飛んだページの「Core」の中から「tar.gz」をクリックしてダウンロード。
ルートディレクトリ(~/のところ)にダウンロードしておくと後々楽かも?ぶっちゃけどこでもいいです。

ダウンロードしたtar.gzファイルをFinderから解凍して中を見ます。
「conf」というフォルダがあるので中に入り、server.xmlをお好きなテキストエディタで開きます。

74行目あたりにある以下のコードを、

conf/server.xml
<Connector executor="tomcatThreadPool"
          port="8080" protocol="HTTP/1.1"
          connectionTimeout="20000"
          redirectPort="8443" /> 

今回HTTP通信は使わないので、コメントアウトします。

conf/server.xml
<!--
<Connector executor="tomcatThreadPool"
          port="8080" protocol="HTTP/1.1"
          connectionTimeout="20000"
          redirectPort="8443" /> 
-->

続いて117行目あたりにある、今回用いるAJP通信用の設定のアドレスを127.0.0.1に書き換え、secretRequiredを追加し、パラメータをfalseに設定します(ローカルのときのみ!)

conf/server.xml
<Connector protocol="AJP/1.3"
           address="127.0.0.1"
           port="8009"
           redirectPort="8443"
           secretRequired="false" />

ちなみにsecretRequiredを設定しなかったせいで相当ハマりました。

Pebbleの導入

ここまで来たらラストスパート。
まずはPebbleをこのサイトからダウンロードします。
ダウンロード場所が少し分かりづらいですが、右上のPebble 2.6.4をクリックするとダウンロードできます。
image.png

ダウンロードしたファイルを解凍し、解凍したフォルダ内にあるpebble-2.6.4.war解凍せずにコピーし、先程のTomcatディレクトリに移動し、webapps直下にペーストします。もともとのフォルダは不要です。中に入ってるwarファイルだけを使います。
warファイルにあとでアクセスするので、pebble.warリネームしておきましょう。

TomcatとApacheサーバの起動

ここまで来たらほとんどゴールです。
ターミナルを開き、Tomcatのbinの中に入ります。
Tomcatのサーバを起動するには、ターミナル上binの中で

tomcat/bin
$ ./startup.sh

のコマンドを打つだけです。ちなみに止めるときは

tomcat/bin
$ ./shutdown.sh

を同じ場所で実行するだけです。
起動するのを確認したら、そのまま

terminal
$ apachectl start

を実行し、apacheサーバを起動します。

ゴール!

Tomcatサーバとapacheサーバがどちらも起動した状態になったので、ブラウザのURLにlocalhost/pebbleと入力すると、少し読み込んだ後にPebbleのWelcomeページが表示されるはずです。

image.png

あとがき

非常にハマってしまったので、是非とも参考にしてスムーズに駆け抜けてください…。

ハマった場合のチェックポイント

ポート8009は埋まってない?
埋まってたら適当に別のポート(8019とか)使うと出来ますよ。
server.xmlとhttpd-proxy.confどちらも変更するのを忘れずに!

参考サイト

https://ameblo.jp/g-pinchan-new/entry-11573378743.html
https://qiita.com/brighton0725/items/0e116db637a8fea1d907

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java SE11 silver に受かった話

経歴

地方公務員(向いてないなあ)→SESに転職→1ヶ月の研修後、運用・保守の現場

研修ではjavaをやってました。その前に空白があったので、すっきりわかるJava入門paiza を1ヶ月ほどやってました。Bランクまではなんとか解けました。

研修最終日にsilver受けて、53%でした。。。

再受験で89%!合格!

トータル学習期間:3ヶ月くらい

気をつけたこと

1回目は勉強不足!が確実にあったので

2回目は黒本を解きまくって、終盤は満点しか出さないくらいのレベルでした。

Javaのことでいえば
・オーバーライドの仕様をよく確認する
・アクセス修飾子をよく確認する
・ローカル変数とフィールドの優先度とか
・コンストラクタの仕様
・例外処理、ラムダ式、モジュールシステムに関しては出題されるパターンが黒本と似ているので、それで覚える。(あんまりよくないですけど…)

・あんまり参考にならんかもですけど、モジュールに関しては、役割とか、基本的なAPIがまとめられているのはbaseか、とかがよくでた印象でした。知識を問うような問題が多かった。

先人たちの記事

とても参考になりますので、ぜひ!

Java Silver 試験対策メモ
[java] Java SE 8 Silver メモ

さいごに

ほんとに認定教科書シリーズやりまくれば、受かります!

次は基本情報かLPIC受けたいし、なんか作りたいですね
あと、技術的な記事も書きたいですね

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Effective Javaを読む】 第2章 項目3 『privateのコンストラクタかenum型でシングルトン特性を強制する』

privateのコンストラクタかenum型でシングルトン特性を強制する

Java1.5より前ではシングルトンを実装する方法が2つあった(例1、例2)けど、1.5でできるようになった3つ目の方法(例4)が一番良いねってお話。

用語集

シングルトン

デザインパターンの一種。
「Singleton(シングルトン)パターン」と呼ばれることもある。
手短に言えば厳密に一度しかインスタンスが作成されないクラス。
「あるクラスのインスタンスが常にたった1つしか存在していない」という状態を実現したいときに利用される。

シングルトンの作り方
・コンストラクタをprivateで宣言する。
 (このクラスを利用する側からコンストラクタを呼び出せないようにするため)

・インスタンスを取得するメソッドgetInstance( )をstaticで宣言する。
 これにより、利用側はSingleton#getInstance( )という呼び出しでインスタンスを取得することができる。

シングルトンサンプル
/**
 * アプリケーション全体の設定情報
 */
public class Config {
    /**
     * 外部からインスタンス化できないよう、コンストラクタをprivateで宣言する
     */
    private Config() {
        // 実際はファイル・データベースなどから設定情報を
        // 読み込む処理をここに書く
    }

    /**
     * 唯一のインスタンスを返す
     * @return このクラスの唯一のインスタンス
     */
    public static Config getInstance() {
        return ConfigInstanceHolder.INSTANCE;
    }

    /**
     * 指定されたキーに対応する設定値を返す
     * @param key 設定キー
     * @return 設定値
     */
    public String getValue(String key) {
        // 実際はコンストラクタで読み込んだ設定情報を
        // 返す処理をここに書く
        return ....;
    }

    /**
     * Configクラスの唯一のインスタンスを保持する内部クラス
     */
    public static class ConfigInstanceHolder {
        /** 唯一のインスタンス */
        private static final Config INSTANCE = new Config();
    }
}

enum型

Enum(列挙型)とは、複数の定数をひとつにまとめておくことができる型のこと。
Enumで定義する定数のことを列挙子と呼ぶ。

public class Main {

    public static void main(String[] args) {
        Fruit fruit_type = Fruit.Orange;

        System.out.println(fruit_type);
    }

    protected enum Fruit {
        Orange,
        Apple,
        Melon
    };

}
実行結果
Orange

Elvis Presley

偉大なるロックンローラー
私は「A Little Less Conversation」が好きです
https://www.youtube.com/watch?v=Zx1_6F-nCaw

Elvis has left the Building.

往年の人気歌手エルビス・プレスリーの有名なエピソードにまつわる表現です。
プレスリーのコンサートが終わっても、アンコールを期待してなかなか帰ろうとしない聴衆に向かって「エルビスはもうこの建物を出ました」とアナウンスを流して、聴衆が会場から去るよう促したことが始まりです。

現在は、どのようなイベントについても、終了したことについて使われます。

サンプルコード

1.5より前でのシングルトンの作り方その1

コンストラクタをpriavteにして、クラスの利用者がそのクラスの唯一のインスタンスにアクセスできるようにpublic staticのメンバを提供している。

privateのコンストラクタは、public static finalのフィールドであるElvis.INSTANCEを初期化するために1度だけ呼ばれる。
これでElvisが世界に一人しかいないことが保証される。

例1
//public finalのフィールドによるシングルトン
public class Elvis{
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }

    public void leaveTheBuliding() { ... }

}

1.5より前でのシングルトンの作り方その2

その1のメンバをpublic staticにするのが2つ目の方法。
Elvis.getInstance()でオブジェクト参照を返す。
この良いところは宣言によりそのクラスがシングルトンになっていることが明白であること。

例2
//staticファクトリーメソッドによるシングルトン
public class Elvis{
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    public static Elvis getInstance() { return INSTANCE; }

    public void leaveTheBuilding() { ... }
}

でも、例1、例2の方法で作られたElvisには偽物が存在する可能性があって、それを防ぐには以下のようなメソッドを追加する必要がある。

例3
//シングルトン特性を保持するためのreadResolveメソッド
private Object readResolve() throws ObjectStreamException{
    /*
     * 本物のElvisを返して、Elvisの偽物をガーベジコレクタに
     * 始末させる。
     * 
     */
    return INSTANCE;
}

最新の一番良い方法

Java 1.5からできるようになった3つ目の方法。
単一要素をもつenum型を単純に作るだけ。
簡単な記述だし偽物を許さない鉄壁さもあるからシングルトンを作るならこのやり方にしましょう、だって。

例4
// enumシングルトン - 好ましい方法
public enum Elvis {
    INSTANCE;

    public void leaveTheBuilding() { ... }
}

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOS: DeviceCheckの参照、保存をJavaで実装。(アカウントBan,リセマラ防止対応など)

iOSのdevice checkで出来ること。

  • 端末から取得できるdevice tokenを元に、端末単位で2つのビット値をAppleのAPIに記録、参照できる。
  • 端末を初期化、アプリのアンインストール&インストールしても保存されたビット値はリセットされない。

どんなことに利用できるか。

リセマラ防止。

  • (初期インストール時、device checkのAPIに記録すると、再インストールされたことを判定できる。)

深刻な不正行為をするユーザーを端末単位で、アカウントbanする。

  • device checkのAPIで、アカウントbanされた端末であることを記録。
  • アプリの再インストール、端末の初期化後も、以前にアカウントbanされた端末である場合、利用できないようにする。

利用時の注意点

  • 端末が中古市場等で別の人に渡った場合でも、保持される値なので慎重な運用が必要。
  • 端末から取得したdevice tokenは時間的な有効期限があるみたい。(この部分の記憶は定かじゃないので、テストしてみてください。)アカウントbanで利用する場合は、banした後の次のアプリ起動時にdevice tokenをサーバーサイドに送って、そこですぐにdevice checkのAPIで更新するような工夫が必要。

事前準備、前提

  • 認証キーのp8ファイルを取得。
  • KEY_ID, TEAM_IDを取得
  • DeviceTokenを端末で取得し、サーバーサイドに渡す。

参考記事

DeviceCheck APIのURL

baseのAPI

開発

https://api.development.devicecheck.apple.com/v1/

本番運用時

https://api.devicecheck.apple.com/v1/

APIの機能

参照:query_two_bits

https://api.devicecheck.apple.com/v1/query_two_bits

更新:update_two_bits

https://api.devicecheck.apple.com/v1/update_two_bits

device tokenのバリデーション:validate_device_token

https://api.devicecheck.apple.com/v1/validate_device_token

プログラム

iOSアプリでdevice tokenを取得。

※シミュレーターでは取得できません。

import DeviceCheck

DCDevice.current.generateToken {
    (data, error) in
    guard let data = data else {
        return
    }

    let token = data.base64EncodedString()
    print(token)
}

サーバーサイド(Java)

取得、更新サンプル

// 取得
private void queryIOSDeviceCheckSample() {
    // この値で2つのbool値と最終更新日時を取得できる。
    Response response = postRequest(DEVELOPMENT_BASE_API_URL + "query_two_bits", "端末から取得したdevicetoken", null, null);
}

// 更新
private void updateIOSDeviceCheckSample(Boolean bit0, Boolean bit1) {
    Response response = postRequest(DEVELOPMENT_BASE_API_URL + "update_two_bits", "端末から取得したdevicetoken", null, null);
}

API呼び出し処理

  • "Authorization"ヘッダーにJWTのトークンを設定。
  • request bodyにjson形式で各パラメーターを設定。
    • device_token, transaction_id, timestamp, bit0, bit1
private static Response postRequest(String url, String deviceToken, Boolean bit0, Boolean bit1) throws IOException {
    MediaType JSON = MediaType.get("application/json; charset=utf-8");

    JSONObject jsonObject = new JSONObject();
    jsonObject.put("device_token", deviceToken);
    jsonObject.put("transaction_id", UUID.randomUUID().toString());
    jsonObject.put("timestamp", new Date().getTime());
    if (bit0 != null) {
        jsonObject.put("bit0", bit0);
    }
    if (bit1 != null) {
        jsonObject.put("bit1", bit1);
    }
    String json = jsonObject.toJSONString();

    RequestBody body = RequestBody.create(JSON, json);

    String jwt = getJWTStr();
    if (jwt == null) {
        return null;
    }
    Request request = new Request.Builder()
            .url(url)
            .header("Content-Type", "application/x-www-form-urlencoded")
            .header("Content-Length", String.valueOf(json.length()))
            .header("Authorization", "Bearer " + jwt)
            .post(body)
            .build();
    OkHttpClient client = new OkHttpClient();
    return client.newCall(request).execute();
}

p8ファイルから、JWTトークンを取得。

プッシュ通知用ライブラリ「pushy」のソースを参考に実装:JWTトークンの取得処理

JTW(=JSON Web Token)

https://ja.wikipedia.org/wiki/JSON_Web_Token

private static String getJWTStr() {
    try {
        ECPrivateKey privateKey = getECPrivateKey(P8_SECRET_KEY_PATH);
        return Jwts.builder()
            .setHeaderParam("kid", KEY_ID)
            .setIssuer(TEAM_ID)
            .setIssuedAt(new Date())
            .signWith(privateKey, SignatureAlgorithm.ES256)
            .compact();
    } catch (Exception e) {
        return null;
    }
}

private static ECPrivateKey getECPrivateKey(String p8FilePath) throws Exception {

    final FileInputStream fileInputStream = new FileInputStream(new File(p8FilePath));
    final ECPrivateKey signingKey;
    {
        final String base64EncodedPrivateKey;
        {
            final StringBuilder privateKeyBuilder = new StringBuilder();

            final BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream));
            boolean haveReadHeader = false;
            boolean haveReadFooter = false;

            for (String line; (line = reader.readLine()) != null; ) {
                if (!haveReadHeader) {
                    if (line.contains("BEGIN PRIVATE KEY")) {
                        haveReadHeader = true;
                    }
                } else {
                    if (line.contains("END PRIVATE KEY")) {
                        haveReadFooter = true;
                        break;
                    } else {
                        privateKeyBuilder.append(line);
                    }
                }
            }

            if (!(haveReadHeader && haveReadFooter)) {
                throw new IOException("Could not find private key header/footer");
            }

            base64EncodedPrivateKey = privateKeyBuilder.toString();
        }

        final byte[] keyBytes = Base64.getDecoder().decode(base64EncodedPrivateKey.getBytes(StandardCharsets.US_ASCII));

        final PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        final KeyFactory keyFactory = KeyFactory.getInstance("EC");

        try {
            signingKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);
        } catch (InvalidKeySpecException e) {
            throw new InvalidKeyException(e);
        }
    }
    return signingKey;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JFR(Java Flight Recorder)を記録してダンプファイルを出力する方法

JFR(Java Flight Recorder)を記録してダンプファイルを出力する方法を紹介します。
ここでは、Eclipse GlassFish 5.1.0の状態を記録します。

環境

  • OS:CentOS Linux release 7.7.1908
  • jdk1.8
  • GlassFish 5.1.0
[glassfish@CENTOS7 ~]$ cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
[glassfish@CENTOS7 ~]$
[glassfish@CENTOS7 ~]$ java -version
java version "1.8.0_241"
Java(TM) SE Runtime Environment (build 1.8.0_241-b07)
Java HotSpot(TM) 64-Bit Server VM (build 25.241-b07, mixed mode)
[glassfish@CENTOS7 ~]$
[glassfish@CENTOS7 ~]$ /opt/glassfish5/glassfish/bin/asadmin version
Version string could not be obtained from Server [localhost:4848].
(Turn debugging on e.g. by setting AS_DEBUG=true in your environment, to see the details.)
Using locally retrieved version string from version class.
Version = GlassFish Server Open Source Edition  5.1.0  (build default-private)
Command version executed successfully.
[glassfish@CENTOS7 ~]$

GlassFish 5.1.0のインストールについては、以前投稿したCentOS7にEclipse GlassFish 5.1.0をインストールする方法を参照してください。

1. Glassfishの起動時のJVMオプションの設定

Glassfishの起動時のJVMオプションに以下を追加します。

  • -XX:+UnlockCommercialFeatures
  • -XX:+FlightRecorder
  • -XX:FlightRecorderOptions=<..>

具体的には「/opt/glassfish5/glassfish/domains/domain1/config」配下のdomain.xmlの「domain/configs/java-config」(domainタグ内のconfigsタグ内のjava-configタグ内)に以下の3行を追加します。

/opt/glassfish5/glassfish/domains/domain1/config/domain.xmlに追加
<jvm-options>-XX:+UnlockCommercialFeatures</jvm-options>
<jvm-options>-XX:+FlightRecorder</jvm-options>
<jvm-options>-XX:FlightRecorderOptions=defaultrecording=true,disk=true,repository=/var/log/jvm/diagnostics_images,maxsize=2048m,maxage=25h,dumponexit=true,dumponexitpath=/var/log/jvm/dump_test.jfr</jvm-options>

※FlightRecorderOptionsの設定の詳細はJavaのページを参照してください。

2. Glassfishを起動

以下のコマンドでGlassfishを起動します。

/opt/glassfish5/glassfish/bin/asadmin start-domain domain1

実行結果
[glassfish@CENTOS7 config]$ /opt/glassfish5/glassfish/bin/asadmin start-domain domain1
Waiting for domain1 to start ......
Successfully started the domain : domain1
domain  Location: /opt/glassfish5/glassfish/domains/domain1
Log File: /opt/glassfish5/glassfish/domains/domain1/logs/server.log
Admin Port: 4848
Command start-domain executed successfully.
[glassfish@CENTOS7 config]$

3. JFRダンプファイルの出力

まずは以下のコマンドでglassfishのプロセスIDを調べます。

ps -ef | grep glassfish | grep -v grep

実行結果
[glassfish@CENTOS7 config]$ ps -ef | grep glassfish | grep -v grep
glassfi+ 26302     1  5 19:54 pts/0    00:00:16 /usr/java/jdk1.8.0_241-amd64/bin/java -cp /opt/glassfish5/glassfish/modules/glassfish.jar -XX:+UnlockCommercialFeatures -XX:+UnlockDiagnosticVMOptions -XX:NewRatio=2 -XX:FlightRecorderOptions=defaultrecording=true,disk=true,repository=/var/log/jvm/diagnostics_images,maxsize=2048m,maxage=25h,dumponexit=true,dumponexitpath=/var/log/jvm/dump_test.jfr -XX:+FlightRecorder -XX:MaxPermSize=192m -Xmx512m -javaagent:/opt/glassfish5/glassfish/lib/monitor/flashlight-agent.jar -client -Djavax.xml.accessExternalSchema=all -Djavax.net.ssl.trustStore=/opt/glassfish5/glassfish/domains/domain1/config/cacerts.jks -Djdk.tls.rejectClientInitiatedRenegotiation=true -Djdk.corba.allowOutputStreamSubclass=true -Dfelix.fileinstall.dir=/opt/glassfish5/glassfish/modules/autostart/ -Dorg.glassfish.additionalOSGiBundlesToStart=org.apache.felix.shell,org.apache.felix.gogo.runtime,org.apache.felix.gogo.shell,org.apache.felix.gogo.command,org.apache.felix.shell.remote,org.apache.felix.fileinstall -Dcom.sun.aas.installRoot=/opt/glassfish5/glassfish -Dfelix.fileinstall.poll=5000 -Djava.endorsed.dirs=/opt/glassfish5/glassfish/modules/endorsed:/opt/glassfish5/glassfish/lib/endorsed -Djava.security.policy=/opt/glassfish5/glassfish/domains/domain1/config/server.policy -Dosgi.shell.telnet.maxconn=1 -Dfelix.fileinstall.bundles.startTransient=true -Dcom.sun.enterprise.config.config_environment_factory_class=com.sun.enterprise.config.serverbeans.AppserverConfigEnvironmentFactory -Dfelix.fileinstall.log.level=2 -Djavax.net.ssl.keyStore=/opt/glassfish5/glassfish/domains/domain1/config/keystore.jks -Djava.security.auth.login.config=/opt/glassfish5/glassfish/domains/domain1/config/login.conf -Dfelix.fileinstall.disableConfigSave=false -Dfelix.fileinstall.bundles.new.start=true -Dcom.sun.aas.instanceRoot=/opt/glassfish5/glassfish/domains/domain1 -Dosgi.shell.telnet.port=6666 -Dgosh.args=--nointeractive -Dcom.sun.enterprise.security.httpsOutboundKeyAlias=s1as -Dosgi.shell.telnet.ip=127.0.0.1 -DANTLR_USE_DIRECT_CLASS_LOADING=true -Djava.awt.headless=true -Dcom.ctc.wstx.returnNullForDefaultNamespace=true -Djava.ext.dirs=/usr/java/jdk1.8.0_241-amd64/lib/ext:/usr/java/jdk1.8.0_241-amd64/jre/lib/ext:/opt/glassfish5/glassfish/domains/domain1/lib/ext -Djdbc.drivers=org.apache.derby.jdbc.ClientDriver -Djava.library.path=/opt/glassfish5/glassfish/lib:/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib com.sun.enterprise.glassfish.bootstrap.ASMain -upgrade false -domaindir /opt/glassfish5/glassfish/domains/domain1 -read-stdin true -asadmin-args --host,,,localhost,,,--port,,,4848,,,--secure=false,,,--terse=false,,,--echo=false,,,--interactive=true,,,start-domain,,,--verbose=false,,,--watchdog=false,,,--debug=false,,,--domaindir,,,/opt/glassfish5/glassfish/domains,,,domain1 -domainname domain1 -instancename server -type DAS -verbose false -asadmin-classpath /opt/glassfish5/glassfish/lib/client/appserver-cli.jar -debug false -asadmin-classname com.sun.enterprise.admin.cli.AdminMain
[glassfish@CENTOS7 config]$

プロセスIDが26302であることがわかります。

以下のコマンドでJFR(Java Flight Recorder)の記録をダンプファイルに出力します。

jcmd <プロセスID> JFR.dump recording=0 filename=<出力ダンプファイルのパス>

実行結果
[glassfish@CENTOS7 ~]$ jcmd 26302 JFR.dump recording=0 filename=/home/glassfish/perf/test_$(date "+%Y%m%d_%H%M%S").jfr
26302:
Dumped recording 0, 2.5 MB written to:

/home/glassfish/perf/test_20200726_200546.jfr
[glassfish@CENTOS7 ~]$

出力されたダンプファイルを確認します。

実行結果
[glassfish@CENTOS7 ~]$ cd /home/glassfish/perf
[glassfish@CENTOS7 perf]$ ls -l
合計 2600
-rw-rw-r--. 1 glassfish glassfish 2660207  7月 26 20:05 test_20200726_200546.jfr
[glassfish@CENTOS7 perf]$

3. 「jmc.exe」で出力されたダンプファイル(jfrファイル)を参照

出力したjfrダンプファイル(test_20200726_200546.jfr)をjdk1.8がインストールされているWindowsPCに転送します。

C:\Program Files\Java\jdk1.8.0_231\bin」配下の「jmc.exe」(Java Mission Contorol)を起動します。

01.png

メニューから「ファイル」-「ファイルを開く」で出力したjfrダンプファイル(test_20200726_200546.jfr)を開きます。

02.png

03.png

「jmc.exe」(Java Mission Contorol)で出力したjfrダンプファイルを参照することができます。

04.png

参考

Java Platform, Standard Editionツール・リファレンス

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

eclipse使わずにJDBCでJavaアプリケーションとPostgreSQLの接続(コマンドプロンプトで実行)

はじめに

プログラミング教育の講師という立場でもある私は、初学者に対して統合開発環境をあえて使わずにプログラミング言語の基礎を理解するよう伝えています。
そのため、eclipseを使わずにJavaアプリケーションを動作させる環境を用意する必要がありました。

この記事を読んでできること

コマンドプロンプトでPostgreSQLのAPIを使ったJavaアプリケーションを実行することができるようになります。

実行環境

実行環境は以下を使っています。

  • OS
    • Windows10
  • Javaバージョン
    • OpenJDK 14.0.2
  • データベースバージョン
    • PostgreSQL 12

PostgreSQL用JDBCのjarファイルを追加する

PostgreSQLをインストールする際の付属アプリケーションである「スタックビルダー」を起動してください。

スタックビルダ 4.2.0の起動画面

インストールしたいアプリケーションから"pgJDBC vXX.X.XX"を選択してください。
これはインストーラーなので保存ディレクトリはどこでもOKです。(迷ったらダウンロードフォルダへ保存してください。)

スタックビルダ 4.2.0のインストールしたいアプリケーションの選択画面

上記でダウンロードした"edb_pgjdbc.exe"を開いてjarファイルを追加します。
保存先はデフォルトのまま("C:\Program Files (x86)\PostgreSQL\pgJDBC")でインストールしてください。

JDBCを使ってPostgreSQLとの接続を行う

私は最近、Javaプログラミングをする際は統合開発環境(eclipseなど)を使って開発する機会が増えて、滅多にサクラエディタなど簡単なエディタで実装することはなくなってきました。(大学などで学ぶ時はよく使っていました…。)
eclipseでのJDBC使用方法はよく見かけますがおさらいします。

eclipseでJDBCを使う際には、Javaプロジェクトを新規作成後、
プロジェクトを右クリックし以下の操作でJDBCのjarファイルを追加します。

eclipse新規Javaプロジェクト作成画面

(英語)
"Build Path"→"Add External Archives..."→"postgresql-XX.X.XX.jar"を選択
(日本語)
"ビルド・パス"→"外部アーカイブの追加"

ビルドパスの追加後

追加するとパッケージ・エクスプローラに表示されます。

eclipseでビルドパスの追加方法

実行したいソースコード

データベース(restaurantdb)にはすでにテーブル(menuitems)を生成しています。

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

public class P5_1 {
   public static void main(String[] args) {

       String url = "jdbc:postgresql://127.0.0.1:5432/restaurantdb";
       String user = "postgres";
       String password = "postgres";
       String sql = "SELECT * FROM menuitems";

       try (Connection connection = DriverManager.getConnection(url, user, password);
           Statement statement = connection.createStatement();
           ResultSet resultSet = statement.executeQuery(sql)) {

           while(resultSet.next()) {
               String id = resultSet.getString(1);
               String name = resultSet.getString(2);
               int price = resultSet.getInt(3);
               String kindId = resultSet.getString(4);
               Boolean isDisabled = resultSet.getBoolean(5);

               System.out.println(id + " " + name + " " + price + " " + kindId + " " + isDisabled);
           }
       } catch (SQLException e) {
           e.printStackTrace();
       }
   }
}

本題:eclipseを使わずにJavaのプログラムからデータベース接続しようとするとエラーが発生する問題を解決したい

C:\java-programming\JDBCSample>javac P5_1.java

C:\java-programming\JDBCSample>java P5_1
java.sql.SQLException: No suitable driver found for jdbc:postgresql://127.0.0.1:5432/restaurantdb
       at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:702)
       at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:228)
       at P5_1.main(P5_1.java:15)

上記エラーを抑える方法は2つあるようです。
・環境変数へ「CLASSPATH」を追加する
・実行時に実行オプション「-cp」を付与する

環境変数へ「CLASSPATH」を追加する

1つ目に、環境変数へ「CLASSPATH」を追加するという選択肢があります。
"コントロール・パネル"→"システム"→"システムの詳細設定"→"環境変数"→"ユーザの環境変数"へ以下を追加してください。
変数名「CLASSPATH」
値「C:\Program Files (x86)\PostgreSQL\pgJDBC\postgresql-42.2.12.jar;.」
※値の最後にドット(.)が入っているので注意してください。ドットを入れ忘れるとデフォルトで設定されているカレントディレクトリへのクラスパスが無効となる場合があります。
※"postgresql-XX.X.XX.jar"は、格納場所やバージョンなどは適宜読み替えてください。
※すでに「CLASSPATH」が存在する場合、既存の値を消してしまうと他の環境が壊れる場合があるので、追記する形で編集してください。
 例えば、「C:\XXX\YYY.jar;」を設定していた場合は、「C:\XXX\YYY.jar;C:\Program Files (x86)\PostgreSQL\pgJDBC\postgresql-42.2.12.jar;.」となるように追記します。(セミコロンは区切り文字です。)

実行時に実行オプション「-cp」を付与する

何らかの理由で環境変数を変更できない場合、実行時にオプションをつけることができます。

例えば、「P5_1.java」をコンパイルし実行する場合、以下のコマンドを入力します。

> javac P5_1.java

> java -cp "C:\Program Files (x86)\PostgreSQL\pgJDBC\postgresql-42.2.12.jar;." P5_1

(実行結果が表示されます)
※値の最後にドット(.)が入っているので注意してください。ドットを入れ忘れるとデフォルトで設定されているカレントディレクトリへのクラスパスが無効となる場合があります。
※"postgresql-XX.X.XX.jar"は、格納場所やバージョンなどは適宜読み替えてください。

まとめ

今回、eclipseを使わずにJavaプログラムからJDBCのAPIを呼び出しました。
あまりこれを使う機会は少ないかもしれませんが、仕組みを理解する上で試してみるのも良いかもしれません。

ありがとうございました。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Springで勤怠サイトを作ってみる。【概略】

概要

評価面談でSpringを勉強していると言ってしまったばっかりに、
次回面談までに勤怠サイトを作ることに・・・。
実業務でSpringベースの開発経験はあるけども、全体的に素人に毛が生えたレベル。

PCの調子が悪くて(なんかカリカリ音がしている)成果物が消える恐れがあるので、
面談時のエビデンスのためにも作業履歴としてQiitaに残そうかな、と。

構成(想定)

  • Webアプリ
    • フロント:Vue.js
    • バックエンド:Spring
    • DB:PostgreSQL


※追記事項があり次第記載します

環境

  • Eclipse - Version: Oxygen.3a Release (4.7.3a)
  • Atom


※追記事項があり次第記載します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

(Intelij)Spring BootでHelloWorld

手順

  1. InteliJで「File」→「New」→「Project」
  2. 表示されたNew Projectで「Spring Initializer」を選択し、「Next」
  3. 適当に「Group」,「Artifact」を入力。サーバにデプロイしたいので、「Packaging」は「War」を選択し、「Next」
  4. Webアプリケーションを作りたいので、「Web」→「Spring Web」にチェックし、「Next」
  5. 適当に「Project name」,「Project location」を入力し、「Fisnish」
  6. 自動作成されたDemoApplicationに以下の通り追記し、実行。

私は@RestControllerがなくて、ハマりました・・・

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+ import org.springframework.web.bind.annotation.GetMapping;
+ import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
+ @RestController
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
+    @GetMapping("/hello")
+    public String sayHello() {
+        return "Hello World";
+    }
}

  1. 以下URLにアクセスすると「Hello World」が表示されるはず

http://localhost:8080/hello

スクリーンショット 2020-07-26 12.53.06.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Jacksonで良い感じに整形してシリアライズする

JavaでJSONにシリアライズしたいときはJSON-Bだと力不足なのでJacksonを使う事が多いのだけど、いつも書き方忘れるのでメモ。

整形せずにシリアライズする

データ交換用に整形せずにシリアライズするパターン。通常はこれ。

var item = Map.of("parent", Map.of("child", List.of("a", "b", "c")));
var json = new ObjectMapper().writeValueAsString(item);

結果

{"parent":{"child":["a","b","c"]}}

整形してフォーマットを綺麗にしたい場合 その1

画面出力や設定ファイル用にフォーマットを整えたい場合. INDENT_OUTPUTを使う

var item = Map.of("parent", Map.of("child", List.of("a", "b", "c")));

var mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);

var json = mapper.writeValueAsString(item);

結果

{
  "parent" : {
    "child" : [ "a", "b", "c" ]
  }
}

整形してフォーマットを綺麗にしたい場合 その2

さらに要素の配列を改行付きで表示したい場合。要素が長い時とか用。PrettyPrinterとSYSTEM_LINEFEED_INSTANCEを使う。

var item = Map.of("parent", Map.of("child", List.of("a", "b", "c")));

var printer = new DefaultPrettyPrinter();
printer.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE);

var json = new ObjectMapper().writer(printer).writeValueAsString(item);

結果

{
  "parent" : {
    "child" : [
      "a",
      "b",
      "c"
    ]
  }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaからVB.NETへ ―書き方対照メモ―

この記事について

作成の経緯

新人研修で3ヶ月間Javaをやってきたけれども、配属先部署で使う言語はVisual Basic .NETだったので新しく学ぶ必要が生じた。
しかし、「JavaからVB.NETへ移行」というケースはそんなにないのか(今ならC#あたりが普通…?)、文法の比較などを細かくしているサイトが見つからなかったため、自分で書いてみることにした。

対象者・目的

  • Javaの書き方やプログラミングの諸概念は一通り理解している
  • これからVB.NETでもプログラムを書けるようになりたい

という人(まあ自分と数名の同期だけれど)にJavaとVB.NETの比較対象リファレンスを提供する。

環境

  • Windows 10
  • Visual Studio 2019
  • .NET Framework 4.7.2

といっても、環境に依存するようなコードはほぼないはず。

記述上の注意

  • Visual Basic .NET(VB.NET)のことは、以下単に「VB」と呼ぶ。
  • 同じセクションにあるJavaとVBのコードは、基本的に同じ処理になるようにしている。

参考文献(総合)

コードの基本構造

main

Main.java
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello Java!");
        int a; String b; double c;
    }
}
  • ブロックは {} で区切られる
  • public などの修飾子は小文字
  • ;で文を終える(改行それ自体は意味をもたない)
Form1.vb
Public Class Form1
    Private Sub ShowMessage(sender As Object, e As EventArgs) _ 
    Handles Button1.Click
        Console.WriteLine("Hello VB!")
        Dim a As Integer : Dim b As String : Dim c As Double
    End Sub
End Class
  • ブロックは (修飾子) ClassEnd Class のように分けられる
  • 行の終わりは文(ステートメント)の終わり。
    • 長い文中で意図的に改行させたいときは、行継続文字 _ を入れる
    • ただし、VB2010からは、特定の条件下で行継続文字がなくても改行できるようになった(暗黙の行継続)。
    • 詳しいルールはVisual Basic 2010の新機能 - @ITを参照
  • 1行の中に複数のステートメントを入れたいときは、 : で区切る。

コメント

Comment.java
// 単数行コメント

/*
 * 複数行コメント
 */
Comment.vb
' 単数行コメント

※VBに複数行コメントはない

ドキュメンテーションコメント

専用ツールでAPIドキュメントを生成したり、メソッド名上マウスオーバーで説明を表示したりできるやつ。

  • Java: Javadoc形式で記述する。 /** ~ */
    • Eclipseでは、対象メンバにカーソルを当ててから Alt+Shift+J で生成できる
JavaDoc.java
/**
 * 引数で指定された2つの整数をかけ算し、その結果を返す。
 * @param a  かける数1
 * @param a  かける数2
 * @return かけ算の結果
 */
public static int doCalc(int a, int b) {
    return a * b;
}
  • VB: XMLで記述する。 '''
    • Visual Studioでは、 対象メンバのすぐ上の行で ''' と打つと生成できる。
XmlDoc.vb
''' <summary>
''' 引数で指定された2つの整数をかけ算し、その結果を返す。
''' </summary>
''' <param name="a">かける数1</param>
''' <param name="b">かける数2</param>
''' <returns>かけ算の結果</returns>
Public Shared Function DoCalc(a As Integer, b As Integer) As Integer
    Return a * b
End Function

参考

ファイル・フォルダ構成

※一部省略あり

Java (Eclipse)の例

  • JavaProject
    • bin
    • package
      • Main.class(ビルドされたJavaバイトコード)
    • src
    • package
      • main.java(ソースコード)
    • lib
    • doc
    • .project (Eclipseプロジェクトファイル)
    • .settings
    • .classpath

VB.NET Windows フォーム アプリケーション(Visual Studio)の例

  • VisualStudioSolution
    • VisualStudioSolution.sln (VSソリューションファイル)
    • FirstProject
    • FirstProject.vbproj (VBプロジェクトファイル)
    • bin
      • Debug
      • FirstProject.exe (ビルドされたデバッグ用実行ファイル)
      • Release
    • My Project
    • obj
    • App.config
    • Form1.vb (ソースコード[動作])
    • Form1.Designer.vb (ソースコード[デザイン])
    • SecondProject
    • (FirstProjectと同様)

Visual Studioでは、複数のプロジェクトをソリューションとしてまとめることができる。(Eclipseでもワーキング・セットというものもあるが)

変数

データ型分類

  • Java
    • 基本型(byte, short, int, long, float, double, char, boolean
    • 参照型(Stringなど)
  • VB
    • 値型(Byte, Short, Integer, Long, Single(float相当), Double, Decimal(10進型), Char, Boolean, Date など)
    • 参照型(String など)

日付型は、Javaではjava.util.Datejava.util.Calenderjava.timeなどの標準APIを使う必要がある(つまり必然的に参照型になる)。しかしVBでは、日付・時刻を管理できるDateを標準で用意している。

宣言・アクセス修飾

DeclareVariable.java
int number; // package private
String message; // package private
public int publicNumber;
private String privateMessage;
DeclareVariable.vb
Dim Something ' Private
Dim Number As Integer ' Private
Dim Message As String ' Private
Public PublicNumber As Integer

VB標準設定では、変数の宣言時に型の指定を省略することができる。その場合、初期値のデータ型に従って自動的に変数のデータ型も決められる(型の推定)。初期値がない場合はObject型とみなされる。Option Strict Onにすると、型の推定は無効になる。

変数名の規則

文字 Java VB 備考
半角英数字
日本語文字 もちろんあまり推奨されない
_ アンダースコア
& ×
先頭が数字 × ×

初期化

InitiarizeVariable.java
int number = 100; 
String message = "Hello"; 

InitiarizeVariable.vb
Dim Number As Integer = 100
Dim Message As String = "Hello"
Dim Pi = 3.14 ' 自動的にDouble型として扱われる
Dim BlankNumber As Integer ' 初期値は自動的に「0」になる
Dim BlankMessage As String ' 初期値は自動的に「Nothing」になる

定数宣言

Constant.java
final int MAX_STOCK = 100;
public static final String VERSION_ID = "v1.0.1-RELEASE";
Constant.vb
Const MAX_STOCK As Integer = 100
Const VERSION_ID As String = "v1.0.1-RELEASE" ' ConstステートメントではSharedは使えない

参考

演算子

算術演算子

機能 Java VB.NET 備考
加算 a + b a + b
減算 a - b a - b
乗算 a * b a * b
除算 a / b a / b
整数除算(商) N/A a \ b [VB] aとbはどちらも整数型でなければならない。
23 \ 5 の結果は4になる
剰余(余り) a % b a Mod b 23 % 5 ないし 23 Mod 5 の結果は3になる
累乗 (演算子としてはなし) a ^ b VBの^は算術演算子の中で優先順位が最も高いことに注意
インクリメント ++a または a++ N/A VBではa += 1などど書くしかない
インクリメント --a または a-- N/A VBではa -= 1などど書くしかない

整数同士の除算

Javaでは、割られる数aと割る数bの両方が整数だと、結果の小数点以下が切り捨てられ、整数になる。これは代入先がdouble型などの変数であっても変わらない。

DivideInteger.java
double x;
x = 23 / 5; // xは4.0になる

少なくとも片方が小数(倍精度浮動小数点数)だと、結果も小数になる。

java.DivideDouble.java
double x;
x = 23 / 5.0 // xは4.6になる

一方、VBではできるだけ精度が落ちないように演算が行われる。

DivideInteger.vb
Dim x As Double
x = 23 / 5 ' xは4ではなく4.6になる

VBでもJavaのように整数同士の除算をしたい場合に、\演算子を使う。
vb:DivideWithBackSlashOperator.
Dim x As Double
x = 23 \ 5 ' xは4になる

Javaにおける累乗

Javaでは、 java.lang.Math.pow(a, b) を使う。
第1引数aが底、第2引数bが指数(つまりVBでいうところの a ^ b)。

代入演算子

機能 Java VB.NET 備考
そのまま代入 a = b a = b
加算結果を代入 a += b a += b
減算結果を代入 a -= b a -= b
乗算結果を代入 a *= b a *= b
除算結果を代入 a /= b a /= b
整数除算の結果を代入 N/A a \= b
剰余(余り)を代入 a % b N/A [VB]Modに対応するものはない

(ビット演算系は省略)

比較演算子

機能 Java VB.NET 備考
aはbよりも小さい a < b a < b
aはb以下 a <= b a <= b
aはbよりも大きい a > b a > b
aはb以上 a >= b a >= b
aはbに等しい a == b a = b VBでは=は1個
aはbに等しくない a != b a <> b

論理演算子

以下の表ではABは条件式(True/Falseを返す式)を表す。

論理 機能 Java VB.NET
論理積(AND) AかつB N/A A And B
論理積(AND) AかつB(短絡評価) A && B A AndAlso B
論理和(OR) AまたはB N/A A Or B
論理和(OR) AまたはB(短絡評価) A && B A OrElse B
論理積(NOT) Aでない !A Not A
排他的論理和(XOR) AまたはB、しかしAかつBではない ^A A Xor B

短絡評価:
AがFalseなら条件式全体がFalseになることが確定するので、Bを評価せずに先へ進むこと。
このとき、Bに何らかのメソッドが書いてあっても実行されない。
これを利用して、AがTrueにならないとエラーになる式をBに書くことができる。
例: If Integer.TryParse(str, num) AndAlso num < 5 Then ...

連結演算子

Javaでは文字列の連結に + を使うが、VBでは & を使う。

VBでも+で文字列連結をすることは可能だが、片方が文字列型でない場合に意図しない結果となったり、エラーになる可能性があるため、Microsoftは&の使用を推奨している。

演算子の参考ページ

型変換

条件分岐

if文 / Ifステートメント

ConditionalBranch.java
if (age < 20) canBuyAlcohol = true;

if (age < 13) {
    fareType = "child";
} else if (age < 18) {
    fareType = "student";
} else {
    fareType = "adult";
}

ConditionalBranch.vb
If age < 20 Then canBuyAlcohol = True ' 1行ならばEnd Ifはいらない

If age < 13 Then
    FareType = "child"
ElseIf age < 18 Then
    FareType = "student"
Else
    FareType = "adult"
End If

VBでは、次のように「:」を使って複数のステートメントを1行に書くことも可能。

ConditionalBranchInOneLine.vb
If 20 < age Then FareType = "adult" : CanBuyAlcohol = true Else CanBuyAlcohol = false

Switch / Select Caseステートメント

1つの値と一致させる

ConditionalBranch2.java
switch (num) {
    case 1:
        gender = "男性";
        break;
    case 2:
        gender = "女性";
        break;
    case 3:
        gender = "その他";
        break;
    default:
        gender = "未回答";
        break;
}

switch文の式(上記のnum)は、基本型+String型(Java SE 7以降)のみ。

ConditionalBranch2.vb
Select Case Num
    Case 1
        Gender = "男性"
    Case 2
        Gender = "女性"
    Case 3
        Gender = "その他"
    Case Else
        Gender = "未回答"
End Select

複数の値に一致させる

ConditionalBranch3.java
switch (phoneNumberPrefix) {
    case 090:
    case 080:
    case 070:
        isMobile = true;
        break;
    default:
        isMobile = false;
        break;
}
ConditionalBranch3.vb
Select Case PhoneNumberPrefix
    Case 090, 080, 070
        IsMobile = true
    Case Else
        IsMobile = false
End Select

値の範囲を指定する

ConditionalBranch4.java
// JavaのSwitch文ではできない(やるとしても別の変数を噛ませるしかない)
ConditionalBranch4.vb
Select Case MonthNumber
    Case 3 To 5
        Season = "春"
    Case 6 To 8
        Season = "夏"
    Case 9 To 11
        Season = "秋"
    Case Else
        Season = "冬"
End Select

比較演算子を使う

ConditionalBranch5.java
// JavaのSwitch文ではできない(素直にif文使った方が良い)
ConditionalBranch5.vb
Select Case Score
    Case Is < 60
        Grade = "F"
    Case Is < 70
        Grade = "C"
    Case Is < 80
        Grade = "B"
    Case Is < 90
        Grade = "A"
    Case Else
        Grade = "S"
End Select

繰り返し

for文 / Forステートメント

ForLoop.java
for (int i = 0; i <= 9; i++) {
    System.out.println(i + "回目の繰り返し処理です");
}
ForLoop.vb
For i As Integer = 0 To 9 Step 1 ' 増分値1の場合、Stepは省略可能
    Debug.WriteLine(i & "回目の繰り返し処理です")
Next

どちらの言語でも、For文の初期化式内でループカウンタを宣言するのではなく、For文の外で宣言した変数を使うこともできる。その場合、For文を抜けてもその変数を使うことができる。

ForLoop2.java
int i;
for (i = 0; i <= 9; i++) {
    System.out.println(i + "回目の繰り返し処理です");
}
System.out.println(i + "回繰り返されました");
ForLoop2.vb
Dim i As Integer
For i = 0 To 9 Step 1 ' 増分値1の場合、Stepは省略可能
    Debug.WriteLine(i & "回目の繰り返し処理です")
Next
Debug.WriteLine(i & "回繰り返されました")

拡張for文 / For-Eachステートメント

ForEachLoop.java
int[] scoreArray = {70, 80, 90};

// 通常のfor文
for (int i = 0; i < scoreArray.length(); i++) {
    System.out.println(scoreArray[i]);
}

// 拡張for文
for (int score : scoreArray) {
    System.out.println(score);
}
ForEachLoop.vb
Dim ScoreArray() As Integer = {70, 80, 90}

' 通常のfor文
For i As Integer = 0 To UBound(ScoreArray) 
    Debug.WriteLine(ScoreArray(i))
Next

' For Eachステートメント
For Each score As Integer In ScoreArray
    Debug.WriteLine(score)
Next

while文 / While-End Whileステートメント

条件がtrueである限り実行し続ける。

WhileLoop.java
int i = 0;
while (i < 10) {
    System.out.println(i + "回目の繰り返し処理です");
    i++;
}
WhileLoop.vb
Dim i As Integer = 0
While i < 10
    Debug.WriteLine(i & "回目の繰り返し処理です")
    i += 1
End While

※このサンプルではWhileよりもForのほうが適している

do-while文 / Do-Loopステートメント

後判断型(1回は実行される)

DoWhileLoop.java
Random rd = new Random();
int num = 0;
do {
    num = rd.nextInt(100) + 1;
    System.out.println(num);
} while (num % 2 == 0);
DoLoopWhile.vb
Dim rd As Random = new Random()
Dim Num As Integer = 0

Do
    Num = rd.Next(1, 100)
    Debug.WriteLine(Num)
Loop While Num Mod 2 = 0

VBでは、Loop While 条件 (条件がfalseになるまで繰り返す)のほか、Loop Until 条件(条件がtrueになるまで繰り返す)というのも使える。

DoLoopUntil.vb
Dim rd As Random = new Random()
Dim Num As Integer = 0

Do
    Num = rd.Next(1, 100)
    Debug.WriteLine(Num)
Loop Until Num Mod 2 <> 0

Until以下の条件が逆転しているが、DoLoopWhile.vbDoLoopUntil.vbはどちらも同じ処理になる。

前判断型(1回も実行されない可能性がある)

DoLoopWhile2.vb
Dim i As Integer = 0
Do While i < 10
    Debug.WriteLine(i & "回目の繰り返し処理です")
    i += 1
Loop
DoLoopUntil2.vb
Dim i As Integer = 0
Do Until i >= 10
    Debug.WriteLine(i & "回目の繰り返し処理です")
    i += 1
Loop

ループを抜ける

  • Javabreak;
  • VB:Exit DoExit ForExit While

途中で次の繰り返しに進む

  • Java:continue;
  • VB:Continue DoContinue ForContinue While

配列

宣言

カッコの中で指定する数字の意味が違う点に注意。

ArrayDecralation.java
int[] numArray = new int[5];

インデックス 0, 1, 2, 3, 4 の合計5個の要素を持った配列になる。
[n] で指定するのは配列の要素数

ArrayDeclaration.vb
Dim NumArray(4) As Integer

インデックス 0, 1, 2, 3, 4 の合計5個の要素を持った配列になる。
(n) で指定するのはインデックスの最大値

初期化

ArrayInit.java
int[] numArray = { 10, 20, 30, 40, 50 };
ArrayInit.vb
Dim NumArray() As Integer = { 10, 20, 30, 40, 50 }

代入・利用

ArrayUse.java
numArray[3] = 31;

int a = numArray[3];
ArrayUse.vb
NumArray(3) = 31

Dim a As Integer = NumArray(3)

多次元配列

MultiDArray.vb
int[][] numArray = new int[3][4];
double[][] doubleArray = { { 0.0, 0.1, 0.2 }, { 1.1, 2.2, 3.3, 4.4 } };
MultiDArray.vb
Dim NumArray(2, 3) As Integer
Dim DoubleArray(, ) As Double = { { 0.0, 0.1, 0.2 }, { 1.1, 2.2, 3.3, 4.4 } }

(, )は一見するとインデックス最大値を入れ忘れているようにも見えるが、Javaでいう[][]に相当するもの。

配列サイズの変更

Javaでは一度作った配列のサイズを変更することはできず、新たに配列を作ってそこに値を移し替えるしかない。

しかし、VBではReDimステートメントを使うことで配列のサイズを変更できる。

ChangeArraySize.vb
Dim NumArray(9) As Integer

' ...

ReDim Preserve NumArray(6)

Preserve を付けると、元の要素の値が保持される(付けないと全ての要素が空になる)。
要素数を減らした場合、減らされた分の要素は削除される(上記例では、インデックス7, 8, 9の3要素は削除される)。

配列の長さ(要素数)

  • Java
    • 配列名.length (要素数を返す) を使う。
ArrayLength.java
int[] numArray = new int[5];

for (int i = 0; i < numArray.length; i++) {
    numArray[i] = i; 
}
// 配列の中身は {0, 1, 2, 3, 4} になる
  • VB:
    • 配列名.Length要素数を返す)を使う。
    • 繰り返しで全要素を処理する場合は、 UBound(配列名)インデックスの最大値を返す)を使う。
    • For文の To< ではなく <= の意味。
    • したがって、 0 To 配列名.Length と書くと、最終回で配列の長さを突き抜けてしまい System.IndexOutOfRangeException になる。
    • どうしてもUBound() を覚えたくなければ、配列名.Length - 1でもいけなくはないが…
ArrayLength.java
Dim NumArray(4) As Integer

For i As Integer = 0 To UBound(NumArray)
    NumArray(i) = i
Next
' 配列の中身は {0, 1, 2, 3, 4} になる

メソッド / プロシージャ

概念の整理(整理し切れていない)

基本的に、「メソッド」=「プロシージャ」だと思っても実用上は困らない。

Javaでは「メソッド」しか出てこないのに対して、VBではどちらの単語も登場する。やっていることは同じ「一連の処理をまとめる」ということだが、「メソッド」は、プロシージャの中でもその所属元を意識している言葉、らしい。

「オブジェクト」が持つ「性質」(フィールド)と「機能」(メソッド)、という感じ。

ただ、英語で "what is the difference between a method and a procedure in visual basic" ってググると、"method vs procedure" じゃなくて "function vs procedure" って書いてあるページばかりがヒットする(method = function?)
このあたりはプログラム言語の歴史(関数 function とか サブルーチン subroutine)にかかわってきそう。

参考

用語の比較

対象 Java VB
戻り値を返さない処理 メソッド(void Subプロシージャー
戻り値を返す処理 メソッド(void以外) Functionプロシージャー
クラスフィールドの読み書きをする処理 getter/setterメソッド Propertyプロシージャー
個々のインスタンスに属する処理 インスタンスメソッド (普通のSub/Functionプロシージャー)
クラス全体に属する処理 staticメソッド 共有(Shared)メソッド
イベントに応じた処理 N/A イベントハンドラー(Subプロシージャーの一形態)

Subプロシージャー

戻り値を返さない 処理。(直接の戻り値がないだけなので、参照渡しを使って呼び出し元に存在する変数やオブジェクトを書き換え、データを返すようなことは可能)

  • Java: アクセス修飾子 [static] void 名前(型名 引数名, ...) {}
VoidMethod.java
public void showMessage(int a, int b) {
    System.out.println(a + b);
}
  • VB: アクセス修飾子 [Shared] Sub 名前(引数名 As 型名, ...)End Function
    • イベントハンドラーもここに属する(後ろに Handles句が付くやつ)
SubProc.vb
Public Sub ShowMessage(Str1 As String, Str2 As String)
    Debug.WriteLine(a + b)
End Sub

Functionプロシージャー

戻り値を返す処理。

  • Java: アクセス修飾子 [static] 戻り値の型 名前(型名 引数名, ...) {}
    • return で戻り値を指定する
ReturnMethod.java
public int doCalc(int a, int b) {
    return a * b;
}
  • VB: アクセス修飾子 [Shared] Function 名前(引数名 As 型名, ...) As 戻り値の型End Function
    • Return で戻り値を指定する
FunctionProc.vb
Public Function DoCalc(a As Integer, b As Integer) As Integer
    Return a * b
End Function

Propertyプロシージャー

→ クラスの項目で解説

プロシージャーを途中で抜ける

ExitMethod.java
public void showMessage() {
    if (errFlag) {
        return; // 実はvoidメソッドでもこれで抜けられる
    } else {
        System.out.println("処理成功")
    }
}

public int doCalc(int a, int b) {
    int result = a * b;
    if (result > 10) {
        return 0; // 値を返さずに抜けることは許されない
    } else {
        return result;
    }
}
ExitProcedure.vb
Public Sub ShowMessage() 
    If ErrFlag Then
        Exit Sub ' VBではExit Sub
    Else
        Debug.WriteLine("処理成功")
End Sub

Public Function DoCalc(a As Integer, b As Integer) As Integer
    Dim result As Integer = a * b
    If (result > 10) Then
        Exit Function ' 戻り値がInteger型なので0を返す
    ElseIf (result > 50) Then
        DoCalc = result + 1
        Exit Function ' 変数DoCalcに設定した値を返す
    Else
        Return result
    End If
End Function

Javaだとreturnせずにvoid以外のメソッドを抜けることは不可能だが、VBのFunctionプロシージャーではできてしまう。
ただし、戻り値の型によってはぬるぽ例外を発生させるなど、予期しない動作を招く原因になりかねないので、必ずReturnすべきと思われる。

可変長引数

  • Java: 引数を (データ型... 変数名)とする
    • 当該メソッド内では、配列変数のように扱うことができる
    • 他の引数も指定する場合、可変長引数は引数リストの最後に置かなければならない
VariadicMethod.java
public static int getSum(int... numbers) {
    int sum = 0;
    for (int i = 0; i < numbers.length; i++) {
        sum += numbers[i];
    }
    return sum;
}
  • VB: (ParamArray 変数名 As データ型[]) とする
    • 性質はJavaと同じ。
VariadicFunction.vb
Public Shared Function GetSum(ParamArray Numbers As Integer[]) As Integer
    Dim Sum As Integer = 0
    For i As Integer = 0 To UBound(Numbers)
        Sum += Numbers(i)
    Next i
    Return sum;
End Function 

可変長引数の参考文献

オブション引数

呼び出し時に省略可能な引数。

  • Java: (たぶん)言語仕様として持っていない。
    • Java 8 から導入されたOptional型は、全く違う概念なので混同しないこと。
  • VB: (Optional 変数名 As データ型 = 既定値) とする
    • 呼び出し時に省略された場合、既定値が渡されたものとみなされる。
    • なので既定値は必ず指定しておく必要がある。
    • Optionalを指定した引数移行のすべての引数は、Optionalでなければならない(省略できない引数を全て書いた後、Optional引数を書く)
    • Optional引数を複数設けること自体はOK。
OptionalArguments.vb
Public Shared Function Calc(Num1 As Integer, Num2 As Integer, Optional CalcMethod As Integer = 0)
    If CalcMethod = 0 Then
        Return Num1 + Num2
    ElseIf CalcMethod = 1 Then
        Return Num1 - Num2
    ElseIf CalcMethod = 2 Then
        Return Num1 * Num2
    ElseIf CalcMethod = 3 Then
        Return Num1 / Num2
    Else
        Return 0
    End If
End Function

この例では、Calc(5, 10)のように呼び出した場合、CalcMethod = 0のパターン(つまり足し算)が実行される。

返り値として複数の値を受け取る

  • Java: クラスにまとめて、そのオブジェクトを返すしかない。
ReturnMultiValue.java
public static Result getResult(int a, int b) {
    Result result = new Result();
    result.setSum(a + b);
    result.setDiff(a - b);
    result.setProduct(a * b);
    result.setQuotient((double) a / b);
    Return result;
}
Result.java
public Class Result {
    int Sum;
    int Diff;
    int Product;
    double Quotient;

    // getter / setter 
}
  • VB: タプルを利用して複数の値を返すことができる
    • タプル:その場で複数の変数を1つにまとめたもの
    • 臨時のクラスを作る、というイメージだと分かりやすいだろうか
Tuple.vb
Public Sub Main()
    ' タプルを名前付きで宣言
    Dim Result As (Sum As Integer, Diff As Integer, Product As Integer, Quotient As Double)

    Result = GetResult(5, 10)

    ' タプルに入った値を利用
    Debug.WriteLine(Result.Sum)
    Debug.WriteLine(Result.Diff)
    Debug.WriteLine(Result.Product)
    Debug.WriteLine(Result.Quotient)
End Sub

' タプルを返すFunctionプロシージャー
Public Shared Function GetResult(a As Integer, b As Integer) As (Integer, Integer, Integer, Double)
    Return (a + b, a - b, a * b, a / c)
End Function

エントリポイント

プログラムが起動されたときに、最初に実行されるメソッド。

Javaはmainと名の付くメソッドが必ずエントリポイントになるが、VBではそうとは限らない。Windows Formsプロジェクトを作成すると、最初に作成したフォームがエントリポイントになる。これを変更する方法については、JavaのmainメソッドをVB.NETで作成してみる! | ライズウィルスタッフブログが詳しい。

クラス

構成

  • Javaクラス public class Main{ }
    • フィールド
    • メソッド
    • getter/setterメソッド

※JavaBeansの形式に従った例。

JavaClass.java
public class JavaClass {
    // フィールド(オブジェクトの状態/性質を示すもの)
    private int field;

    // メソッド(オブジェクトの動作・振る舞いを示すもの)
    public void method(){
        // ...
    }

    // メソッド > getter(カプセル化されているprivateフィールドの読み取り機能を提供)
    public int getField() {
        return field;
    }

    // メソッド > setter(カプセル化されているprivateフィールドへの書き込み機能を提供)
    public void setField(int value) {
        this.field = value;
    }
}
  • VBクラス Public Class Main ... End Class
    • フィールド(メンバ変数)
    • プロパティとの区別のために、_を接頭辞として付ける場合がある
    • プロパティ
    • Getプロシージャー
    • Setプロシージャー
    • プロシージャ(メソッド)
    • イベント
VBClass.vb
Public Class VBClass
    ' フィールド(メンバー変数)
    Dim _field As Integer

    ' プロパティ
    Property field() As Integer
        Get
            Return _field
        End Get
        Set(ByVal value As Integer)
            _field = value
        End Set
    End Property

    ' プロシージャー
    Public Sub Procedure()
        ' ...
    End Sub
End Class

プロパティについてもっと詳しく

基本

プロパティは、Javaでいうところのgetter/setterメソッドをまとめたもの(Getプロシージャ・Setプロシージャのうち片方だけを実装することもできる)。
Javaと異なるのは、プロパティは当該クラスの外からはフィールドのように扱われるという点である。

たとえば、上記サンプルコード JavaClass.java の プライベートフィールド field に他のクラスからアクセスするときには、次のようなコードを書く必要がある。

AccessToField.java
public class Main {
    public static void main(String[] args) {
        JavaClass jc = new JavaClass();

        // 以下2行はコンパイルエラーになる
        int num = jc.field;
        jc.field = 100;

        // 代わりに、こう書く
        int num = jc.getField();
        jc.setField(100);
    }
}

このように、オブジェクト変数名.フィールド名 ではアクセスが拒否されるので、代わりにgetterメソッドの返り値としてフィールドの内容を受け取ったり、setterメソッドに値を引数として渡すことでフィールドの内容を書き換えるというやり方になる。

これと同じような動きをVBで書くと、こうなる。

AccessToField.vb
Public Class Main
    Public Shared Sub Main
        Dim vbc As New VBClass()

        Dim num As Integer = vbc.field 'Get呼び出し
        vbc.field = 100 'Set呼び出し
    End Sub
End Class

プロパティ名をフィールドのように書くことで、そのプロパティに定義されたGet/Setプロシージャーが暗黙的に呼び出される。

自動実装プロパティ

なお、単に値を返す/書き込むだけのプロパティであれば、自動実装プロパティを使うことでコードを簡略化できる。

AutoImplProperty.vb
Public Class AutoImplProperty
    Public Property Name As String
    Public Property Owner As String = "DefaultName"
    Public Property Items As New List(Of String) From {"M", "T", "W"}
    Public Property ID As New Guid()
End Class

自動実装プロパティ - Visual Basic | Microsoft Docs より)

このとき、プロパティ名に_を付けた隠しPrivateフィールド(バッキング フィールド)が自動的に作成される。上記の例では、_Name, _Owner, _Items, _ID というバッキングフィールドが作成される(従って、自分でこれらと同じ名前のフィールドを宣言するとコンパイルエラーになる)

プロパティ:フィールド = 1:n もOK

また、プロパティはフィールドと1対1で対応している必要はない。言い換えると、複数のフィールドから値を拾ってきて、連結して1つのフィールドのように扱うこともできる。また、1つのまとまった値を受け取り、実際には2つ以上のフィールドに分割して格納する、ということもできる。(もちろんそれに見合ったGet/Setプロシージャを定義しておく必要はある)。
Microsoft Docsにわかりやすい例があったので、引用する(クラス内のメンバであることが分かりやすいよう、Public Class ~ End Classを付加している)。

次のプロパティは、フル ネームを 2 つの構成要素名 (名と姓) として格納します。 呼び出し元のコードが fullName を読み取ると、Get プロシージャが 2 つの構成要素名を結合し、フル ネームを返します。 呼び出し元のコードが新しいフル ネームを割り当てると、Set プロシージャがそれを 2 つの構成要素名に分割することを試みます。 スペースが見つからない場合は、すべてが名として格納されます。.
Property プロシージャ - Visual Basic | Microsoft Docs

CombinedProperty.vb
Public Class CombinedProperty
    Dim firstName, lastName As String

    Property fullName() As String
        Get
        If lastName = "" Then
            Return firstName
        Else
            Return firstName & " " & lastName
        End If

        End Get
        Set(ByVal Value As String)
            Dim space As Integer = Value.IndexOf(" ")
            If space < 0 Then
                firstName = Value
                lastName = ""
            Else
                firstName = Value.Substring(0, space)
                lastName = Value.Substring(space + 1)
            End If
        End Set
    End Property
End Class

呼び出し側:

CallProperty.vb
fullName = "MyFirstName MyLastName"
MsgBox(fullName)

その他、プロパティとメンバ変数の違いについては以下のページも参照。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む