[Tips] OpenOffice.orgとOffice Viewerを併用する

以前のエントリで書いたとおり、弊社はオフィス文書や教材の作成にはOpenOffice.orgを使っています。もちろん、OpenOffice.orgの機能にも満足しているのですが、やはり、弊社のような零細企業はできるだけコストを節減したいために、無償で使えるツールには魅力を感じているのです。

とはいえ、 やはりオフィス文書は自社内だけで使うものではありません。特に、研修関係の業務では、教材はMicrosoft Office形式であることがほとんどです。OpenOffice.orgもMS Office形式との互換性はかなり高いのですが、やはり完全ではありませんので、レイアウトが崩れてしまうことが結構あります。

PowerPointについては、閲覧だけでなく作成することも多いため、 正規版を購入しましたが、Word/Excelについても正規版を購入するとなると・・・冒頭に書いた問題に突き当たるわけですね。

どうしようかと思っていたのですが、実は、閲覧に限れば、PowerPoint/Word/Excelにはビューアがあり、Microsoftから無償でダウンロードできることを、今日になって知りました。PowerPointのビューアがあることは以前から知っていたのですが、Word/Excelにもあったのですね。

ということで早速インストールしました。これで、研修で使う教材がWord/Excel形式でも安心です。

自社で作る教材や、社内文書は変わらずOpenOffice.orgを使い、MS形式のドキュメントの表示にはOffice Viewerを使うことで、当面はMicrosoft Officeを購入しなくてもしのげそうです。

[Java][Tips] JSPのスクリプトレットで{ }のないループ処理を書いたらどうなるか

今週は、研修講師でサーバサイドJavaを教えておりますが、受講生からこのような質問が。
「{ }のないループをスクリプトレットで書いたらどうなりますか?」

普段、自分が担当する研修では、「forループやif文では、{ }をつけずに記述することも出来るが、可読性も考慮して普通は{ }をつけるようにしましょう」と指導していることが多いので、こういった質問が出ることも少なく、実は自分でも検証してみたことがなかったので、質問されたその場で、実験してみました。

たとえば、

<% for(int i=0;i<10;i++) %>
こんにちは

のようなコードを書くと、エラーにこそなりませんが、画面には何も表示されません。このようなコードは、Javaに変換されると、以下のようなコードになってしまうんですね。


for(int i=0;i<10;i++)
out.write("\r\n");
out.write("こんにちは\r\n");

つまり、スクリプトレットの後に続く「改行」が、1行分の「out.write文」に変換されてしまうために、「改行が10回表示されるだけ」で、期待されたような「こんにちは」を表示するループ処理にならないというわけです。

それならば、こういうコードなら良いのか?と試してみましたところ

<% for(int i=0;i<10;i++) %>こんにちは

こちらは、期待どおり?に

for(int i=0;i<10;i++)
out.write("こんにちは\r\n");

と変換され、「こんにちは」と10回表示させることが出来ます。

しかしながら、ループさせたいHTMLに、以下のようにExpressionを混ぜてしまうと

<% for(int i=0;i<10;i++) %>こんにちは< %= i %>

Expressionの処理の部分が1行で変換され、前後のHTMLドキュメントと合わせて複数行に分割されてしまうため、変数iが参照できずコンパイルエラーになってしまいます。変換はこんな感じになります。

for(int i=0;i<10;i++)
out.write("こんにちは");
out.print( i );
out.write("\r\n");

以上の結果はTomcat5.5.27で試したものです。このようなJSPからサーブレットへの変換に関して、仕様でどの程度決められているものなのか、調べていないので、どんなサーブレットのコードに変換されるのかは、実装依存なのかもしれません。

ご参考までに・・・。

[Tips] OpenOffice.org 3.1 Impressの不具合

弊社は、創業以来、普段からOpenOffice.orgを使っております。研修で使用するスライドなども、PowerPointではなくOpenOffice.orgのImpressを使って書いています。顧客とのやりとりがないドキュメントであれば、OpenOffice.orgでもほとんど不便を感じることはありません。もし、顧客に見てもらうだけのドキュメントで良ければ、PDFに変換して顧客に送れば済んでしまいます(OpenOffice.orgは標準でPDF出力機能を持っています)。そんなわけで非常に重宝しています。

もちろん、スライドは研修受講者の皆様に印刷して配布するのですが、最新のOpenOffice.org 3.1を使うと、配付資料印刷(1ページに2スライドずつ印刷するなどの形式)でページ下部に印刷されるページ番号が全て「1」になってしまうという現象に遭遇しました。

再現性などは追求していないのでわからないのですが、 OpenOffice.org 3.0では、こういった現象が起きないので、バージョン3.1固有の不具合ではないかなあと想像しています。

ご参考になりましたら幸いです。

[Java][Tips] Calendar#get(Calendar.MONTH)の戻り値

研修なんかでJavaの文法やAPIを教えていると、なぜそんな仕様なんだろう、と思うものが結構あります。

ということで、「どうしてこんな仕様にしてしまったのでしょう」シリーズ第2回は、java.util.Calendar#get(int)メソッド(引数Calendar.MONTH)です。CalendarクラスのgetメソッドにはCalendarクラスのstaticフィールドを指定することで、保持している日時の好きなフィールドを取得することが出来ます。たとえば、次のようなコードでは、システム時刻の年月日を表示させることが出来るわけです(import/import staticは適宜行っているものとします)。

Date d = new Date();
Calendar cal = new GregorianCalendar();
cal.setTime(d);
System.out.println(cal.get(YEAR));
System.out.println(cal.get(MONTH));
System.out.println(cal.get(DATE));

今日は2009年6月22日ですから、表示結果は

2009
6
22

となることが予想されますが、実行結果は


2009
5
22

となってしまいます。つまり、Calendar#get(Calendar.MONTH)の戻り値は「月」なんですが、1月が「0」、12月が「11」なのです。

もしかすると、何か、深い意味があるのかもしれませんが、 素直に考えれば、年も日も値どおり2009年は「2009」、22日は「22」で取得できるようになっているのですから、月も値どおり取得できるようにしても良かったのではないかと思いますよね。

また、思いついたら、エントリをあげたいと思います。

[VirtualBox][Tips] Bridged Networkでブリッジ接続が簡単に

Linuxのちょっとした試験用のサーバ環境を作りたいときなど、マシンを用意せずにいつものデスクトップPC内で仮想的に準備できてしまう仮想化ソフトウェアは非常に重宝しますよね。

そんな仮想化ソフトウェアでお気軽に試せるものとして私が個人的に気に入っているのが「VirtualBox」です。動作も安定していますし速度もそれなりに出ます。

ただ、ちょっと面倒なのがネットワーク関連の設定です。

たとえば試験用のLinuxサーバをVirtualBoxで作りたい場合、仮想化環境(ゲストOS)からインターネットに接続できるようにする必要もありますし、外部(ホストOSやそのネットワーク内のマシン)から仮想化環境にアクセスできるようにする必要もあります。

ちょっと前までのVirtualBoxでは、VirtualBox用のホストインターフェースというのを作成し、通常のネットワーク接続(有線LANや無線LAN)との間にブリッジ接続を作成しなければなりませんでした。しかも、無線LANとのブリッジはうまく機能しないことが多く、ノートPCなどで無線LANで外部に接続している場合などに不便でした。

最新のVirtualBox(2.2.4で確認)では、仮想化環境のネットワークに関する設定に、「Bridged Network」というのが追加されていて、これを使うと上記の「ホストインターフェースを作って通常の接続とブリッジする」ような操作をより簡単に行うことが出来ます。さらにうれしいのが、無線LANとのブリッジもきちんと動作することです。これによってVirtualBoxはさらに便利になったと思います。

[Java][Tips] String#substringメソッドの仕様

研修なんかでJavaの文法やAPIを教えていると、なぜそんな仕様なんだろう、と思うものが結構あります。

その中のひとつが String#substringメソッドです。このメソッドは文字列から部分文字列を抜き出すためのメソッドですが、第一引数が開始インデックス、第二引数が終了インデックスを表します。文字列のインデックス番号は0番から始まりますので、たとえば、”Knowledge-ex.”という文字列から、”led”を取り出して標準出力に表示したければ、

String str = "Knowledge-ex.";
System.out.println(str.substring(4,6));

とすればよさそうに思えます。 しかしながら、substringメソッドの第二引数は「終了インデックス+1」の番号を指定しないといけないのです。つまり、上記のコードでは、最後の”d”が欠けてしまい、

le

と表示されてしまいます。正しく意図どおりに表示するには、

String str = "Knowledge-ex.";
System.out.println(str.substring(4,7));

としなければなりません。

もしかすると、何か、深い意味があるのかもしれませんが、 素直に考えれば、開始位置も終了位置もインデックス番号を指定できた方が間違いが少ないような気がします。

どうして、こんな仕様にしてしまったのでしょう。というシリーズ第1回でした。
また、思いついたら、エントリをあげたいと思います。

[Java][Tips] 変数の初期値(ローカル変数とフィールド)

意外と、普段からよくJavaを使っている方でも知らなそうなのが、Javaにおける変数の初期値ではないでしょうか。

static int a;
public static void main(String[] args) {

  System.out.println(a);

  int b;
  System.out.println(b);

  int[] c = new int[3];
  System.out.println(c[0]);

}

上記のコードで、コンパイルエラーになる変数はどれでしょうか?といわれたら、即答できますでしょうか。

答えはというと・・・「System.out.println(b);」だけなんですね。同じ変数でもフィールドには初期値が決められており、例えばint型であれば0があらかじめセットされます。ですからこの場合、aには初期値代入を明記しなくても0が入るのです。同じく、配列の初期化においても各要素の初期値が決められていますので、c[0]は0が入ります。

プログラミングの流儀として、変数は定義したままにするな、必ず明示的に初期値をセットしておけ、と教えられた人も多いと思います。私も、そんな部類の人間なので、実務で使うコードを書くときは習慣的にローカル変数でもフィールドでも初期値代入をしていたような気がします。なので恥ずかしながら社会人になって数年はこの事実を知らずにいました。

実際、初期値は決まってるんだから明記しないほうがいいのか、それでもやっぱり初期値代入は明記したほうがいいのか、考えどころですね。

[Java][Tips] インクリメント・デクリメント演算子を式の中で使うと

今月は、Javaの文法基礎を新人研修で教えているのですが、こんな質問がありました。


int a=5;
System.out.println(a++  +  a--);

を実行すると、「-1」と表示されるのですが、どうしてですか?

ふだん、インクリメント・デクリメント演算子を式に組み合わせて用いることがないので「ん?」と思ったのですが、インクリメント・デクリメント演算子は後置の場合「評価後演算」になるため、以下のような動作になるのだと思われます。

  • 左辺の「a++」は、式の値として「a」そのものの値(この例では5)を取り出してから、1加算(6になる)
  • 右辺の「a–」は、左辺で加算された「a」の値(この例では6)を取り出してから、1減算(5になる)
  • 式の結果自体は、上記によって「5-6」になるので、「-1」となる

私は資格系の研修はあまりやったことがないので、こういう現場であまり見かけなさそうな例はちょっと苦手です。もしかしたら上記の推測も全然違うのかもしれません・・・もし、間違ってるよ、というご指摘がありましたら、こっそりコメントでお知らせください(笑)。

[Java][Tips] ショートサーキット論理演算子

体系的にJavaを学習していないと、意外に知らなかったりするのが「ショートサーキット論理演算子」です。ショートカット演算子などとも呼ばれます。

論理演算子で「AND」の演算をする演算子には「&」「&&」が、「OR」の演算をする演算子には「|」「||」があります。それぞれ、後者の演算子がいわゆる「ショートサーキット論理演算子」です。

ショートサーキット論理演算子の特徴は、「左辺の結果だけで全体の演算結果が分かるときは、右辺の演算を省略する」という点にあります。

例えば、

int a = 1;
int b = 3;

の場合に、

(a>b)&&(b>1)

という演算をする場合、 (a>b)すなわち(1>3)はfalseになります。AND演算は左辺・右辺ともにtrueのときのみ全体がtrueになりますので、左辺の演算結果がfalseと判明した時点で、右辺を演算せずとも全体がfalseになることは自明です。このとき、ショートサーキット論理演算子を使っている場合には右辺の演算は省略され、全体の演算結果がfalseになります。

これが、OR演算の場合は

(a<b)||(a>2)

という演算をする場合、(a<b)すなわち(1<3)はtrueになります。OR演算は左辺か右辺のどちらか一方でもtrueであれば全体がtrueになるため、この例では全体がtrueになることは自明です。この場合も右辺の演算は省略され、全体の演算結果がtrueとなります。

これがどういうときに便利なのか、という話なんですが、例えば、「ある文字列がnullでなく、かつ長さが10以上」といった条件式を書きたい場合などがこれにあたります。次のような条件文でstrがString型の変数として、

if ((str != null)&(str.length()>=10)) { ・・・

という条件式を書いてしまうと、strがnullのときに、「&」の左辺と右辺を必ず評価(演算)してしまうために、右辺の演算でNullPointerExceptionが発生してしまいます。

if ((str != null)&&(str.length()>=10)) { ・・・

であれば、strがnullのときには、左辺の評価結果がfalseになるために右辺の評価は省略されますので、NullPointerExceptionの発生を回避し、正常に条件式の実行を続けることができます。

[Java][Tips] Javaにおけるスコープ(変数の有効範囲)の判断

新社会人シーズンということで、Javaの基本文法なんかのTipsも載せてみたいと思います。

Javaに限らず変数を扱うプログラミングにおいて初学者が迷いやすいもののひとつが、変数のスコープ(有効範囲)ではないかと思います。

Javaの場合は、おおむね次のような法則で判断すれば大丈夫です。

「スコープはブロック({~}で囲まれた範囲)の内側である」
(逆に言うと「ブロックの外側はスコープではない」 )

例えば、メソッド内のローカル変数のスコープはメソッド内のみで、メソッド外はスコープではありませんが、これはメソッドを囲むブロックが境界線になっていると見ることができます。


public void sample() {

int a = 100;
a = 150; // スコープ内は有効

}


public void foobar() {

a = 200;
// ↑ブロックの外はスコープ外なので無効

}

try~catch節におけるtryブロック内で定義した変数は、tryブロックの外はスコープではありませんし、if文、for文、while文などのブロック内で定義した変数もまた同様です。


public void demo() {

int b = 100;
if (b > 100) {

    int c = 100;

}
c = 200;
// ↑ブロックの外はスコープ外なので無効

}


public void trycatch() {

try {
     int d = 100;
} catch(Exception ex) {
     System.out.println(d);
     // ↑ブロックの外はスコープ外なので無効
}

}