No Programming, No Life

プログラミング関連の話題や雑記

Javaはつまらなくなったな

f:id:fumokmm:20191223002811p:plain:w500

これは、Javaに限った話ではないが、最近の流れとして、プログラミング言語がどれもこれも似てきてしまっているように思う*1。 あまりに言語が似すぎてしまうと、何を選んでも大差ない、選ぶ基準は動かせるプラットフォームとか、動作速度とか、そういった部分になってきてしまう。言語を選ぶ基準がその言語の特徴的な機能や、その言語でしか出来ないことでなくなってしまうことに、ワクワク感が薄れてしまうのは私だけだろうか。

AltJava言語達

このブログの読者の皆さんならきっとご存知と思うが、JavaはJava8でついに重い腰を上げて関数型の構文が取り入れた。そのあたりから進化のスピードが加速してきており、その後はJava10で型推論が導入されたり、Java12ではSwitch式が取り入れられたりと枚挙にいとまがない。 しかしJava8が世に出る以前から、AltJava言語*2では既に取り入れられていたものが多くある。 諸事情により、Java6で長い間更新が滞ってしまっていたこともあり、その間に多くのAltJavaが栄えたのではないかと思う。

その機能をよこせ

さて、このように「公式がなかなかやってくれないから俺がやるぜ!」と名乗りを上げた多数の言語達が、その当時Javaがまだ持っていなかった先進的な機能をどんどん繰り出すことによって優位性を誇示していた。 しかし現在、Javaは貪欲にそれらの機能を吸収し続けていっており、どんどん複雑になってきている*3。 こんな状況だから、心無い開発者から「もうその機能はJava自体で使えるんだから、AltJavaはいらないよねー」と言った声が聴こえてくると、とても悲しい。 誤解しないで欲しいのは、公式に採用されたことは非常に喜ばしいことであることに違いはない。世の中に広く普及するための第一歩を踏み出したのだ。だが、それでAltJavaのことを忘れないであげて欲しいのだ。牙を抜かれたライオンのような扱いはやめてあげて欲しい。

あえて削る

上であげたようなJavaの貪欲さとは対照的な美しさ、それはシンプルであることだと思う。 JavaJVMというシンプルなスタックマシンで動いている。コアはシンプルな方が美しい。本当に必要な機能だけを卒なく美しく提供してくれればそれでいい。それでよかったのだ。

Javaもかつては無駄な*4機能は削ぎ落す選択をしていた。だから未だにプロパティ*5を扱えなかったり、演算子オーバーロードできないし、もちろんポインタ*6も使えない。しかし、この状況だから、そのうちJavaでもプロパティが使えて、演算子オーバーロードできて、そしてついにはポインタが使えるようになってしまうかもしれない。そんなJavaはたぶんつまらない。 私はJavaをJava1.4の頃から使っているのだが、あの頃の不自由さが今思うと非常に懐かしい*7

多様性の海に

とりとめもなく書いてきたが、Javaに限らず、プログラミング言語は他の多種多様な言語の様々な機能に囲まれ、影響され、磨かれて進化してきたのだ。 たとえAltJavaが衰退しようとも、太りすぎたJavaがシンプルな新言語に将来もしかしたら駆逐されようとも、それはそれで。 この弱肉強食のプログラミングの多様性を最後まで見届けようと私は思う。

参考

Java8の新機能を徹底解説!(ラムダ式、Streamなど) | 侍エンジニア塾ブログ(Samurai Blog) - プログラミング入門者向けサイト

Java9の新機能とサンプルコード - Qiita

JDK9 Jigsaw を試してみた - Qiita

Reactive Programming with JDK 9 Flow API | Oracle Community

Java 10新機能まとめ - Qiita

Java9,10,11の新機能 - Qiita

Java8からJava11への変更点 - Qiita

Java12新機能まとめ - Qiita

[速報]Java 13が登場。ZGCの改善やSwitch式の実現など新機能。 Oracle Code One 2019 - Publickey

*1:JavaよりもむしろJavaScriptなんかの方が状況がひどいことになっているかもしれないが、それはまた別の機会に

*2:Scala, Kotlin, Groovyなど

*3:例えるなら、千と千尋の神隠しに出てくるカオナシみたいな感じだろうか

*4:少なくとも、複雑になることを犠牲にしてまで取り入れなかったという意味で

*5:.propertiesではなくて、クラスのプロパティのこと

*6:参照先アドレスの直接操作の話

*7:こんなことを考えるようになったというのは、歳を取ったからなのだろうか

Windows環境にRustをインストールする

f:id:fumokmm:20191216085325p:plain:w150:h150f:id:fumokmm:20191211185740j:plain:w150:h150

突然、RustをやりたくなったのでWindows環境にインストールしてみた。 その時のインストール手順をメモしておく。 環境やバージョンなどは以下の通り。最近インストールばっかりしてるなー。

環境

バージョン
OS Windows 10 (64bit)
Rust 1.39.0
rustup 1.20.2
Cargo 1.39.0

手順

インストーラーダウンロード

こちらよりダウンロード

f:id:fumokmm:20191217164935p:plain

ダウンロードした rustup-init.exe を実行

f:id:fumokmm:20191217164940p:plain

すると、C++コンパイラが要るよと言われるので、コンパイラを先にインストール

f:id:fumokmm:20191217164823j:plain

C++コンパイラをインストール

せっかくなので、Visual Studio 2019の方から入れてみた。

まず新しいプロジェクトの作成を選んで

f:id:fumokmm:20191217164827p:plain

C++ユニバーサル Windows プラットフォームツールを選んで

f:id:fumokmm:20191217164831p:plain

インストール開始

f:id:fumokmm:20191217164836p:plain

f:id:fumokmm:20191217164841p:plain

インストール完了!

f:id:fumokmm:20191217164845p:plain

Rustのインストール(続き)

Rustのインストールを再開

f:id:fumokmm:20191217164911j:plain

1) Proceed with installa (default)を選択

f:id:fumokmm:20191217164857j:plain

Rust is installed now Great!

f:id:fumokmm:20191217164902j:plain

インストール完了!

rustc --version でバージョン確認してみる

f:id:fumokmm:20191217164907j:plain

rustup --version でバージョン確認してみる

f:id:fumokmm:20191217164920j:plain

cargo --version でバージョン確認してみる

f:id:fumokmm:20191217164923j:plain

ということで、Rustがインストールできたみたい

Hello World

ひとまずget startedのハローワールドまでやってみた。

cargo new hello_world でプロジェクトが作成される

f:id:fumokmm:20191217164932p:plain

Visual Studio Codeで開いてみたところ。 hello_worldにTerminalで入っていって cargo runで実行できた

f:id:fumokmm:20191217164927j:plain

おしまい。

参考

Rust Programming Language

Windows 10 で Rust のインストール - Qiita

Excel VBAでUTF-8でパーセントエンコードされた文字列をデコードする(簡易版)

f:id:fumokmm:20191216193045p:plain

Excel VBAUTF-8でパーセントエンコードされた文字列をデコードする必要があり、ちょっと調べてみたらADODB.Streamを使うと出来そうだったのでやってみた。

環境

  • Windows 10 (バージョン 1903) 64bit
  • Excel Office365 MSO (16.0.12228.20322) 64bit

コード

Option Explicit

'''
' UTF-8でパーセントエンコードされた文字列をデコードします
'
' @param percentEncodedStr UTF-8でパーセントエンコードされた文字列
' @return デコードした文字列
'
' ※ADODB.Streamを利用するため、ツール > 参照設定で
' 「Microsoft ActiveX Data Objects 6.1 Library」を追加してください。
'
Public Function PercentDecode(percentEncodedStr As String) As String
  ' 空文字なら空文字を返却
  If IsEmpty(percentEncodedStr) Then
    PercentDecode = ""
    Exit Function
  End If

  ' ストリームをオープン
  Dim objStm As ADODB.Stream
  Set objStm = New ADODB.Stream
  objStm.Open
  
  ' ストリームをリセット
  objStm.Position = 0
  objStm.SetEOS
  
  ' バイナリを書き込み
  objStm.Type = ADODB.adTypeBinary
  objStm.Write ToHexBytes(percentEncodedStr)
  
  ' UTF-8でテキスト読み込み
  objStm.Position = 0
  objStm.Type = ADODB.adTypeText
  objStm.Charset = "UTF-8"
  PercentDecode = objStm.ReadText() ' 結果返却
  
  ' ストリームをクローズ
  objStm.Close
  Set objStm = Nothing
End Function

'''
' UTF-8でパーセントエンコードされた文字列をバイト配列に変換します
'
' @param percentEncodedStr UTF-8でパーセントエンコードされた文字列
' @return バイト配列
'
Private Function ToHexBytes(percentEncodedStr As String) As Byte()
  Dim size As Long
  size = Len(percentEncodedStr) / 3
  
  Dim bytes() As Byte
  ReDim bytes(0 To size - 1)
  Dim i As Long
  For i = 0 To size - 1
    bytes(i) = Val("&H" & Mid(percentEncodedStr, (i * 3) + 2, 2))
  Next i

  ToHexBytes = bytes
End Function

使い方

PercentDecodeがパブリック関数になっているので、こちらをExcelの数式などとして利用するだけ。引数はパーセントエンコードされた文字列を受け取り、戻り値はデコードした文字列となる。

デモ

f:id:fumokmm:20191216192520g:plain

注意

なお、すべての文字が3バイトにパーセントエンコードされていた場合しか想定していません。また、例外処理なども省略しています。あくまでテスト用ということで利用する際はもうちょっとアレンジが必要。

参考

EXCEL VBAメモ - UTF-8バイト列を文字に変換する - hakeの日記

NonSoft - ADODB.Streamによる文字コード変換のサンプル(VB6)

URLデコードを行う:エクセルマクロ・Excel VBAの使い方/ユーザー定義関数

Windows環境にElixirをインストールする

f:id:fumokmm:20191211185242p:plainf:id:fumokmm:20191211185740j:plain:w180:h150

突然、ElixirをやりたくなったのでWindows環境にインストールしてみた。 その時のインストール手順のスクリーンショットを貼っておきます。 環境やバージョンなどは以下の通り。

環境

バージョン
OS Windows 10 64bit
Elixir 1.9.4

手順

1. 公式サイトからインストーラーのexe1をダウンロード。

2. Click next, next, …, finish

elixir-websetup.exe を起動

f:id:fumokmm:20191211184828p:plain

バージョンは1.9.4を選択

f:id:fumokmm:20191211184833p:plain

そういえばElixirはErlang VM上で動くんだった

f:id:fumokmm:20191211184839p:plain

f:id:fumokmm:20191211184844p:plain

f:id:fumokmm:20191211184850p:plain

f:id:fumokmm:20191211184855p:plain

f:id:fumokmm:20191211184902p:plain

f:id:fumokmm:20191211184907p:plain

f:id:fumokmm:20191211184913p:plain

f:id:fumokmm:20191211184919p:plain

f:id:fumokmm:20191211184925p:plain

f:id:fumokmm:20191211184930p:plain

f:id:fumokmm:20191211184935p:plain

f:id:fumokmm:20191211184940p:plain

f:id:fumokmm:20191211184945p:plain

f:id:fumokmm:20191211184949p:plain

f:id:fumokmm:20191211184954p:plain

インストール完了!

f:id:fumokmm:20191211184958p:plain

スタートメニューから起動してみよう

f:id:fumokmm:20191211185003p:plain

Elixirの方を起動

f:id:fumokmm:20191211185008p:plain

こちらは Erlang

f:id:fumokmm:20191211185014p:plain

おしまい。

参考

Elixir

Elixir for Windows - Qiita

2行でWindowsにElixirをインストールするたった一つの冴えているようなやり方 - Qiita

Logbackで開始時に出るLogback自身のログの出力をやめたい

f:id:fumokmm:20191211191500p:plain

Logback自身のログが最初に大量に出る

logbackを導入したときに、プログラム開始時にlogback自身のログが大量に出ることがあります。こんな感じで。 f:id:fumokmm:20191210214110p:plain

調べてみると、NopStatusListener というのを指定するだけで、消せるみたい。

logback.xml

<!-- Stop output INFO at start -->
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />

消えました

f:id:fumokmm:20191210214128p:plain

参考

How to stop logback status INFO at the start of every log? – Mkyong.com

How to prevent logback from outputting its own status at the start of every log? - Stack Overflow

Kotlinで二つのリストの要素をペアにしたリストやマップにまとめる

f:id:fumokmm:20191207000933p:plain

zipメソッド

Kotlinでzipはどうやるのかな?と思って調べた内容です。いろいろありそうだけど、とりあえずシンプルなものをメモしておく。 Kotlinにはそのものズバリの zip というメソッドが List や Array に用意されている。

list.zip

val list1 = listOf("A", "B", "C")
val list2 = listOf(100, 200, 300)
println(list1.zip(list2))

Output

[(A, 100), (B, 200), (C, 300)]

array.zip

val array1 = arrayOf("a", "b", "c")
val array2 = arrayOf(400, 500, 600)
println(array1.zip(array2))

Output

[(a, 400), (b, 500), (c, 600)]

出力結果の (A, 100) などの部分は、Pair<out A, out B> 型となっているようです(ところでoutってなんだ?勉強不足)。

さて、これでペアのリストが得られた。例えば以下のようにすれば、1番目の最初の要素 "a" が取得できる。

array1.zip(array2)[0].first // => "a"

associateメソッド

さて、次はマップにまとめたい。それには Collection#associate を使うといいらしい。ペアのリスト List<Pair<A, B>> をアソシエイトすると、マップ Map<A, B> が出来上がるようだ。

associate map

val list1 = listOf("A", "B", "C")
val list2 = listOf(100, 200, 300)
println(list1.zip(list2).associate{ it })

Output

{A=100, B=200, C=300}
200

いい感じにマップが得られた。使い心地はこんな感じ。

list1.zip(list2).associate{ it }["B"] // => 200

参考

zip - Kotlin Programming Language

Pair - Kotlin Programming Language

【Kotlin】複数の値を返したい! - Qiita

associate - Kotlin Programming Language

Kotlin の Collection まとめ ~List編~ - Qiita

Kotlinでクラスパス上にあるプロパティファイルを読み込む

f:id:fumokmm:20191207000933p:plain

クラスパス上にあるプロパティファイルを読み込むには・・・?

Javaだとクラスパス上にあるリソースを読み込むにはJavaクラスクラス(Class<?>のクラス)の利用するがKotlinだとどうするのかな?と思って調べたもの。 Javaクラスクラスを参照するには、this.javaClassとすればいいらしい。クラスローダーも.classLoaderでいいみたい。 以下は簡単なクラスパスの通ったディレクトリに置かれたプロパティファイルを読み取るサンプル。

Main.kt

import java.io.File
import java.io.InputStreamReader
import java.net.URL
import java.util.*

class PropertiesReadSample1 {
    fun readProperty() {
        val prop = Properties()
        val resource: URL? = this.javaClass.classLoader.getResource("sample.properties")
        InputStreamReader(resource?.openStream(), "UTF-8").use { inStream ->
            prop.load(inStream)
            println("ooo's value is ${prop.getProperty("aaa")}")
            println("bbb's value is ${prop.getProperty("bbb")}")
            println("ううう's value is ${prop.getProperty("ううう")}")
        }
    }
}

fun main(args: Array<String>) {
    PropertiesReadSample1().readProperty()
}

sample.properties [UTF-8] (クラスパスの通ったディレクトリに置くこと)

aaa=100
bbb=200
ううう=300

Output

ooo's value is 100
bbb's value is 200
ううう's value is 300

ちょっと脇道に逸れるけど、Propertiesファイルってnative2asciiしなくても大丈夫になってたのね。

参考

Kotlinでクラスオブジェクトを参照する(Javaのクラス名.classの代わり) - Qiita

[Java] getResourceAsStreamの使い方

Javaリソース・プロパティーメモ(Hishidama's Java resource/property Memo)

Java 9 でようやくResourceBundle のデフォルト文字コードが UTF-8に - yanok.net