無名クラスとは

javaやC#では、インスタンス変数をnewする際に、後ろに中かっこを記述し定義を行うことができます。
ここで定義されるものは「無名クラス(匿名クラス)」と呼ばれ、クラス名を新たに定義することなく、インスタンス変数のクラス・インターフェースを継承・実装したクラスを定義することができます。
(ちなみに、「ラムダ式」と呼ばれる文法は「無名クラス」を応用したものになります)

以下、javaの例です。

【サンプルコード】

・AnonymousClass.java

・AnonymousInterface.java

・AnonymousMain.java

【実行結果】


いかがでしたでしょうか。

無名クラスは、使い捨てのクラスを作りたい時に便利です。
また、前述のラムダ式等を理解する上でも、無名クラスを理解する必要があります。

javaの入門書には出てくることが少ない文法だと思いますが、javaに慣れたらこの文法も早い内に理解することをお勧めします。

java:標準入出力の入力元・出力先を変更する

javaには
・System.setIn
・System.setOut
・System.setErr
の3つのメソッドが用意されており、これらのメソッドにより標準入出力の入力元・出力先を変更することができます。
これらのメソッドを利用することで、標準入力や標準出力を使用している処理の立ち振る舞いを外から変えることができます。

以下は、標準入力をハードコーディングで与え、標準出力・標準エラー出力を文字列として受け取りファイルに出力する例です。

【サンプルコード】

・SystemInOut.java

・SystemInOutMain.java

【処理結果】

コンソールは入出力無し

・C:\tmp\test1.txt

・C:\tmp\test2.txt


いかがでしたでしょうか。

簡易なシステムやレガシーなシステムだと、標準入出力を入出力とするプログラムが少なくないと思います。
そのようなプログラムに対して、外側から立ち振る舞いを変えられるのは便利です。
例えば、JUnitでテストする時に便利だと思いますし、リファクタリングを行う一つの手段にもなり得ると思います。

役に立ちそうな技があれば今後も紹介していきたいと思います!

java:重複を排除する方法3選

今回は、javaでListの重複排除を行う方法を3つ紹介します。

1つ目の方法は、for文で自力でアルゴリズムを記述して重複排除を行う方法です。
記述が冗長になり、コーディングミスも起こりやすいことから、現在の実務ではこの方法で重複排除を行うことはないと思います。
しかし、新人研修でjavaの標準APIの学習が不十分な段階で使うケースが想定される他、実務でもCOBOLからjavaにコンバージョンしている等のレガシーな環境では見かけることがあるかもしれません。

2つ目の方法は、HashSet(順番を保証する必要がある場合はLinkedHashSet)を使用する方法です。
HashSetとは、重複を排除して要素を格納するクラスであり、自力で重複排除のアルゴリズムを記述する必要がないためコーディングミスは起こりにくいです。
コンストラクタでListとSetの相互変換も可能であることもあり、記述も簡潔になります。
実務ではHashSetを使うケースが多いと思います。

3つ目の方法は、StreamAPIを使用する方法です。
StreamAPIにはdistinctメソッドが用意されており、このメソッドを呼び出すことで重複排除が可能です。
Java8から導入された機能であり、背景に関数型プログラミングの考え方があることから、昔からjavaを書いてきた人は取っつきにくさを感じるかもしれません。
しかし、新しい物好きの現場ではStreamAPIの使用が好まれるでしょう。

以下、サンプルコードです。

【サンプルコード】

【実行結果】


いかがでしたでしょうか。

新人研修で重複排除の方法が話題になったので、この記事を書いてみました。

javaは歴史の長い言語であるため、一つのことを実現するだけでも色々と書き方があります。
また、今回紹介したように、時と場合により、どのような書き方をするか使い分けすることが望ましいです。

続・singletonとstaticの違い

こちらの記事について社内外でちょっとした議論になったので、その内容をまとめてみました。
Singletonパターンを利用する理由は「外部からnewさせたくないから」だと思っていましたが、「そう書いた方がわかりやすいから」「staticではないメソッドも利用可能になるから」という理由の方が大きそうです。

【指摘】

・privateコンストラクタを持った時点でnewできない

newさせたくないだけなら、オブジェクト取得メソッドは不要。
Singletonパターンで無くても良い。

・Singletonパターンの思想の表現としてオブジェクト取得メソッドが必要

書籍ではSingletonパターンはオブジェクト取得メソッドが必要とされている。
確かに、privateでオブジェクトを1つ生成、外部にはメソッド経由で提供する、とすれば、「オブジェクトは1つのみ存在する」という思想をわかりやすく表現できる。
人によってstaticの方が分かりやすいかSingletonパターンの方が分かりやすいかは違うと思うが、オブジェクト指向に慣れた技術者であればSingletonパターンの方が設計思想が分かりやすいというのはありそう。

・Singletonパターンだとstaticではないメソッドも参照可能になる

Singletonパターンであればクラスへの参照ではなくオブジェクトへの参照となる。
そのため、staticではないメソッドの参照も可能となる。
具体的には、継承・オーバーライドができるというメリットがある。

【サンプルコード】

・StaticMemory.java

・SingletonMemory.java

・SingletonMemoryChild.java

・MemoryTestMain.java

【実行結果】


この話、社内でちょっとした議論になりました。
おかげで色々理解が深まりました。

議論のきっかけを作れるというのも、技術ブログの良い所だと思いました。

java:実務で使うテクニックでfizzbuzzを解いてみた

10年ほど前に流行ったプログラミングの問題として、fizzbuzzと呼ばれる問題があります。
この問題は、応募者のプログラミング経験の有無を見極める問題であり、問題の内容は以下の通りです。
・1から100までの数を出力する。
・3の倍数の時は代わりに”fizz”と出力する。
・5の倍数の時は代わりに”buzz”と出力する。
・3の倍数かつ5の倍数の時は代わりに”fizzbuzz”と出力する。

「実務ではfizzbuzzのようなプログラムを書くことは無いから解けなくても良い」という意見もあるようですが、個人的にはfizzbuzzで使うテクニックは実務でも使えると思っています。

以下では、実務でも使うテクニックを用いてfizzbuzzを解いてみます。
(言語はjavaです。今回の記事の趣旨上、トリッキーな解答は除外します。)

・剰余を用いた一般的な解答パターン

恐らく、これが一番自然な解答なのではないかと思います。
剰余を用いて、「n % m == 0」と記述することで、「m毎に何かをする」という記述が可能になります。
性能の観点で、一定のデータが溜まってからまとめてログ出力やデータベース書き込みを行うことがあるのですが、そのような処理を記述する時に使えます。
その他、テストデータを生成する時にも、この書き方を用いると楽になる場合があります。
(例えば、100個データを用意し、その内偶数のデータについては特定のフラグが立ったデータにする等)

・同じ分岐の記述を避けるパターン

先に挙げた解答では「3の倍数の時」「5の倍数の時」の分岐が2回ずつ出現し、若干冗長なので、このように同じ分岐の記述を避ける解答もあります。
同じ分岐を複数記述すると、保守性が低下します。
(例えば、「3の倍数」を「4の倍数」としたい時に、修正漏れが発生する可能性が出てくる)
プログラマーは保守性にも気を配るべきなので、個人的にはこちらの解答の方がよりプログラマーっぽいと思っています。

・除算と乗算を組み合わせるパターン

剰余を使わずとも、整数型は小数点以下切り捨てになるということを知っていれば、このような解答を記述することもできます。
除算で小数点以下の切り捨てが発生する場合、同じ数で乗算を行っても元の数に戻らないので、それを利用しています。
除算による切り捨てを実務で用いる場合もあり、例えば100未満の位を切り捨てしたい場合は、「n = n / 100 * 100」と記述したりします。逆に切り上げたい場合は、「n = (n + 99) / 100 * 100」となります。
現代のプログラミング言語では切り捨てや切り上げを行う便利な関数が用意されているのでこのような書き方をすることは少ないですが、このような書き方を知らないと他の人のプログラムを読んでいて困ることがあるので、知っておいた方が無難です。

・カウンターを持たせるパターン

fizz用のカウンターとbuzz用のカウンターを持たせて、カウンターを上手く制御すると、剰余や切り捨てを利用しなくても解答を記述できます。
実務では、カウンターの数字自体に意味がある場合にこのような書き方をします。
例えば、「ログ1→ログ2→ログ3→ログ1…とローテーションさせたい」という場合に、「ログ1」「ログ2」「ログ3」の数字部分にカウンターの値をそのまま用いることができます。


いかがでしたでしょうか。

今回紹介した問題は難しくないものですが、その解き方で個性やテクニックを発揮することができそうなので、今回は色々と解答を紹介してみました。
実務で役に立つ問題があれば、これからも紹介していきたいと思います!