2011年06月21日

OutputStreamWriterやOutputStreamReaderの罠?

Javaにて、テキストファイルをオープンする際、最近ではUTF-8で記載したファイルも開くため、エンコーディングを事前に指定することも多いと思います。
本来は勝手にエンコーディングを見つけてくれると助かりますが、そういう処理も重たいですし、何よりプロジェクトにおいては共通化することがポイントだったりしますので、全体の決めでUTF-8とすることも多いでしょう。
もしかしたら、下記の内容、私のJavaの不勉強さで間違ったことを記載しているかもしれません。
その際はご容赦ください。


そういった場合に例えばPrintWriterを利用する場合、簡単には以下のように記載します。

PrintWriter pw = null;

try {
pw = new PrintWriter("ファイル名", "UTF-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (pw != null) {
pw.close();
}
}

このように実行した場合、PrintWriterのコンストラクタは以下のコードが実行されます。

public PrintWriter(String fileName, String csn)
throws FileNotFoundException, UnsupportedEncodingException {

this(new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(fileName), csn)), false);
}

※ 出典はJDK1.6 Update 26のソースコード(Copyright (c) 2006, Oracle)です。Oracle様、記載し申し訳ございません。

ポイントは、csnに変なエンコードを入れた場合、UnsupportedEncodingExceptionが出ることです。
この例外が出る前にはFileOututStreamの処理は成功しておりインスタンスは生成済みです。
その後、OutputStreamWriterのコンストラクタで例外が発生します。
その場合、FileOutputStreamのインスタンスはどうなってしまうのでしょうか。。。
普通はそのうち運がよければガベージコレクションが発動すると思います。
ガベージコレクションが発動すればfinalize内にclose()呼び出しがあるので、そこで確保されたリソースは解放されます。が、逆にガベージコレクションが発動されるまで開放されません。
何かしらのリソースをロックしてしまう可能性がありますので、注意する必要がありそうです。


普通は文字コードの設定などはプロジェクトの初期に行ってしまい、変更はしないものです。
ですが、ふとした作業(例えば変更してはいけないところを誤って変更していたなんてこともないとは言い切れないのが、この業界です)で、エンコーディングの指定を存在し得ないものにしていたなんてこともあるでしょう。通常はUnsupportedEncodingExceptionがスローされて、それをキャッチして異常終了させるとは思います。ですが、フレームワークによっては、そういった例外をもみ消して縮退運転的なことをさせることはないでしょうか?
それも普通はシステムの異常なのだから一度は止めてということもあるでしょうが、代替手段で行い、メインサーバは停止できないこともあります。私が関わっている案件はまさに止めるわけにはいかないシステム(止めてもいいけど、その後のリカバリが遅れたら〇〇億円とかになったらとか思うと。。。)です。。。

もみ消した場合は、ファイルがロックされたままだったり、利用しているStreamの種類によってはJNIの外でメモリリークも発生し、最悪はOutOfMemoryErrorとなり得ます。

なので、面倒なのですが私は必ずこのように記載するようにしています。


public void sample(File file, String encoding) {
PrintWriter pw = null;
BufferedWriter bw = null;
OutputStreamWriter osw = null;
FileOutputStream fos = null;

try {
fos = new FileOutputStream(file);
osw = new OutputStreamWriter(fos, encoding);
bw = new BufferedWriter(osw);
pw = new PrintWriter(bw);
} catch (Exception e) {
e.printStackTrace();
} finally {
close(pw, bw, osw, fos);
}
}

// 下記は本当はF/W側共通メソッドにしています。
public void close(Closeable... closeables) {

if (closeables == null) {
return;
}

for (Closeable c : closeables) {
if (c != null) {
try {
c.close();
} catch (Throwable e) {
}
}
}
}

こうすることで、実は例外発生時のスタックトレースも分割されるので、若干の処理速度とメモリ効率を犠牲にして、障害回復のしやすさを優先しています。
同じことはOutputStreamReaderでも言えると思います。

あとは、全てのJVMでfinalize()メソッドが確実に呼ばれるかどうか分かりませんので、確実にclose()するよう心がけておけばよいと考えます。
posted by Kiruahさん at 00:12| Comment(0) | TrackBack(0) | ノウハウ

2011年06月20日

私が上司になったら

私はまだ上司という立場ではありませんが、先輩後輩という立場でプロジェクト内で実践したことがあります。
それは、部下(この場合は後輩ですが)の愚痴や要望、やりたい事を聞くということです。
これは酒の席であれば、酒の勢いで話しやすいこともあるでしょうが、結局聞いたことを忘れてしまいやすいです。また、メモを取らなければ、真摯に聞くという気持ちも出てこないものです。

どんな内容でも愚痴を聞きました。「やり方が良くないのではないか」、「答えは分からないけど、これはおかしい」等です。
対して私の返答は「なるほど、〜ということで認識はあっている?」「なるほど、私もそう思う。では、一度持ち帰って率直に試してみるよ」「なるほど、私は〜だと思う」という感じで答えました。

また、最初は当然後輩といえでも身構えてしまうでしょう。どうやったって意図はなんだろうかと勘ぐってしまうものです。私は先に、こう目的を切りだしています。

1. 愚痴を出しきって、少しでもストレスを出したい。
大きな声で人に聞かれたくないことでも会議室なら聞かれにくい。
2. 酒の席では真面目に聞いてあげられなくなったりする。
でも、酒の席がよければそっちでも聞くよ。
3. 自分もたくさん愚痴があって、会社や自分の上司、もちろん君にも愚痴があって、
実は聞いてもらいたい。その愚痴から君も言いたいことを言っていいし、
自分で気づかなかったより良くする方法にこっそり気づいたらラッキーかなと思った。
4. プロジェクトは結局なんとか回る。
けれど、やりたくないことをずっとやり続けて回すんじゃなく、
やりたいことをやって、それでプロジェクトが回るように配置したいんだ。
5. 一対一なのは、他の人がいると言いにくいこともあるでしょう。
だからここの話はここだけの話にしてほしい。私の分は少なくともね。

直接口頭ではもっともっと簡単にピックアップして説明しますが、ここでは色々と目的を記載しました。


多くの上司や先輩は忙しいことも多く、また業務の進め方の良い点として、結論先出しもあって
「何が問題で、どうして欲しくて、それでどうなるかを説明しろ」
「愚痴とか誰かをせめるのではなく、建設的・前向きにプロジェクトをどうしていくかを考えよう」
「だからなんなのか?ただの愚痴で終わったら何もできない」
と言われやすいです。
ですが、本当のプロジェクトの問題は、あくまでも漠然としていて、しかも下っ端ではどうしたらいいか
力も権限も人脈も何もなく、それでも一番の実態を知っているのに何もできないという状況だと、私は考えます。だから上記のように言われると、下はもう何も言えないのではなく、言わなくなります。
また、上司は部下の言葉を真面目に効いていないとも思います。
いつもは「人生相談だってなんだって乗るよ」とか「なんで俺に相談しないんだ」など飲み会で言っていても、所詮それは言葉だけだと痛感させてしまうのです。

これは後輩たちが打たれ弱いのではなく、また勇気が足りないとか、昔と変わったとかではなく、誰でもそう感じるものです。ただ、そう感じた後にどう動くかが世代や性格によって違ってきているだけなのではないかと考えています。

でも、愚痴をメインにしたら結局答えはでないでしょう。それは分かっています。
人間は思っていることを言えないことがまた、大きなストレスになってしまいます。同期やさらに下の後輩に言っているうちは良いでしょうが、それでも解消しきれないストレスとなった場合、それは行き場を失います。本当は上に投げるべきものなのにです。
何でも言える場を提供してあげることも重要です。

また、下の愚痴からプロジェクトの問題点を抽出、推敲、類推できない上司は、正直なところもう無能な上司だと言われる時代だと考えるべきでしょう。
そこにはいろいろな問題点と解決策があるはずです。ただの愚痴だと思ってしまったら、ただの愚痴です。でも「そんなところに答えもアイディアもないと思うところにアイディアがあるかもしれない」とよく上司は言うのに、愚痴からはアイディアを探さないのは、単純に自分のことややり方を批判されたくないだけではないでしょうか。
上司の度量として、真摯に後輩の指摘を愚痴でも聞き、修正していくということを見せなければ、後輩が成長しない姿をなぜ注意できるのでしょうか。
「最近の若者はなかなか理解できない」は、簡単にいえば我々先輩がなかなか勉強もせず新しいことを取り入れていないからのように後輩からは見えています。だからこそ、私は誰よりも最先端のやり方も把握しようとしています。愚痴から取り入れようというのも、その一環です。。。
愚痴では前に進まないのではなく、また愚痴では結局どうしたら良いか分からないのではなく、その愚痴から本当の問題を抽出し、解決策を考えるのもマネジメント職の仕事だと私は考えます。

ただし上司側も、色々と聞き出したくて聴きに行くんだけど、やっぱりなかなか話してもらえないと思うでしょう。だからこそ、自分から自分の上司の愚痴をわかり易い言葉で後輩に先に話すのです。
先に、「上司がこうだから、本当はこうしてやりたいんだけどなかなかできないんだよね。。。難しいし、君が何がやりたいかもっと明確にしてくれたら、もっと君のやりたい事をサポートできて、それを理由に上も動かせるのにさ。だから、上を動かすためにも先に君のやりたい事を教えてほしい。もしくは一緒に考えよう」と言ったりします。



ただし、全ての後輩に対してやるとこれは大きな問題です。後輩一人ひとり性格が違います。
これをやって結局言いふらしてしまう子もいるでしょうし、私生活の話に飛んだりする子もいるでしょう。
真面目な子に対してやると効果的ですし、人によって時間をうまくコントロールすることも重要です。
人それぞれの性格をどれだけ見て、その子が何をしているかをどこまで把握しているか、当然上司として求められる物です。そこまでやって、適切に愚痴を聞き、プロジェクトを回すのが必要です。


私が上司になったら、どこまでうまくやれるかは分かりませんが、こういうことをしっかりやりメンバーマネジメントを図りたいと考えています。