- 投稿日:2020-01-26T23:05:48+09:00
javaでAtCoder Beginner Contest 153を解く
AtCoder Beginner Contest 153お疲れ様でした!
公式ページ今回の自分の書いたコードはこちら
結果はA-DまでAC、FがTLEでした。以下簡単に解説します。
問題A
HPがHのモンスターを攻撃力Aで攻撃して、何回で倒せるかを求める問題。
H/Aがちょうど割り切れるときの処理に注意すれば大丈夫なはずです。問題B
数字(必殺技の攻撃力)を足し合わせて、相手のHPに届くかどうかを求める問題。
シンプルな足し算でいけるはずです。問題C
モンスターがN体いて、必殺技がK回使えます。
この必殺技でモンスターを瞬殺できるので、この必殺技を誰に使うかが求められれば、あとは残った敵の体力を足し合わせれば大丈夫です。当然、体力が高い順にK体必殺技を使いたいので、それをコードで頑張って表現しましょう。
問題D
1度攻撃を行うと、モンスターが体力H/2になって分裂し、体力が1の場合には倒せる。
これは敵の数と敵の体力をもっておくと比較的シンプルにできました。1回の操作で
敵の数分だけ、攻撃を行った回数を加算し、
敵の体力を半分にし、
敵の数を2倍にするこの操作を体力が0になるまで繰り返せばOKです。
問題E
なんだかアルゴリズムの定番問題っぽいなぁと思いつつ分からず。
問題F
2ケースTLEでした・・・
自分の考え方は
①座標を小さい順にソートする
②敵の体力を何回の攻撃で倒せるかに換算する
を下処理として行い、①座標を小さい順にひとつ取得する
②その点の敵があと何回で倒せるかを取得
③そこから、爆弾の範囲ぶんだけの点を取得
④その範囲の敵について、②で取得したぶん攻撃する。実装きちんとできればACなると思うのですが、、基本的な考え方は間違っていない気がします。
レーティングは956→944。
D問題までは17分とサクサクできて、成長も感じれたのですが
E問題以降解けるようにならないとここからはレートなかなか伸びなそうです。。今回のE問題もF問題もきちんと復習します!!
- 投稿日:2020-01-26T18:03:38+09:00
Java11でJakarta EE 8でダークウェブのSNSを作りたい
こんにちは。
今は私は暗号通貨をやり取りするダークウェブ系のSNS作りに挑戦しています。
https://github.com/nandaka-furari/DarkwebSNS
仕様等はREADMEに書いているので具体的にはここを参照してもらうとして、概要の設計としてはJava 11とJakarta EE 8を使います。
でもさっぱり開発の仕方が分からないのでJakarta EE のアプリを作る方法のサンプルとしてこの記事を発展させていきたいので編集リクエストをどんどん送ってください。Eclipse
今ではJakarta EEはEclipse Foundation(EF)傘下になっているのでEclipseで開発する前提の記事にしたいです。Payara Toolsの使い方などがあればいいかな。
終わりに
GitHubの方にもイシューやREADMEへのコミットやらガンガン送ってください。(基本READMEを発展させていけば何とかなりそうな気がする)
そして既存のJava EEやJakarta EEのQiita記事をここに集約できればと思います。
- 投稿日:2020-01-26T17:33:46+09:00
各言語で、継承の挙動はかなり違うという話
はじめに
この記事は、私が色んな言語でひたすら似たようにクラス継承を書いてみて、実際にどんな値が出力されるのかを調査した結果をまとめたものです。時には既知の言語でも「こんな文法あったんだ」と思いながら、時にはHello Worldから頑張りました。
まとめるのが大変だった割に誰得?という内容ですが、同じことが気になった人のために置いておきます。
いやでも新しい発見があるかもしれないのでとりあえず読んでみてください。
意外と面白い結果になったかもしれません。調べた言語
静的型付け
- Java (Corretto 1.8.0_232)
- C# (3.4.0)
- C++ (11.0.0)
- Scala (2.13.1)
- Kotlin (1.3.61)
- Swift (5.1.3)
動的型付け
- Python (3.7.1)
- Ruby (2.6.5)
- PHP (7.1.32)
- JavaScript (node v12.14.1)
オプショナルな静的型付け
- TypeScript (3.7.2)
- Dart (2.7.0)
調査で使うコード
ある親クラスを子クラスが継承します。
その親クラスと子クラスには、同じ名前のインスタンス変数があります。(クラス変数ではありません)
親クラスにはメソッドがあり、そのメソッドを使うとインスタンス変数をコンソールに出力できます。実行時には、子クラスのインスタンスで、継承した親のメソッドを呼びます。
さぁ親と子どっちのインスタンス変数が出力されるでしょうか……というストーリーです。多分読める人が多いであろうJS(ES6以降)のコードで書くと、こういうコードです。
class SuperClass { constructor() { // ※JSではインスタンス変数は実行時に定義されるので、コンストラクタに書く this.instanceVariable = "SuperClass" // 同じ名前で違う値 } superClassMethod() { console.log(this.instanceVariable) } } class SubClass extends SuperClass { constructor() { super() this.instanceVariable = "SubClass" // 同じ名前で違う値 } } const sub = new SubClass() // 子クラスをインタンス化 sub.superClassMethod() // 継承した親クラスのメソッドを呼ぶ自分が普段使っている言語でどういう値が出力されるかぜひ想像してみてください。
(良し悪しはともかくとして)たまにある書き方なので、自分の得意な言語のものは知っているかもしれません。
でも他の言語でどう動くのかを知っていたら、いつか別の会社や別の案件に入った時、もしくは興味本位で他言語に入門した時に役に立つかもしれません。今回は一応、インスタンス変数のみならず、メソッド(クラスメソッドではないインスタンスのメソッド)で
return "SuperClass"をした時にどうなるのかも見たりしています。
この場合は、親クラスと子クラスに同じ名前のメソッドがあり、親クラスのメソッドでそれを呼ぶ……というシナリオです。どんなコードを書いて調べたかは、
コードを見る(hoge言語)
class Hoge {}こんな風に詳細折りたたみ要素が置いてあるので、クリックして開いてもらえると中身のコードを読むことができます。
何をしているか見やすくするために原則としてコピペを採用したかなりWETなコードですが、それはわざとなのでマサカリを投げないでください。今回のポイント
ご存知の通り、プログラミング言語によって存在する文法は異なりますし、評価の仕方も違います。
今回の結果が変わるポイントは、下記であると思います。
- アクセス修飾子が存在するか。また、どんな種類のものがあるか
- 親クラスと子クラスで同名のインスタンス変数をそもそも定義可能か
- インスタンス変数のオーバーライド、メソッドのオーバーライドがそれぞれ存在するか。
- 継承そのものを、各言語がどう処理しているか
結果発表
Java
エンタープライズシステムの覇者、Java。
Javaにはアクセス修飾子として、privateやprotectedがあります。
privateは、現在のクラスからしか見ることはできません。protectedは、現在のクラスと子クラスからアクセスできます。Javaではインスタンス変数のオーバーライドは存在しません。
なので、メソッドでオーバーライドをした時にどうなるのかも見てみます。
条件 結果 インスタンス変数がprivate "SuperClass" インスタンス変数がprotected "SuperClass" インスタンス変数の代わりにprivateなメソッド "SuperClass" インスタンス変数の代わりにprotectedなメソッド(override) "SubClass" オーバーライドは文字通り「上書き」してしまいます。
今回は関係ありませんでしたが、Javaは、子クラス側のメソッドで親クラスのインスタンス変数に
super.instanceVariableのようにしてアクセスすることができます。オーバーライドしないゆえにできる芸当ですね。
コードを見る(Java)
public class JavaSample { public static void main(String[] args) { System.out.println("---- SubClass ----"); SubClass sub = new SubClass(); sub.superClassMethod(); System.out.println("---- SubClassProtected ----"); SubClassProtected subp = new SubClassProtected(); subp.superClassMethod(); System.out.println("---- SubClassGetter ----"); SubClassGetter subg = new SubClassGetter(); subg.superClassMethod(); System.out.println("---- SubClassGetterProtected ----"); SubClassGetterProtected subgp = new SubClassGetterProtected(); subgp.superClassMethod(); } } class SuperClass { // privateのインスタンス変数はサブクラスから参照できない private String instanceVariable = "SuperClass"; public void superClassMethod() { System.out.println(instanceVariable); } } class SubClass extends SuperClass { private String instanceVariable = "SubClass"; } // ------------------------------------------- class SuperClassProtected { protected String instanceVariable = "SuperClass"; public void superClassMethod() { System.out.println(instanceVariable); } } class SubClassProtected extends SuperClassProtected { protected String instanceVariable = "SubClass"; // public void subClassMethod() { // System.out.println(instanceVariable); と書くと、 // System.out.println(this.instanceVariable); と同じ。"SubClass"が出る。 // superをつけると、"SuperClass"と表示させることもできる // System.out.println(super.instanceVariable); // } } // ------------------------------------------- class SuperClassGetter { private String instanceVariable() { return "SuperClass"; } public void superClassMethod() { System.out.println(instanceVariable()); } } class SubClassGetter extends SuperClassGetter { private String instanceVariable() { return "SubClass"; } } // ------------------------------------------- class SuperClassGetterProtected { protected String instanceVariable() { return "SuperClass"; } public void superClassMethod() { System.out.println(instanceVariable()); } } class SubClassGetterProtected extends SuperClassGetterProtected { protected String instanceVariable() { return "SubClass"; } }C#
Javaの次はやっぱりC#。歴史的経緯からかなりJavaに近い文法を持ちます。その結果もまたJavaや、後述するC++と似ていますが、Javaには無いものもあります。
ちなみにC#にはプロパティがあるので、メソッドの代わりにプロパティで書きました。C#には
virtualとoverrideがあります。virtualは、「このメソッドはオーバーライドされる可能性があるぞ」と教える修飾子で、overrideは、ここでメソッドはオーバーライドしているぞと教える修飾子です。そこまではいいのですが、C#には更に、
newという変わった修飾子があります。このnewは、インスタンス生成のときのnew Human()のnewとは別モノです。overrideの代わりにnewをつけることで、子クラスからの呼び出しであっても、親クラスのメソッドを親クラスの文脈のままで評価させることができます。なぜかというと、親クラスのメソッドをオーバーライド(上書き)しているわけではなく、ただ隠しているだけだからです。ややこしいですね。
条件 結果 インスタンス変数がprivate "SuperClass" インスタンス変数がprotected "SuperClass" プロパティがprivate "SuperClass" プロパティがprotected(override) "SubClass" プロパティがprotected(new) "SuperClass"
コードを見る(C#)
using System; public class CSharpSample { public static void Main(string[] args) { Console.WriteLine("---- SubClass ----"); var sub = new SubClass(); sub.SuperClassMethod(); Console.WriteLine("---- SubClassProtected ----"); var subp = new SubClassProtected(); subp.SuperClassMethod(); Console.WriteLine("---- SubClassGetter ----"); var subg = new SubClassGetter(); subg.SuperClassMethod(); Console.WriteLine("---- SubClassGetterProtectedOverride ----"); var subgpo = new SubClassGetterProtectedOverride(); subgpo.SuperClassMethod(); Console.WriteLine("---- SubClassGetterProtectedNew ----"); var subgpn = new SubClassGetterProtectedNew(); subgpn.SuperClassMethod(); } } class SuperClass { private string instanceVariable = "SuperClass"; public void SuperClassMethod() { Console.WriteLine(instanceVariable); } } class SubClass : SuperClass { // warning CS0414: The field 'SubClass.instanceVariable' is assigned but its value is never used private string instanceVariable = "SubClass"; } // ---------------------------- class SuperClassProtected { protected string instanceVariable = "SuperClass"; public void SuperClassMethod() { Console.WriteLine(instanceVariable); } } class SubClassProtected : SuperClassProtected { // newはオーバーライドではなく、継承元のインスタンス変数隠しているよと明示している new protected string instanceVariable = "SubClass"; } // ---------------------------- class SuperClassGetter { private string instanceVariable { get { return "SuperClass"; } } public void SuperClassMethod() { Console.WriteLine(instanceVariable); } } class SubClassGetter : SuperClassGetter { private string instanceVariable { get { return "SubClass"; } } } // ---------------------------- class SuperClassGetterProtected { protected virtual string instanceVariable { get { return "SuperClass"; } } public void SuperClassMethod() { Console.WriteLine(instanceVariable); } } class SubClassGetterProtectedOverride : SuperClassGetterProtected { protected override string instanceVariable { get { return "SubClass"; } } } class SubClassGetterProtectedNew : SuperClassGetterProtected { protected new string instanceVariable { get { return "SubClass"; } } }C++
C++は組み込みの現場などで使われることが多いらしいですが私は何も知りません。
C++ナニモワカラナイ……。Javaとともに、C#の元となった言語なだけあって、C#に挙動がとても似ています。
インスタンス変数の代わりにメソッドを使った場合で、かつoverrideしないというのは、C#でいうところのnewと同じ挙動をします。
条件 結果 インスタンス変数がprivate "SuperClass" インスタンス変数がprotected "SuperClass" インスタンス変数の代わりにprivateなメソッド "SuperClass" インスタンス変数の代わりにprotectedなメソッド(override) "SubClass" インスタンス変数の代わりにprotectedなメソッド(overrideしない) "SuperClass"
コードを見る(C++)
#include <iostream> class SuperClass { // デフォルトだとprivate(クラス外からアクセス不可になる) std::string instanceVariable = "SuperClass"; public: void superClassMethod() { std::cout << instanceVariable << std::endl; } }; class SubClass : public SuperClass { std::string instanceVariable = "SubClass"; }; // ------------------------------- class SuperClassProtected { protected: std::string instanceVariable = "SuperClass"; public: void superClassMethod() { std::cout << instanceVariable << std::endl; } }; class SubClassProtected : public SuperClassProtected { protected: std::string instanceVariable = "SubClass"; }; // ------------------------------- class SuperClassGetter { std::string instanceVariable() { return "SuperClass"; } public: void superClassMethod() { std::cout << instanceVariable() << std::endl; } }; class SubClassGetter : public SuperClassGetter { std::string instanceVariable() { return "SubClass"; } }; // ------------------------------- class SuperClassProtectedGetter { protected: std::string instanceVariable() { return "SuperClass"; } public: void superClassMethod() { std::cout << instanceVariable() << std::endl; } }; class SubClassProtectedGetter : public SuperClassProtectedGetter { protected: std::string instanceVariable() { return "SubClass"; } }; // ------------------------------- class SuperClassProtectedGetterOverride { protected: virtual std::string instanceVariable() { return "SuperClass"; } public: void superClassMethod() { std::cout << instanceVariable() << std::endl; } }; class SubClassProtectedGetterOverride : public SuperClassProtectedGetterOverride { protected: std::string instanceVariable() override { return "SubClass"; } }; int main() { std::cout << "---- SubClass ----" << std::endl; SubClass sub; sub.superClassMethod(); std::cout << "---- SubClassProtected ----" << std::endl; SubClassProtected subp; subp.superClassMethod(); std::cout << "---- SubClassGetter ----" << std::endl; SubClassGetter subg; subg.superClassMethod(); std::cout << "---- SubClassProtectedGetter ----" << std::endl; SubClassProtectedGetter subpg; subpg.superClassMethod(); std::cout << "---- SubClassProtectedGetterOverride ----" << std::endl; SubClassProtectedGetterOverride subpgo; subpgo.superClassMethod(); return 0; }Scala
関数型の風を取り込んだAltJavaです。
JavaやC#と大きく違うところは、インスタンス変数のオーバーライドができることです。新機能来ました!
条件 結果 インスタンス変数がprivate "SuperClass" インスタンス変数がprotected(override) "SubClass"
コードを見る(Scala)
object ScalaSample { def main(args: Array[String]): Unit = { println("---- SubClass ----") val sub = new SubClass sub.superClassMethod() println("---- SubClassProtected ----") val subp = new SubClassProtected subp.superClassMethod() } } class SuperClass { private val instanceVariable = "SuperClass"; def superClassMethod(): Unit = { println(instanceVariable); } } class SubClass extends SuperClass { private val instanceVariable = "SubClass"; } // ---------------------------- class SuperClassProtected { protected val instanceVariable = "SuperClass"; def superClassMethod(): Unit = { println(instanceVariable); } } class SubClassProtected extends SuperClassProtected { override protected val instanceVariable = "SubClass"; }Kotlin
Scalaに大きな影響を受けたAltJavaです。Androidアプリの開発で多く用いられています。
オーバーライドする予定のインスタンス変数にはopenをつけなくてはならないこと以外、Scalaと同じです。
つまりopenはC++やC#のvirtualみたいなものですね。
条件 結果 インスタンス変数がprivate "SuperClass" インスタンス変数がprotected(override) "SubClass"
コードを見る(Kotlin)
fun main(args: Array<String>) { println("---- SubClass ----"); val sub = SubClass(); sub.superClassMethod(); println("---- SubClassOverride ----"); val subo = SubClassOverride(); subo.superClassMethod(); } open class SuperClass { private val instanceVariable = "SuperClass"; fun superClassMethod() { println(instanceVariable); } } class SubClass : SuperClass() { private val instanceVariable = "SubClass"; } // ----------------------------------- open class SuperClassOverride { open val instanceVariable = "SuperClass"; fun superClassMethod() { println(instanceVariable); } } class SubClassOverride : SuperClassOverride() { override val instanceVariable = "SubClass"; }Swift
アプリと言ったらAndroidだけではありません。iOSを忘れて貰っては困ります。
Swiftのprivateはバージョンによって挙動が変わったりするようですが、今回はSwift 5で検証したので、Javaと同じく、クラス内のみ有効で、継承されません。Swiftの
letは再代入を禁止した変数宣言です。JSでいうとconstです。
そしてSwiftのvarは再代入可能な普通の変数宣言です。JSでいうletです。ややこしや。Swiftでは、インスタンス変数(Swiftではプロパティという)を、継承元と同じものを定義することはできません。
代わりにComputed Property(C#でいうプロパティのようなもの)を使うと、オーバーライドすることができます。
privateのようなアクセス修飾子をつけないと、internalというスコープになります。internalはJavaでいうpublicみたいなものです(雑)。
条件 結果 インスタンス変数がprivate "SuperClass" インスタンス変数がinternal 定義不可 Computed Propertyがprivate "SuperClass" Computed Propertyがinternal(override) "SubClass"
コードを見る(Swift)
class SuperClass { private let instanceVariable = "SuperClass"; func SuperClassMethod() { print(instanceVariable); } } class SubClass: SuperClass { private let instanceVariable = "SubClass"; } // -------------------------------- class SuperClassInternal { let instanceVariable = "Error"; func SuperClassMethod() { print(instanceVariable); } } class SubClassInternal: SuperClassInternal { // error: cannot override with a stored property 'instanceVariable' // let instanceVariable = "SubClass"; } // -------------------------------- // Computed Propertyにしてgetterを生やす。こうしたら関数扱いなのでoverrideができるようになる。 class SuperClassGetter { // letだと、error: 'let' declarations cannot be computed properties private var instanceVariable: String { get { return "SuperClass" } } func SuperClassMethod() { print(instanceVariable); } } class SubClassGetter: SuperClassGetter { private var instanceVariable: String { get { return "SubClass" } }; } // -------------------------------- // Computed Propertyにしてgetterを生やす。こうしたら関数扱いなのでoverrideができるようになる。 class SuperClassInternalGetter { // letだと、error: 'let' declarations cannot be computed properties var instanceVariable: String { get { return "SuperClass" } } func SuperClassMethod() { print(instanceVariable); } } class SubClassInternalGetter: SuperClassInternalGetter { override var instanceVariable: String { get { return "SubClass" } }; } print("---- SubClass ----"); let sub = SubClass(); sub.SuperClassMethod(); print("---- SubClassInternal ----"); let subi = SubClassInternal(); subi.SuperClassMethod(); print("---- SubClassGetter ----"); let subg = SubClassGetter(); subg.SuperClassMethod(); print("---- SubClassInternalGetter ----"); let subig = SubClassInternalGetter(); subig.SuperClassMethod();Python
ここからは動的型付け言語!
Qiitaのタグ投稿ランキングで1位を取り続けるなど、その人気を盤石なものにしたPythonです。Pythonのクラスで特徴的なのは、メソッドの第一引数にインスタンス自身がやってくるので宣言時には第1引数に
selfと書くところです。別にselfじゃなくても良いのですが、みんなselfと書きます。あとは動的型付け言語らしく、インスタンス変数を動的に生み出すので、クラス宣言直下ではなくコンストラクタの中でインスタンス変数を定義します。ここはRubyもJavaScriptも同じですね。
Pythonにはメンバのアクセス制限がありません。修飾子
privateはありません。
関数名の先頭にアンダースコアを1つつけて、アクセスしないで欲しいことを示す文化です。しかしPythonでは、子クラスと名前が衝突した場合に備えた機能があります。アンダースコアを2つつけると、内部的なメンバ名が変わり(ネームマングリング)、元の変数名に簡単にアクセスできなくすることができます。この機能を使うことで、子クラスで同名のメンバがあった場合でも、実行時に元の親クラスの文脈で結果を評価することができるようになります。
pep8-ja - 命名規約 - メソッド名とインスタンス変数
結果を見てみましょう。
条件 結果 インスタンス変数 "SubClass" インスタンス変数の代わりにメソッド "SubClass" インスタンス変数(アンスコ2つ付き) "SuperClass" インスタンス変数の代わりにメソッド(アンスコ2つ付き) "SuperClass"
コードを見る(Python)
class SuperClass: def __init__(self): self.instance_variable = "SuperClass" def super_class_method(self): print(self.instance_variable) class SubClass(SuperClass): def __init__(self): super().__init__() self.instance_variable = "SubClass" # ------------------------------ class SuperClassNameMangling: def __init__(self): self.__instance_variable = "SuperClass" def super_class_method(self): print(self.__instance_variable) class SubClassNameMangling(SuperClassNameMangling): def __init__(self): super().__init__() self.__instance_variable = "SubClass" # ------------------------------ class SuperClassGetter: def instance_variable(self): return "SuperClass" def super_class_method(self): print(self.instance_variable()) class SubClassGetter(SuperClassGetter): def instance_variable(self): return "SubClass" # ------------------------------ class SuperClassNameManglingGetter: def __instance_variable(self): return "SuperClass" def super_class_method(self): print(self.__instance_variable()) class SubClassNameManglingGetter(SuperClassNameManglingGetter): def __instance_variable(self): return "SubClass" print('---- SubClass ----') sub = SubClass() sub.super_class_method() print('---- SubClassNameMangling ----') subp = SubClassNameMangling() subp.super_class_method() print('---- SubClassGetter ----') subg = SubClassGetter() subg.super_class_method() print('---- SubClassNameManglingGetter ----') subpg = SubClassNameManglingGetter() subpg.super_class_method()Ruby
「オブジェクト指向の動的型付け言語といったら?」
という連想クイズをされたプログラマは、真っ先にこの言語を思い浮かべる方も多いのではないでしょうか。Rubyにはメソッドに対して使える
privateがありますが、Javaのような言語のprivateとは挙動が違います。詳しくはレシーバとかを説明しなきゃいけなくなるので書きませんが、とりあえず言えることはprivateがあっても継承先にはそのメソッドが見えるということです。なのでJavaでいうとprotectedの方が近いかもしれません。
[Ruby] privateメソッドの本質とそれを理解するメリットちなみにRubyは変数とメソッドの名前空間が別れているので、メソッドをカッコなしで書いても呼び出せます。
それからメソッドはreturnを書かなくても、最後に評価した式の結果を返します。
@変数名がインスタンス変数です。Rubyでは変数名の1文字目で変数の種別(スコープ)がわかります。
条件 結果 インスタンス変数 "SubClass" インスタンス変数の代わりにメソッド "SubClass" インスタンス変数の代わりにprivateなメソッド "SubClass"
コードを見る(Ruby)
class SuperClass def initialize() @instance_variable = "SuperClass" end def super_class_method p @instance_variable end end class SubClass < SuperClass def initialize() super() @instance_variable = "SubClass" end end # -------------------------------- class SuperClassGetter def instance_variable() "SuperClass" end def super_class_method p instance_variable end end class SubClassGetter < SuperClassGetter def instance_variable() "SubClass" end end # -------------------------------- class SuperClassGetterPrivate def super_class_method p instance_variable end private def instance_variable() "SuperClass" end end class SubClassGetterPrivate < SuperClassGetterPrivate private def instance_variable() "SubClass" end end p '---- SubClass ----' subc = SubClass.new subc.super_class_method p '---- SubClassGetter ----' subg = SubClassGetter.new subg.super_class_method p '---- SubClassGetterPrivate ----' subgp = SubClassGetterPrivate.new subgp.super_class_methodPHP
PHPにはJavaのような
privateやprotectedやpublicがあります。
PythonやRubyやJavaScriptには基本的に無いのに! 羨ましい!
でもJavaとは違って、protectedなインスタンス変数はサブクラスのものを読みに行きます。
そこは他の動的型付け言語と足並みを揃えた動きですね。
条件 結果 インスタンス変数がprivate "SuperClass" インスタンス変数がprotected "SubClass" インスタンス変数の代わりにprivateなメソッド "SuperClass" インスタンス変数の代わりにprotectedなメソッド "SubClass"
コードを見る(PHP)
<?php function println($message) { echo $message.PHP_EOL; } // ---------------------------------------- class SuperClass { private $instanceVariable = "SuperClass"; public function superClassMethod() { println($this->instanceVariable); } } class SubClass extends SuperClass { private $instanceVariable = "SubClass"; } // ---------------------------------------- class SuperClassProtected { protected $instanceVariable = "SuperClass"; public function superClassMethod() { println($this->instanceVariable); } } class SubClassProtected extends SuperClassProtected { protected $instanceVariable = "SubClass"; } // ---------------------------------------- class SuperClassGetter { private function instanceVariable() { return "SuperClass"; } public function superClassMethod() { println($this->instanceVariable()); } } class SubClassGetter extends SuperClassGetter { private function instanceVariable() { return "SubClass"; } } // ---------------------------------------- class SuperClassGetterProtected { protected function instanceVariable() { return "SuperClass"; } public function superClassMethod() { println($this->instanceVariable()); } } class SubClassGetterProtected extends SuperClassGetterProtected { protected function instanceVariable() { return "SubClass"; } } // ---------------------------------------- println("---- SubClass ----"); $sub = new SubClass(); $sub->superClassMethod(); println("---- SubClassProtected ----"); $subp = new SubClassProtected(); $subp->superClassMethod(); println("---- SubClassGetter ----"); $subg = new SubClassGetter(); $subg->superClassMethod(); println("---- SubClassGetterProtected ----"); $subgp = new SubClassGetterProtected(); $subgp->superClassMethod();JavaScript
フロントエンドの覇者です。
プロトタイプベースオブジェクト指向言語という、プログラミング言語Selfから影響を受けた言語です。
ES6以降のJavaScriptではクラスベースの書き方も取り入れているため、extendsして継承もできます。
条件 結果 インスタンス変数 "SubClass" 古い書き方でインスタンス変数 "SubClass" インスタンス変数で、呼び出しメソッドがアロー関数 "SubClass" インスタンス変数の代わりにアロー関数 "SubClass"
コードを見る(JavaScript)
class SuperClass { constructor() { this.instanceVariable = "SuperClass" } superClassMethod() { console.log(this.instanceVariable) } } class SubClass extends SuperClass { constructor() { super() this.instanceVariable = "SubClass" } } // ------------------------ function LegacySuperClass() { this.instanceVariable = "SuperClass"; }; LegacySuperClass.prototype.superClassMethod = function() { console.log(this.instanceVariable) }; function LegacySubClass() { this.instanceVariable = "SubClass"; }; LegacySubClass.prototype = new LegacySuperClass(); // ------------------------ class SuperClassArrow { constructor() { this.instanceVariable = "SuperClass" } superClassMethod = () => { console.log(this.instanceVariable) } } class SubClassArrow extends SuperClassArrow { constructor() { super() this.instanceVariable = "SubClass" } } // ------------------------ class SuperClassGetterArrow { instanceVariable = () => { return "SuperClass" } superClassMethod = () => { console.log(this.instanceVariable()) } } class SubClassGetterArrow extends SuperClassGetterArrow { instanceVariable = () => { return "SubClass" } } // ------------------------ console.log('---- SubClass ----') const sub = new SubClass() sub.superClassMethod() console.log('---- LegacySubClass ----') var lsub = new LegacySubClass() lsub.superClassMethod() console.log('---- SubClassArrow ----') const suba = new SubClassArrow() suba.superClassMethod() console.log('---- SubClassGetterArrow ----') const subga = new SubClassGetterArrow() subga.superClassMethod()TypeScript
静的に型をつけられる、イケてるJavaScriptですね。
union型という、高度な型システムを持つHaskellに見られるような型に近いものがあったり、Conditional TypesやらMapped Typesやら表現力のある型があるのが特徴です。TypeScriptでは
privateな同名のメンバを親クラス子クラスで定義するとコンパイルエラーになります。protectedであれば問題ありません。Swiftとは真逆ですね。
条件 結果 インスタンス変数がprivate 定義不可 インスタンス変数がprotected "SubClass" インスタンス変数の代わりにprivateなメソッド 定義不可 インスタンス変数がprotectedで、呼び出しメソッドがアロー関数 "SubClass" インスタンス変数の代わりにprotectedなアロー関数 "SubClass"
コードを見る(TypeScript)
class SuperClass { private readonly instanceVariable: string constructor() { this.instanceVariable = "Error" } public superClassMethod() { console.log(this.instanceVariable) } } class SubClass extends SuperClass { // instanceVariableで定義しようとすると、 // TS2415: Class 'SubClass' incorrectly extends base class 'SuperClass'. // private readonly instanceVariable: string // constructor() { // super() // this.instanceVariable = "SubClass" // } } // ------------------------ class SuperClassGetter { private instanceVariable() { return "Error" } public superClassMethod() { console.log(this.instanceVariable()) } } class SubClassGetter extends SuperClassGetter { // instanceVariableで定義しようとすると、 // TS2415: Class 'SubClassGetter' incorrectly extends base class 'SuperClassGetter'. // Types have separate declarations of a private property 'instanceVariable'. // private instanceVariable() { // return "SubClass" // } } // ------------------------ class SuperClassProtected { protected readonly instanceVariable: string constructor() { this.instanceVariable = "SuperClass" } public superClassMethod() { console.log(this.instanceVariable) } } class SubClassProtected extends SuperClassProtected { protected readonly instanceVariable: string constructor() { super() this.instanceVariable = "SubClass" } } // ------------------------ class SuperClassProtectedGetterArrow { protected instanceVariable = () => { return "SuperClass" } public superClassMethod = () => { console.log(this.instanceVariable()) } } class SubClassProtectedGetterArrow extends SuperClassProtectedGetterArrow { protected instanceVariable = () => { return "SubClass" } } // ------------------------ // アロー関数版 class SuperClassProtectedArrow { protected readonly instanceVariable: string constructor() { this.instanceVariable = "SuperClass" } public superClassMethod = () => { console.log(this.instanceVariable) } } class SubClassProtectedArrow extends SuperClassProtectedArrow { protected readonly instanceVariable: string constructor() { super() this.instanceVariable = "SubClass" } } console.log('---- SubClass ----') const sub = new SubClass() sub.superClassMethod() console.log('---- SubClassGetter ----') const subg = new SubClassGetter() subg.superClassMethod() console.log('---- SubClassProtected ----') const subp = new SubClassProtected() subp.superClassMethod() console.log('---- SubClassProtectedArrow ----') const subpa = new SubClassProtectedArrow() subpa.superClassMethod() console.log('---- SubClassProtectedGetterArrow ----') const subpga = new SubClassProtectedGetterArrow() subpga.superClassMethod()Dart
Flutterが流行りだしてから急に存在感が出てきた印象な言語です。
Dartではprivateやpublicを書くことはありません。メンバの名前にアンダースコアをつけることでprivateにすることはできますが、ライブラリ外から見えなくするというだけなので、Javaなどのprivateとは違います。
条件 結果 インスタンス変数(アンスコ付き) "SubClass" インスタンス変数 "SubClass" インスタンス変数の代わりにメソッド "SubClass"
コードを見る(Dart)
void main() { print("---- SubClassPrivate ----"); final subp = new SubClassPrivate(); subp.superClassMethod(); print("---- SubClass ----"); final sub = new SubClass(); sub.superClassMethod(); print("---- SubClassGetter ----"); final subg = new SubClassGetter(); subg.superClassMethod(); } class SuperClassPrivate { // アンダースコアをつけるとPrivateになるが、 // privateは同一ライブラリに対して可視のため、ここではサブクラスから普通に見えちゃう final String _instanceVariable = "SuperClass"; void superClassMethod() => print(_instanceVariable); } class SubClassPrivate extends SuperClassPrivate { final String _instanceVariable = "SubClass"; } // ------------------------------------ class SuperClass { final String instanceVariable = "SuperClass"; void superClassMethod() => print(instanceVariable); } class SubClass extends SuperClass { final String instanceVariable = "SubClass"; } // ------------------------------------ class SuperClassGetter { String instanceVariable() => "SuperClass"; void superClassMethod() => print(instanceVariable()); } class SubClassGetter extends SuperClassGetter { String instanceVariable() => "SubClass"; }まとめ
ある程度使い慣れた言語でも知らないことがあったりして、意外と楽しかったです。
挙げた例の中には今回初めて書いた言語もあるので、こんな書き方あるよ! とか、間違ってるよ! とかあったらコメントください。全体的にまとめると、動的型付け言語だとスーパークラスのメソッドを呼んだ時でもサブクラスの文脈でまずは評価させようとするような印象でした。一方の静的型付け言語では、「スーパークラスのメソッドなんだから基本はスーパークラスで評価する。ただしオーバーライドしたらその限りじゃない」という感じでした。
個人的に印象深かったのは、下記の5つでした。
- C#には
newというオーバーライドしない用の修飾子がある- ScalaとKotlinは静的型付け言語なのにインスタンス変数のオーバーライドができる
- Pythonのアンダースコア2つのメンバ名はただの名前じゃなく効果もあった
- PHPには動的型付け言語なのにJavaみたいな
privateがある- TypeScriptは重複する
privateな同名メンバをコンパイル時にエラーにして予期せぬ動作になることを防いでくれる更新履歴
- Pythonの命名規約の説明について誤りがあったため、修正を行いました。 @shiracamus さんありがとうございました。
- Pythonでは
privateという言葉は使わないと指摘があったため、修正を行いました。 @Luice さんありがとうございました。
- 投稿日:2020-01-26T15:43:04+09:00
UTF-8のBOMを削除するには?(BOMの説明もします)
業務でファイル操作に関連する処理を実装した際に、BOM付きのUTF-8で書かれたファイルから
BOMだけを削除する方法を色々と調べているうちに実装できたのでまとめてみます。
(対象となるプログラミング言語はJavaなので他の言語では書き方や仕様が異なる可能性があります)そもそもBOMとは?
BOMを削除する方法を説明する前に、BOMとは何なのか説明します。
BOMとはざっくりいってしまえばUnicode系の文字コードで書かれたファイルの先頭に追加される目印となるバイト文字列です。
UTF-8では0xEF 0xBB 0xBFの3バイトで表現されます。
BOM付きのファイルをメモ帳などでは視認できませんが、コンピュータ内部ではファイルの先頭にBOMと呼ばれるバイト文字列が追加されたものとして読み込みます。
では、目印とは何の目印なのかということですが、
- Unicode系の文字コードで記述されていることを示すためのもの
- UTF-16、UTF-32においてエンディアンと呼ばれるビットの並び順を指定するためのもの。並べる順序によってビッグエンディアン(上位バイトから順番に並べる)、リトルエンディアン(下位バイトから順番に並べる)の2種類がある
これら2つのことを実現するためにファイルの先頭にバイト文字列であるBOMを追加しています。
なぜUTF-8(BOM付き)が存在するのか?
UTF-16、UTF-32であればエンディアンの並び順を指定BOMあり/なしがあるのは分かるが、UTF-8のように1バイトで文字列を表現する文字コードではエンディアンを指定する必要もないはずです。では、なぜBOM付きの文字コードが定義されているのでしょうか?
調べていくと、MS社のExcelの仕様に原因があることがわかりました。
MS社のExcelがCSVを開くときにデフォルトでShift-JISで開こうとするため、BOMなしのUTF-8で書かれたファイルを読み込もうとすると文字化けしてしまうのです。これを防ぐためにBOMを付けてUnicode系の文字コードで読み込むように指定する必要があるのです。BOMを削除する方法
では、本題となっているBOMを削除するための方法を説明していきます。
JavaではそもそもUTF-8にBOMが付いている場合を想定していません。そのため、BOM付きのファイルを読み込む際にはBOMを他の文字と同様のものとして読み込んでしまい、BOMだけを削除することをしません。そのため、BOMを削除したい場合は別途そのような処理を記入する必要があります。Java// BOMをUnicodeコード表示したもの public static final String BOM = "\uFEFF"; /** * ファイルにBOMが含まれていた場合、 * BOMなしに変換する。 * * @param s ファイル文字列 * @return BOMなしのファイル文字列 * */ private static String removeUTF8BOM(String s) { if (s.startsWith(BOM)) { // ファイルの先頭より後ろの文字列を読み込む s = s.substring(1); } return s; }なお、もう一つの方法としてapacheが提供しているクラスライブラリを使う方法もあります。
詳しい仕様は以下を参照してください。
BOM付きのファイルを読み込むためのクラス参考記事
- 投稿日:2020-01-26T15:43:04+09:00
BOMを削除する方法
業務でファイル操作に関連する処理を実装した際に、BOM付きのUTF-8で書かれたファイルから
BOMだけを削除する方法を色々と調べているうちに実装できたのでまとめてみます。
(対象となるプログラミング言語はJavaなので他の言語では書き方や仕様が異なる可能性があります)そもそもBOMとは?
BOMを削除する方法を説明する前に、BOMとは何なのか説明します。
BOMとはざっくりいってしまえばUnicode系の文字コードで書かれたファイルの先頭に追加される目印となるバイト文字列です。
UTF-8では0xEF 0xBB 0xBFの3バイトで表現されます。
BOM付きのファイルをメモ帳などでは視認できませんが、コンピュータ内部ではファイルの先頭にBOMと呼ばれるバイト文字列が追加されたものとして読み込みます。
では、目印とは何の目印なのかということですが、
- Unicode系の文字コードで記述されていることを示すためのもの
- UTF-16、UTF-32においてエンディアンと呼ばれるビットの並び順を指定するためのもの。並べる順序によってビッグエンディアン(上位バイトから順番に並べる)、リトルエンディアン(下位バイトから順番に並べる)の2種類がある
これら2つのことを実現するためにファイルの先頭にバイト文字列であるBOMを追加しています。
なぜUTF-8(BOM付き)が存在するのか?
UTF-16、UTF-32であればエンディアンの並び順を指定BOMあり/なしがあるのは分かるが、UTF-8のように1バイトで文字列を表現する文字コードではエンディアンを指定する必要もないはずです。では、なぜBOM付きの文字コードが定義されているのでしょうか?
調べていくと、MS社のExcelの仕様に原因があることがわかりました。
MS社のExcelがCSVを開くときにデフォルトでShift-JISで開こうとするため、BOMなしのUTF-8で書かれたファイルを読み込もうとすると文字化けしてしまうのです。これを防ぐためにBOMを付けてUnicode系の文字コードで読み込むように指定する必要があるのです。BOMを削除する方法
では、本題となっているBOMを削除するための方法を説明していきます。
JavaではそもそもUTF-8にBOMが付いている場合を想定していません。そのため、BOM付きのファイルを読み込む際にはBOMを他の文字と同様のものとして読み込んでしまい、BOMだけを削除することをしません。そのため、BOMを削除したい場合は別途そのような処理を記入する必要があります。Java// BOMをUnicodeコード表示したもの public static final String BOM = "\uFEFF"; /** * ファイルにBOMが含まれていた場合、 * BOMなしに変換する。 * * @param s ファイル文字列 * @return BOMなしのファイル文字列 * */ private static String removeUTF8BOM(String s) { if (s.startsWith(BOM)) { // ファイルの先頭より後ろの文字列を読み込む s = s.substring(1); } return s; }なお、もう一つの方法としてapacheが提供しているクラスライブラリを使う方法もあります。
詳しい仕様は以下を参照してください。
BOM付きのファイルを読み込むためのクラス参考記事
- 投稿日:2020-01-26T15:43:04+09:00
BOMを削除する方法(UTF-8)
業務でファイル操作に関連する処理を実装したのですが、UTF-8(BOM付き)ファイルから
BOMを削除するための方法を学んだので今後のためにまとめてみます。そもそもBOMとは?
まず、そもそもBOMとは一体何者なのでしょうか?
BOMとはざっくりいってしまえば
Unicode系文字コードで作成されたファイルの先頭に付く目印です。
UTF-8では0xEF 0xBB 0xBFの3バイトで表現されます。
BOMは普通メモ帳などでは見ることはできませんが、実際にはファイルの中身の最初に
BOMが付いており、コンピュータ側で読み取る際にもそのように解釈して実行します。
そして、目印として主に2つの役割を持ちます。
- Unicode系の文字コードで記述されていることを示すためのもの
- UTF-16、UTF-32においてエンディアンと呼ばれるビットの並び順を指定するためのもの。 並べる順序によって、
・ ビッグエンディアン(上位バイトから順番に並べる)
・ リトルエンディアン(下位バイトから順番に並べる)
の2種類があるなぜUTF-8(BOM付き)が存在するのか?
UTF-16、UTF-32のように2バイト以上の文字コードで文字との対応付けを行う際には
エンディアンの並び順を指定するためにBOMが使われます。
しかし、UTF-8のように1バイトの文字コードで対応付けを行っている場合には
エンディアンを指定する必要なんてありません。
では、なぜUTF-8(BOM付き)が存在するのでしょうか?調べていくと、ExcelがCSVを開く際の仕様に原因があることがわかりました。
ExcelがCSVを開くときにはShift-JISで開こうとするため、BOMなしのUTF-8で
書かれたファイルを読み込もうとすると文字化けしてしまうのです。
これを防ぐためにBOMを付けてCSVを開くときにもUnicode系の文字コードで
読み込むように指定する必要があるのです。BOMを削除する方法
では、本題となっているBOMを削除するための方法を説明していきます。
JavaではそもそもUTF-8にBOMが付いている場合を想定していません。
そのため、BOM付きのファイルを読み込む際にはBOMを他の文字と
同様のものとして扱い、BOMを削除しません。
そのため、BOMを削除する場合は別途そのような処理を実装する必要があります。Java// BOMをUnicodeコード表示したもの public static final String BOM = "\uFEFF"; /** * ファイルにBOMが含まれていた場合、 * BOMなしに変換する。 * * @param s ファイル文字列 * @return BOMなしのファイル文字列 * */ private static String removeUTF8BOM(String s) { if (s.startsWith(BOM)) { // ファイルの先頭より後ろの文字列を読み込む s = s.substring(1); } return s; }なお、もう一つの方法としてapacheが提供しているクラスライブラリを使う方法もあります。
詳しい仕様は以下を参照してください。参考記事
- 投稿日:2020-01-26T15:41:09+09:00
Javaで文字列を整数・小数に変換(データのキャスト)するメソッドについて
- 投稿日:2020-01-26T14:35:41+09:00
変数に変数を代入する方法
文法
データ型 変数名 = (データ型) 代入される側の変数名
※右辺の()を忘れがちなので注意!
public class Main { public static void main(String[] args) { double rand = Math.random(); * 100; //変数に変数を代入 int number = (int)rand; System.out.println(number); } }おまけ
変数定義と同時にMath関数を代入することも可能
その場合は、()でくくる。
int game_num = (int)(Math.random() * 10 + 1); System.out.println("ゲームの本数は" + game_num + "個");
- 投稿日:2020-01-26T14:35:41+09:00
型の違う値を型変換して別の変数に代入する方法
文法
データ型 変数名 = (データ型) 代入される側の変数名
※型指定/型キャストをする場合、右辺のデータ型を括弧で括る必要があります。忘れがちなので注意(戒め)。
public class Main { public static void main(String[] args) { double rand = Math.random(); * 100; //変数に変数を代入 int number = (int)rand; System.out.println(number); } }おまけ
変数定義と同時にMath関数を代入することも可能
その場合は、()でくくる。
int game_num = (int)(Math.random() * 10 + 1); System.out.println("ゲームの本数は" + game_num + "個");
- 投稿日:2020-01-26T11:52:38+09:00
Javaと第一級関数 -関数型インタフェースをこえて-
概要
Java8で関数型プログラミングまわりの機能が強化された。
- 関数型インタフェース
- メソッド参照
- ラムダ式
- ストリームAPI
関数型インタフェースやメソッド参照が、どのような機能なのかについてまとめる
Goal
こんなソースコードが読めて使えるようになる。
public static void main(String[] args) { List<String> strings = Arrays.asList("bravo", "", "charlie", "alpha"); strings.stream() .filter(s -> !s.isEmpty()) .map(s -> s.substring(0, 1).toUpperCase() + s.substring(1)) .forEach(System.out::println); // Bravo // Charlie // Alpha }関数型インタフェース
関数型インタフェースってなんなのか、なんのためにあるのか。
それを理解するためには第一級関数という概念の理解が必要。第一級関数
第一級関数(だいいっきゅうかんすう、英: first-class function、ファーストクラスファンクション)[1]とは、関数を第一級オブジェクトとして扱うことのできるプログラミング言語の性質、またはそのような関数のことである。
-- 第一級関数 - Wikipedia第一級オブジェクト?
第一級オブジェクト
第一級オブジェクト(ファーストクラスオブジェクト、first-class object)は、あるプログラミング言語において、たとえば生成、代入、演算、(引数・戻り値としての)受け渡しといったその言語における基本的な操作を制限なしに使用できる対象のことである。
-- 第一級オブジェクト - Wikipediaなるほど
Javaは?
Javaの関数(メソッド)は変数に代入したり、戻り値・引数に使用することができない。
Javaは第一級関数の性質を満たしていない言語。第一級関数だと何が嬉しいの?
第一級関数は関数型言語には必要不可欠であり、高階関数のような形で日常的に用いられる。
-- 第一級関数 - Wikipedia外から関数によって振る舞いを操作することができる。
e.g. sortのルールList<String> strings = Arrays.asList("bravo", "charlie", "alpha"); Collections.sort(strings); System.out.println(strings); // -> [alpha, bravo, charlie] Collections.sort(strings, Comparator.reverseOrder()); System.out.println(strings); // -> [charlie, bravo, alpha]べんり。
ちょっと待て
今のコードJavaじゃないの?
Strategyパターン
第一級オブジェクトとして関数を利用できないがために考えられたデザインパターン。
Javaではクラスのメソッドオーバーライドによるポリモーフィズムを使ってStrategyパターンを実現することができる。
-- Strategy パターン - Wikipedia詳細は割愛しますが、こんな感じ。
public static <T> void sort(List<T> list, Comparator<? super T> c) { if (c.compare(a, b) < 0) { // aの方が小さい }else { // bの方が小さい } }引数で受け取ったComparatorインタフェースの実装クラスに従って、ソートのルールを決定している。
メソッド自体を引数経由で渡してはいないが、インタフェースを通してメソッドの処理を外側から渡すことができるというプラクティス。実際のsort処理はこんな感じのよう
jdk/TimSort.java at master · openjdk/jdkこのデザインパターンは、関数が第一級オブジェクトの言語では特に意識する必要がない。
このパターンは、関数が第一級オブジェクトである言語では暗黙のうちに使用されている。
-- Strategy パターン - Wikipedia実質
Javaはインタフェースを利用することで、実質、関数(メソッド)を第一級オブジェクトのように扱える。
関数型インタフェースってなんなのか
先程のComparatorのように、関数(メソッド)を第一級オブジェクトとして扱うために利用しているインタフェースのことを、java8からは、関数型インタフェース(functional interface)と呼ぶことにした。
関数(メソッド)を第一級オブジェクトとして扱うというのが目的なので、関数型インタフェースの抽象メソッドは1つのみである。ComparatorやRunnableのように過去から提供されていたインタフェースの一部に新しい名前が付いただけ。
機能は通常のインタフェースと同一である。
関数型インタフェースには、@FunctionalInterfaceというアノテーションが追加されるようになった。
e.g. java.lang.Runnable@FunctionalInterface public interface Runnable { /** * When an object implementing interface {@code Runnable} is used * to create a thread, starting the thread causes the object's * {@code run} method to be called in that separately executing * thread. * <p> * The general contract of the method {@code run} is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }jdk/FunctionalInterface.java at master · openjdk/jdk
@FunctionalInterface
関数型インタフェースのために追加されたアノテーション。
実行時は特に何も起きない(関数型インタフェースは機能的には通常のインタフェースなため特別な処理等は無い)。
コンパイル時には関数型インタフェースの性質を満たしているかを確認してくれる。つまり関数型インタフェースの機能を利用する際に絶対必要なわけではない。
ただし、通常のインタフェースではなく関数型インタフェースということが明示できるため、関数型インタフェースを自作した際はつけるべきだと思われる。標準的な関数型インタフェース
関数型インタフェースを利用して関数(メソッド)を扱う場合、扱うメソッドはJavaの型システムの影響を受ける。
具体的には、下記が異なるメソッドを扱う場合、それぞれ異なる関数型インタフェースを利用しなければならない。
- 返り値の型
- 引数の型
- 引数の数
java8では、返り値の有無や引数の型などを抽象化し利用可能にした標準的な関数型インタフェースが提供されている。
基本的にはこのインタフェースで充分であり、このインタフェースを利用することを考えるべきと言われている。
(ただし、Runnableなどの慣習的なものは除く)代表的な標準関数型インタフェース
インタフェース名 抽象メソッド名 例 Function<T,R> R apply(T t) Arrays::asList Predicate boolean test(T t) Collections::isEmpty Consumer<T> void accept(T t) System.out::println Supplier<T> T get() Instant::now UnaryOperator<T> T apply(T t) String::toLowerCase BinaryOperator<T> T apply(T t1, T t2) BigInteger::add java.util.function (Java Platform SE 8 )
実際に使ってみる
文字列を加工して出力する処理を組んでみる。
出力する処理を呼び出す際に、加工処理の関数を一緒に渡すことで、加工処理後の文字列を出力する。
すべて大文字に変換してから出力するプログラムを組んでみる。文字列表示部分
渡された関数を実行した後に出力する。
関数型インタフェースは変更前文字列(String)を1つ受け取り、変更後文字列(String)を返すような関数を想定し、UnaryOperator<String>を利用する。static void print(String word, UnaryOperator<String> operator) { String newWord = operator.apply(word); System.out.println(newWord); }渡す関数
大文字に変換する関数。
UnaryOperator<String>を実装する。import java.util.function.UnaryOperator; public class MyUpperOperator implements UnaryOperator<String> { @Override public String apply(String s) { return s.toUpperCase(); } }main
先程作成した大文字変換の関数と、文字列をprintメソッドに渡すと、全て大文字となって出力される。
public static void main(String[] args) { UnaryOperator<String> upperOperator = new MyUpperOperator(); print("hello world", upperOperator); // -> HELLO WORLD }まぁ
関数型インタフェースを使ってはいるが、ただのStrategyパターン。
メソッド参照
先程の例、実はもっと強力な書き方が可能。
メソッド参照(method reference)という機能を利用することで、関数型インタフェースを明示的に実装せずに、引数と返り値が一致しているメソッドを直接渡すことができる。
先程の例の場合、UnaryOperator<String>なので、引数がString1つからなり、返り値がStringとなるメソッドであれば直接メソッド参照として渡すことが可能。
StringクラスのtoUpperCase()メソッドを直接UnaryOperator<String>インスタンスに代入することができる。
(インスタンスメソッドのメソッド参照の場合は、レシーバオブジェクトが第一引数として解釈される。後述する文法を参照)
こうなると呼び出し側のソースコードは、第一級オブジェクトとして関数を扱っているように見える。public static void main(String[] args) { // UnaryOperator<String> upperOperator = new MyUpperOperator(); UnaryOperator<String> upperOperator = String::toUpperCase; print("hello world", upperOperator); // -> HELLO WORLD }しくみは難しい
JVMの
invokeDynamicという命令を利用しているらしい。
コンパイル時ではなく、実行時にクラスを動的に生成して解決しているらしい。文法
セミコロンを2つ連続する記法。
セミコロンの両側に記述する内容は、メソッドの種類によって大きく4つのパターンに分けられる。
対象 文法 例 クラスメソッド クラス名::クラスメソッド名 String::toStringインスタンスメソッド インスタンス名::インスタンスメソッド名 System.out::printlnインスタンスメソッド※ クラス名::インスタンスメソッド名 String::toUpperCaseコンストラクタ クラス名::new String::new※レシーバオブジェクトが第一引数として解決される
使ってみる
先程の例は非常に簡潔に記述できる。MyUpperOperatorクラスはもはや不要である。
public static void main(String[] args) { print("hello world", String::toUpperCase); // -> HELLO WORLD }また、java8で追加されたstream APIはその多くが関数型インタフェースを要求しているので、このような処理が組める。
public static void main(String[] args) { List<String> strings = Arrays.asList("bravo", "charlie", "alpha"); strings.stream() .map(String::toUpperCase)// Function: 大文字に変換 .forEach(System.out::println);// Consumer: 出力 // BRAVO // CHARLIE // ALPHA }非常に便利だが、
扱うためにはメソッドを予め宣言する必要がある。
用意されているメソッドを使う分にはいいが、独自処理をいちいちメソッドとして宣言しなければならない。
リテラルのようにもメソッドを扱いたい。ラムダ式
関数型インタフェースに代入可能な評価式の仕組み。
メソッドを宣言せずに、式としてメソッドを記述することができる。e.g. 文字列にピリオドつける関数
public static void main(String[] args) { // UnaryOperator<String> upperOperator = String::toUpperCase; UnaryOperator<String> periodOperator = (String s) -> { return s + "."; }; print("hello world", periodOperator); // -> hello world. }文法
これが基本形
(仮引数列) -> { 処理本体の文 }
e.g.
(String s) -> { return s + "."; }特定の条件下でのみ様々な記述の省略が可能。
調べればいろいろ出てくると思うので割愛。
e.g. 今回の場合
UnaryOperator<String> periodOperator = s -> s + ".";使ってみる
public static void main(String[] args) { print("hello world", s -> s + "."); // -> hello world. }public static void main(String[] args) { List<String> strings = Arrays.asList("bravo", "", "charlie", "alpha"); strings.stream() .filter(s -> !s.isEmpty()) // Predicate: 空文字を削除 .map(s -> s.substring(0, 1).toUpperCase() + s.substring(1)) // Function: 1文字目のみ大文字に変換 .forEach(System.out::println); // Consumer: 出力 // Bravo // Charlie // Alpha }後者の例は本記事の冒頭で挙げた処理である。
こんなソースコードが読めて使えるようになる。
まとめ
java8から関数型プログラミングの機能が強化された。
- 関数型インタフェース
- メソッド参照
- ラムダ式
参考
改訂2版 パーフェクトJava:書籍案内|技術評論社
Effective Java 第3版 - 丸善出版 理工・医学・人文社会科学の専門書出版社
- 投稿日:2020-01-26T07:34:06+09:00
Toast 文字大きく表示させたい Android Studio メモ
ボタン押すと3枚の画像が順に切り替わり
それぞれ違うToastテキストが出るアプリを作った。package com.example.rswitch;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;import android.widget.ImageView;
import android.widget.Toast;public class MainActivity extends AppCompatActivity {
//boolean ブーリアン trueかfalseが入る型 //isShowing 画面に表示されているか判定 //画像re1,re2 は画面に表示されているとコンピューターに判定させる boolean re1IsShowing = true; boolean re2IsShowing = true; public void fade (View view) { //Javaの変数re1, re2, re3をxmlの id とそれぞれ紐づけ // 紐付けしないとアニメーションが実行されない ImageView re1 = findViewById(R.id.re1); ImageView re2 = findViewById(R.id.re2); ImageView re3 = findViewById(R.id.re3); if(re1IsShowing) { //swichボタン押した後、画像re1は表示されていないと判定させる re1IsShowing = false; re1.animate().alpha(0).setDuration(1000); re2.animate().alpha(1).setDuration(1000); Toast.makeText(this, "かわいい?", Toast.LENGTH_LONG).show(); } else if(re2IsShowing) { //swichボタン押した後、画像re2は表示されていないと判定させる re2IsShowing = false; re2.animate().alpha(0).setDuration(1000); re3.animate().alpha(1).setDuration(1000); Toast.makeText(this, "遊んで~", Toast.LENGTH_LONG).show(); } else { re1IsShowing = true; re2IsShowing = true; re3.animate().alpha(0).setDuration(1000); re1.animate().alpha(1).setDuration(1000); Toast.makeText(this, "似合う?", Toast.LENGTH_LONG).show(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }}
しかし、テキストが小さいので大きくしたい。
ネットで出てきた記事を参考に
https://blog.fujiu.jp/2013/11/14-android-toast.htmltextやtoast変えてみて
package com.example.rswitchtoastarrange;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;public class MainActivity extends AppCompatActivity {
//boolean ブーリアン trueかfalseが入る型 //isShowing 画面に表示されているか判定 //画像re1,re2 は画面に表示されているとコンピューターに判定させる boolean re1IsShowing = true; boolean re2IsShowing = true; TextView text = new TextView(getApplicationContext()); public void fade (View view) { //Javaの変数re1, re2, re3をxmlの id とそれぞれ紐づけ // 紐付けしないとアニメーションが実行されない ImageView re1 = findViewById(R.id.re1); ImageView re2 = findViewById(R.id.re2); ImageView re3 = findViewById(R.id.re3); if(re1IsShowing) { //swichボタン押した後、画像re1は表示されていないと判定させる re1IsShowing = false; re1.animate().alpha(0).setDuration(1000); re2.animate().alpha(1).setDuration(1000); text.setText("かわいい?"); text.setTextSize(30); Toast toast = new Toast(getApplicationContext()); toast.setView(text); toast.setDuration(Toast.LENGTH_LONG); toast.show(); } else if(re2IsShowing) { //swichボタン押した後、画像re2は表示されていないと判定させる re2IsShowing = false; re2.animate().alpha(0).setDuration(1000); re3.animate().alpha(1).setDuration(1000); Toast.makeText(this, "遊んで~", Toast.LENGTH_LONG).show(); } else { re1IsShowing = true; re2IsShowing = true; re3.animate().alpha(0).setDuration(1000); re1.animate().alpha(1).setDuration(1000); Toast.makeText(this, "似合う?", Toast.LENGTH_LONG).show(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }}
としてrunすると、エラー起きないもエミュレーターでアプリ起動してすぐにアプリ落ちてしまう。
Logcatを見ると、
2020-01-24 20:10:35.166 1835-1835/? E/netmgr: Failed to open QEMU pipe 'qemud:network': Invalid argument
2020-01-24 20:10:35.167 1835-1835/? E/netmgr: WifiForwarder unable to open QEMU pipe: Invalid argument調べたけどよくわからない。
先ほどの参考記事をそのままコピペして
package com.example.toastbig;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView text = new TextView(getApplicationContext()); //Toastに表示する文字 text.setText("\赤い大きな文字/"); //フォントの種類 text.setTypeface(Typeface.SANS_SERIF); //フォントの大きさ text.setTextSize(30); //フォントの色 text.setTextColor(Color.RED); //文字の背景色(ARGB) text.setBackgroundColor(0x88dcdcdc); //Toastの表示 Toast toast = new Toast(getApplicationContext()); toast.setView(text); toast.setDuration(Toast.LENGTH_LONG); toast.show(); }}
とすると \赤い大きな文字/
とちゃんと表示される。
public class MainActivity extends AppCompatActivity
の中ではなく、protected void onCreate(Bundle savedInstanceState) {
の中にコードを置かないとダメなのかと思い、TextView以下を
protected void onCreate(Bundle savedInstanceState) {
のなかの
setContentView(R.layout.activity_main);のしたに移してみると、
public void fade (View view)
でview に
cannot find symbolと
エラー発生。package com.example.rswitchtoastarrange;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;public class MainActivity extends AppCompatActivity {
//boolean ブーリアン trueかfalseが入る型 //isShowing 画面に表示されているか判定 //画像re1,re2 は画面に表示されているとコンピューターに判定させる boolean re1IsShowing = true; boolean re2IsShowing = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView text = new TextView(getApplicationContext()); public void fade (View view) { //Javaの変数re1, re2, re3をxmlの id とそれぞれ紐づけ // 紐付けしないとアニメーションが実行されない ImageView re1 = findViewById(R.id.re1); ImageView re2 = findViewById(R.id.re2); ImageView re3 = findViewById(R.id.re3); if(re1IsShowing) { //swichボタン押した後、画像re1は表示されていないと判定させる re1IsShowing = false; re1.animate().alpha(0).setDuration(1000); re2.animate().alpha(1).setDuration(1000); text.setText("かわいい?"); text.setTextSize(30); Toast toast = new Toast(getApplicationContext()); toast.setView(text); toast.setDuration(Toast.LENGTH_LONG); toast.show(); } else if(re2IsShowing) { //swichボタン押した後、画像re2は表示されていないと判定させる re2IsShowing = false; re2.animate().alpha(0).setDuration(1000); re3.animate().alpha(1).setDuration(1000); Toast.makeText(this, "遊んで~", Toast.LENGTH_LONG).show(); } else { re1IsShowing = true; re2IsShowing = true; re3.animate().alpha(0).setDuration(1000); re1.animate().alpha(1).setDuration(1000); Toast.makeText(this, "似合う?", Toast.LENGTH_LONG).show(); } } }}
どうすればいいのかな。
https://akira-watson.com/android/toast-custom.html
[Android] Toast をカスタマイズするという記事は参考になりそうだが、複雑そうで理解できないので諦めようかな・・・。
- 投稿日:2020-01-26T00:43:51+09:00
VSCodeにThymeleaf用のスニペットを作ろう
はじめに
VSCodeでのユーザースニペットの記事は調べればあるが、Thymeleaf用のものがなく、VSCodeのプラグインでもいい感じのものがなかったため備忘録的に書いておこうと思う。
※検証環境はmacOS Mojave 10.14.16スニペットとは
直訳すると「切れ端」や「断片」となるが、要は呼び出したいものに名前を付けて簡単に呼び出せるようにしたものということ。
早速試してみる
「Shift+Command+p」を押すと、画面上部に検索画面が出てくるので
userなどと打つと「Preferences: Configure User Snippets」が出てくるからこれを選択。
次に、言語選択画面が出てくるので今回はhtmlを入力し、html.jsonを選択し開く
この中にスニペットを書いていけばhtmlの中で呼び出すことができます。"Thymeleaf value": { "prefix": "tval", "body": "th:value=\"\\${$1.$2}\"", },解説
"Thymeleaf value"
スニペット名…スニペットの名前を決めます。(このファイルの中で区別するためのもの)
"prefix": "tval",
実際に入力する単語…この文字をhtmlファイルで入力することで呼び出せます。
"body": "th:value=\"\\${$1.$2}\"",
呼び出されるもの…prefixを入力するとこちらが呼び出されます。
1行の場合は、""の中、2行以上の場合は[]で入れてください。
\$1…呼び出された後の入力位置tabキーを押すと\$2、\$3と移動することができます。
\…"は\、\$は\\など、特殊文字を単なる文字列として使いたい場合は、エスケープしてください。実演
Thymeleaf用に作成
では、これをThymeleaf用に作成していきたいと思います。
"Thymeleaf comment": { "prefix": "tcom", "body": "<!--/* $1 */-->", }, "Thymeleaf value": { "prefix": "tval", "body": "th:value=\"\\${$1.$2}\"", }, "Thymeleaf text": { "prefix": "ttex", "body": "th:text=\"\\${$1.$2}\"", }, "Thymeleaf local": { "prefix": "twit", "body": "th:with=\"x=$1,y=$2\"", }, "Thymeleaf link": { "prefix": "tlink", "body": "th:href=\"\\@{'/' + \\${$1.$2}}\"" , }, "Thymeleaf if": { "prefix": "tif", "body": "th:if=\"\\${$1}\"" , }, "Thymeleaf unless": { "prefix": "tif", "body": "th:unless=\"\\${$1}\"" , }, "Thymeleaf switch": { "prefix": "tswit", "body": [ "<div th:switch=\"\\${$1}\">", "\t<p th:case=\"$2\" th:text=\"\\${$3}\"></p>", "\t<p th:case=\"$4\" th:text=\"\\${$5}\"></p>", "\t<p th:case=\"*\">対象なし</p>", "</div>" ] , }, "Thymeleaf for": { "prefix": "tfor", "body": [ "<tr th:each=\"$2 : \\${$1}\">", "\t<td th:text=\"\\${$3.$4}\"></td>", "\t<td th:text=\"\\${$5.$6}\"></td>", "\t<td th:text=\"\\${$7.$8}\"></td>", "</tr>", ] , },あとがき
とりあえず最近使っているものだけまとめましたが、他にもThymeleafの記法はあるので随時追加して使っていきたいと思います。また、これを改変すれば他の言語にも応用できるので積極的に使用していこうと思いました。
参考にした記事


