- 投稿日:2019-03-27T22:34:03+09:00
HttpSession session = request.getSession();とは
プログラミング初心者です。
今回は、.getSessionについてアウトプットさせていただきます。Q1: .getSessionメソッドとは?
A: セッションを開始させる処理です。
(例)ユーザーのログイン認証処理が終わった後。
Q2: セッションとは?
A: プログラムにアクセスした際、1回のアクセスで行われる一連のやりとりのこと
Q1: セッションを開始させる処理があるのなら終了させる処理もいるんじゃなのか?
A:要ります。
(例)ユーザーがログアウトした後
[書き方]
session.invalidate();
これだけです。※間違い等ありましたらコメントから教えていただけると幸いです。※
- 投稿日:2019-03-27T22:04:34+09:00
HttpServlet()のメソッドについて
プログラミング初学者です。
今回はHttpServletのメソッドについてアウトプットさせていただきます。HttpServletのメソッドの概要
・protected void doGet(HttpServletRequest request,HttpServletResponse response)
・protected void doPost(HttpServletRequest request,HttpServletResponse response)
・protected void doPut(HttpServletRequest request,HttpServletResponse response)
・protected void doHead(HttpServletRequest request,HttpServletResponse response)
etc....
これらはHTTPメソッドをServletで受け取りたい時に書く必要があるものです。
HttpServletのメソッドを記述することによってServlet にHTTPリクエストを処理可能にさせるため、(service メソッド経由で)サーバによって呼び出されます。例えば、
ユーザーの新規登録でユーザーの情報をDBに保存したいだけの場合はHTTPメソッドはPOSTになると思うので、
Servletには、
protected void doPost(HttpServletRequest request,HttpServletResponse response)
を記述し、その中に処理を書き込む必要があるということです。なぜHttpServletのメソッドを記述する前に@Overrideを書かないといけないのか?
正直ちゃんと理解はしておらず雰囲気だけわかった状態なので説明が書いてあるURLを以下に貼っておきます。
@Overrideについて
このページの冒頭らへんに、Web サイトに適した HTTP Servlet を生成するために、サブクラス化を前提とする抽象クラスを提供します。 HttpServlet のサブクラスでは、少なくとも、以下に挙げられている1つのメソッドをオーバーライドする必要があります。
doGet メソッド, Servlet が HTTP GET リクエストをサポートする場合
doPost メソッド, HTTP POST リクエストをサポートする場合
doPut メソッド, HTTP PUT リクエストをサポートする場合と書いてあると思います。ここが理由となっているので読んでみてください。
毎回かなりふわっとした内容になっております。すみません
また、改善点や間違っている場所等ありましたら、恐れ入りますがコメントから教えていただけると幸いです。
- 投稿日:2019-03-27T19:32:18+09:00
【Android】ListPopupWindowを使った入力候補の表示
0.実行例
1.コード全体
MainActivity.javapackage com.example.listpopupwindowtest; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ListPopupWindow; public class MainActivity extends AppCompatActivity { String[] strList = {"あいうえお","かきくけこ","さしすせそ"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final EditText et_1 = (EditText)findViewById(R.id.et_1); final ListPopupWindow lpw = new ListPopupWindow(this); lpw.setAdapter(new ArrayAdapter<String>( this,android.R.layout.simple_list_item_1,strList)); lpw.setAnchorView(et_1); lpw.setModal(true); et_1.setOnTouchListener(new View.OnTouchListener() { final int DRAWABLE_RIGHT = 2; @Override public boolean onTouch(View v, MotionEvent event) { if(event.getAction()==MotionEvent.ACTION_UP){ if(event.getX()>=v.getWidth()-((EditText) v) .getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width()){ lpw.show(); ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)) .hideSoftInputFromWindow(v.getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS); return true; } } return false; } }); lpw.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { et_1.setText(strList[position]); lpw.dismiss(); } }); } }2.入力欄の右端に▼マークを付ける
下記のリソースファイルをダウンロードし、core/res/res/drawable-hdpi/numberpicker_down_normal_holo_light.pngをdrawableフォルダにコピーする。
https://android.googlesource.com/platform/frameworks/base/+/efd1c67EditTextのdrawableRightで、コピーした画像ファイルを指定する。
<EditText android:id="@+id/et_1" android:layout_width="match_parent" android:layout_height="wrap_content" android:drawableRight="@drawable/numberpicker_down_normal_holo_light"/>参考
- 投稿日:2019-03-27T19:03:44+09:00
Corda関連のおすすめ記事一覧
- 投稿日:2019-03-27T16:33:57+09:00
デザインパターン ~Interpreter~
1. はじめに
GoFのデザインパターンにおける、Interpreterパターンについてまとめます。
2. Interpreterパターンとは
- Interpreterという英単語は、通訳という意味になります。
- Interpreterパターンは、何らかの形式で書かれたファイルの中身を、「通訳」の役目を果たすプログラムで解析・表現する方式です。
- GoFのデザインパターンでは、振る舞いに関するデザインパターンに分類されます。
3. サンプルクラス図
4. サンプルプログラム
テキストファイルに書かれた言語を構文解析するプログラムです。
構文解析対象テキストで使う言語の文法ではBNF記法を使います。<program> ::= program <command list> <command list> ::= <command>* end <command> ::= <repeat command> | <primitive command> <repeat command> ::= repeat <number> <command list> <primitive command> ::= go | right | left
<program>・・・トークン program の後にコマンドの列が続いたもの、になります。<command list>・・・が0個以上繰り返したあとトークン end が続いたもの、になります。<command>・・・繰り返しコマンドまたは基本コマンドのいずれか、になります。( | は or を表す)<repeat command>・・・トークン repeat のあとに繰り返し回数が続き,さらにコマンドの列が続いたもの、になります。<primitive command>・・・go または right または left 、になります。4-1. Contextクラス
構文解析のための前後関係を表すクラスです。
Context.javaimport java.util.StringTokenizer; public class Context { private StringTokenizer tokenizer; private String currentToken; public Context(String text) { tokenizer = new StringTokenizer(text); nextToken(); } public String nextToken() { if (tokenizer.hasMoreTokens()) { currentToken = tokenizer.nextToken(); } else { currentToken = null; } return currentToken; } public String currentToken() { return currentToken; } public void skipToken(String token) throws Exception { if (!token.equals(currentToken)) { throw new Exception("Warning: " + token + " is expected, but " + currentToken + " is found."); } nextToken(); } public int currentNumber() throws Exception { int number = 0; try { number = Integer.parseInt(currentToken); } catch (NumberFormatException e) { throw new Exception("Warning: " + e); } return number; } }4-2. Nodeクラス
構文木の「ノード」となるクラスです。
Node.javapublic abstract class Node { public abstract void parse(Context context) throws Exception; }4-3. ProgramNodeクラス
に対応するクラスです。
ProgramNode.java// <program> ::= program <command list> public class ProgramNode extends Node { private Node commandListNode; public void parse(Context context) throws Exception { context.skipToken("program"); commandListNode = new CommandListNode(); commandListNode.parse(context); } public String toString() { return "[program " + commandListNode + "]"; } }4-4. CommandNodeクラス
に対応するクラスです。
CommandNode.java// <command> ::= <repeat command> | <primitive command> public class CommandNode extends Node { private Node node; public void parse(Context context) throws Exception { if (context.currentToken().equals("repeat")) { node = new RepeatCommandNode(); node.parse(context); } else { node = new PrimitiveCommandNode(); node.parse(context); } } public String toString() { return node.toString(); } }4-5. RepeatCommandNodeクラス
に対応するクラスです。
RepeatCommandNode.java// <repeat command> ::= repeat <number> <command list> public class RepeatCommandNode extends Node { private int number; private Node commandListNode; public void parse(Context context) throws Exception { context.skipToken("repeat"); number = context.currentNumber(); context.nextToken(); commandListNode = new CommandListNode(); commandListNode.parse(context); } public String toString() { return "[repeat " + number + " " + commandListNode + "]"; } }4-6. CommandListNodeクラス
に対応するクラスです。
CommandListNode.javaimport java.util.ArrayList; // <command list> ::= <command>* end public class CommandListNode extends Node { private ArrayList list = new ArrayList(); public void parse(Context context) throws Exception { while (true) { if (context.currentToken() == null) { throw new Exception("Missing 'end'"); } else if (context.currentToken().equals("end")) { context.skipToken("end"); break; } else { Node commandNode = new CommandNode(); commandNode.parse(context); list.add(commandNode); } } } public String toString() { return list.toString(); } }4-7. PrimitiveCommandNodeクラス
に対応するクラスです。
PrimitiveCommandNode.java// <primitive command> ::= go | right | left public class PrimitiveCommandNode extends Node { private String name; public void parse(Context context) throws Exception { name = context.currentToken(); context.skipToken(name); if (!name.equals("go") && !name.equals("right") && !name.equals("left")) { throw new Exception(name + " is undefined"); } } public String toString() { return name; } }4-8. 構文解析対象テキスト
構文解析対象となるテキストです。
program.txtprogram end program go end program go right go right go right go right end program repeat 4 go right end end program repeat 4 repeat 3 go right go left end right end end4-9. Mainクラス
メイン処理を行うクラスです。
Main.javaimport java.io.BufferedReader; import java.io.FileReader; public class Main { public static void main(String[] args) { try { BufferedReader reader = new BufferedReader(new FileReader("program.txt")); String text; while ((text = reader.readLine()) != null) { System.out.println("text = \"" + text + "\""); Node node = new ProgramNode(); node.parse(new Context(text)); System.out.println("node = " + node); } } catch (Exception e) { e.printStackTrace(); } } }4-10. 実行結果
text = "program end" node = [program []] text = "program go end" node = [program [go]] text = "program go right go right go right go right end" node = [program [go, right, go, right, go, right, go, right]] text = "program repeat 4 go right end end" node = [program [[repeat 4 [go, right]]]] text = "program repeat 4 repeat 3 go right go left end right end end" node = [program [[repeat 4 [[repeat 3 [go, right, go, left]], right]]]]5. メリット
Interpreterパターンを利用することで、規則の追加や変更が容易になります。
Interpreterパターンの特徴の1つに、「1つの規則を1つのクラスで表す」というものが挙げられます。つまり、新しい規則を追加する場合はNodeクラスのサブクラスを追加するだけで良くなります。
また、規則を修正する場合も、Nodeクラスのサブクラスを修正するだけになります。6. GitHub
7. デザインパターン一覧
8. 参考
今回の記事、及びサンプルプログラムは、以下の書籍を元に作成させて頂きました。
大変分かりやすく、勉強になりました。感謝申し上げます。
デザインパターンやサンプルプログラムについての説明が詳細に書かれていますので、是非書籍の方もご覧ください。
- 投稿日:2019-03-27T16:14:07+09:00
JUnit起動時にエラーが発生していた
はじめに
とあるプロジェクトにて単体テストクラスがエラーを吐き続けていたため、原因を調査。
その時の調査過程のメモです。発生していたエラー
SLF4J: Failed toString() invocation on an object of type [org.apache.poi.hssf.usermodel.HSSFRow] java.lang.AssertionError: hashCode not designed at org.apache.poi.hssf.usermodel.HSSFRow.hashCode(HSSFRow.java:704) at java.lang.Object.toString(Object.java:236) : :上記エラーのため、デバックログの出力に失敗していた模様。
しかし、失敗するのは一部のみで、テストクラスの実行自体は正常に行える状態。エラー発生箇所を見てみる
エラーが起きているHSSFRow.javaを見てみる
702: @Override 703: public int hashCode() { 704: assert false : "hashCode not designed"; 705: return 42; // any arbitrary constant will do 706: }どうやらhashCodeというメソッドが呼ばれると無条件でAssertionErrorを発生させる実装になっている様子
つまりこのメソッドが呼ばれてしまっているのがよろしくない模様。。ライブラリのバージョンを確認してみた
少し悩んでとりあえず各ライブラリのバージョンを確認してみることに。
- DBUnit:2.5.1
- POI:3.12
↑のバージョンが正しいのか調べるためGoogle先生に聞き込み。
(DBUnitを使用した結合試験データの積み込みの記事を参考にさせて頂きました。)POIが推奨されるバージョンではなかった
参考にさせて頂いた記事によると、POIのバージョンは3.2-FINALを使う、とのこと。
試しにバージョンを切り替えてみたところエラーの発生は無くなった。
- 投稿日:2019-03-27T14:30:31+09:00
Seasar2「Hello,World!」からの「Hello,Seasar2!」
Seasar2に興味があり書籍「Seasar2徹底入門」を読みました。
「Seasar2はJavaベースのDIコンテナ※1と呼ばれ、アプリケーションにDI(Dependency_Injection:依存性注入)機能を提供するフレームワーク」との記述がありました。DIコンテナ??となりましたので(汗)サンプルを実行することで理解へ向けて一歩進みましたので備忘録として記載させていただきました。
※1 DIコンテナ=アプリケーションにDI(Dependency_Injection:依存性注入)機能を提供するフレームワーク
実行環境
java version 1.8.0_202
Eclipse 2018-12(4.10.0)1.Eclipseプラグイン Dolteng※2 インストール
※2 DoltengはSeasar2ライブラリでJavaプロジェクトを簡単に作成することができます。
Eclipseのメニューから[ヘルプ]→[新規ソフトウェアのインストール]
http://eclipse.seasar.org/updates/3.3/2.Eclipseのメニューから[ファイル]→[新規]→[その他]を選択し、新規作成ウィザードを表示
ウィザードの中から[Dolteng]→[Doltengプロジェクト]プロジェクト名:seasar2_sample
ルートパッケージ名:org.seasar2.sample
スタンドアロン・アプリケーションを選択
以下が参照ライブラリ配下に配置されていることを確認
s2-extension-2.4.46.jar
s2-framework-2.4.46.jar
★s2-tiger-2.4.46.jar★s2-tiger-2.4.46を以下から取得
http://s2container.seasar.org/2.4/ja/downloads.html
「パッケージ・エクスプローラー」ビューでプロジェクトを選択、
右クリックしてコンテキスト・メニューの「ビルド・パス」>「外部アーカイブの追加」で「s2-tiger-2.4.46.jar」選択3.「seasar2_sample」パッケージ配下に以下ファイルを作成
package seasar2_sample; public interface ISampleA { public String getName(); }package seasar2_sample; public interface ISampleB { public void settingHoge(ISampleA hoge); public String getMessage(); }package seasar2_sample; public class SampleClassA implements ISampleA { @Override public String getName(){ return "World"; } }package seasar2_sample; public class SampleClassB implements ISampleB { private ISampleA hoge; @Override public void settingHoge(ISampleA hoge){ this.hoge = hoge; } @Override public String getMessage(){ return "Hello, " + hoge.getName() + "!"; } }package seasar2_sample; import org.seasar.framework.container.SingletonS2Container; import org.seasar.framework.container.factory.SingletonS2ContainerFactory; public class StartUp { public static void main(String[] args) { SingletonS2ContainerFactory.init(); ISampleB piyo = SingletonS2Container.getComponent(ISampleB.class); System.out.println(piyo.getMessage()); SingletonS2ContainerFactory.destroy(); } }4.「app.dicon」ファイルに以下を記載
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd"> <components> <component name="seasar2_sample" class="seasar2_sample.SampleClassA" instance="singleton" /> <component name="seasar2_sample" class="seasar2_sample.SampleClassB" instance="singleton" /> </components>5.コンソールに「Hello,World!」と表示されることを確認
6.続いてDIを試すために以下ファイルを作成
package seasar2_sample; public class SampleClassC implements ISampleA { @Override public String getName(){ return "Seasar2"; } }7.「app.dicon」を修正
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd"> <components> <component name="seasar2_sample" class="seasar2_sample.SampleClassC" instance="singleton" /> <component name="seasar2_sample" class="seasar2_sample.SampleClassB" instance="singleton" /> </components>8.コンソールに「Hello,Seasar2!」と表示されることを確認できました。
Seasar2はプロパティの型がインターフェースの場合、自動的にそのインターフェースを実装したコンポーネントをセットしてくれます。この機能を自動バインディングと呼びます。
実装コードには一切手ををいれずにコンポーネントを差し替えることができるのがDIのメリット。
う~ん・・・難しいですがサンプルを試すことで理解へ向けて一歩進んだ気がします(笑)
- 投稿日:2019-03-27T14:30:31+09:00
Seasar2「Hello,World!」~「Hello,Seasar2!」
Seasar2に興味がありまして、書籍「Seasar2徹底入門」を読みました。
「Seasar2はJavaベースのDIコンテナ※と呼ばれ、アプリケーションにDI(Dependency_Injection:依存性注入)機能を提供するフレームワーク」との記述がありました。DIコンテナ??となりましたので(汗)サンプルを実行することで理解へ一歩進みましたので備忘録として記載させていただきます。
※DIコンテナ=アプリケーションにDI(Dependency_Injection:依存性注入)機能を提供するフレームワーク
実行環境
java version 1.8.0_202
Eclipse 2018-12(4.10.0)1.EclipseプラグインDoltengインストール
Eclipseのメニューから[ヘルプ]→[新規ソフトウェアのインストール]
http://eclipse.seasar.org/updates/3.3/※DoltengはSeasar2ライブラリでJavaプロジェクトを簡単に作成することができます。
2.Eclipseのメニューから[ファイル]→[新規]→[その他]を選択し、新規作成ウィザードを表示
ウィザードの中から[Dolteng]→[Doltengプロジェクト]プロジェクト名:seasar2_sample
ルートパッケージ名:org.seasar2.sample
スタンドアロン・アプリケーションを選択
以下が参照ライブラリ配下に配置されていることを確認
s2-extension-2.4.46.jar
s2-framework-2.4.46.jar
★s2-tiger-2.4.46.jar★s2-tiger-2.4.46を以下から取得
http://s2container.seasar.org/2.4/ja/downloads.html
「パッケージ・エクスプローラー」ビューでプロジェクトを選択、
右クリックしてコンテキスト・メニューの「ビルド・パス」>「外部アーカイブの追加」で「s2-tiger-2.4.46.jar」選択3.「seasar2_sample」パッケージ配下に以下のファイルを作成
package seasar2_sample; public interface ISampleA { public String getName(); }package seasar2_sample; public interface ISampleB { public void settingHoge(ISampleA hoge); public String getMessage(); }package seasar2_sample; public class SampleClassA implements ISampleA { @Override public String getName(){ return "World"; } }package seasar2_sample; public class SampleClassB implements ISampleB { private ISampleA hoge; @Override public void settingHoge(ISampleA hoge){ this.hoge = hoge; } @Override public String getMessage(){ return "Hello, " + hoge.getName() + "!"; } }package seasar2_sample; import org.seasar.framework.container.SingletonS2Container; import org.seasar.framework.container.factory.SingletonS2ContainerFactory; public class StartUp { public static void main(String[] args) { SingletonS2ContainerFactory.init(); ISampleB piyo = SingletonS2Container.getComponent(ISampleB.class); System.out.println(piyo.getMessage()); SingletonS2ContainerFactory.destroy(); } }4.「app.dicon」ファイルに以下を記載
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd"> <components> <component name="seasar2_sample" class="seasar2_sample.SampleClassA" instance="singleton" /> <component name="seasar2_sample" class="seasar2_sample.SampleClassB" instance="singleton" /> </components>5.コンソールに「Hello,World!」と表示されることを確認
6.続いてDIを試すために以下ファイルを作成
package seasar2_sample; public class SampleClassC implements ISampleA { @Override public String getName(){ return "Seasar2"; } }7.「app.dicon」を修正
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd"> <components> <component name="seasar2_sample" class="seasar2_sample.SampleClassC" instance="singleton" /> <component name="seasar2_sample" class="seasar2_sample.SampleClassB" instance="singleton" /> </components>8.コンソールに「Hello,Seasar2!」と表示されることを確認できました。
Seasar2はプロパティの型がインターフェースの場合、自動的にそのインターフェースを実装したコンポーネントをセットしてくれます。この機能を自動バインディングと呼びます。
実装コードには一切手ををいれずにコンポーネントを差し替えることができるのがDIのメリット。
う~ん・・・難しいですがサンプルを試すことで理解へ一歩進んだ気がします(笑)
- 投稿日:2019-03-27T10:04:10+09:00
【Android】EditText でのアルファベット大文字制限、長さ制限
EditText でのアルファベット大文字制限
Android アプリでの入力ボックスとして使われる EditText で、
アルファベット大文字のみの入力に制限したい!
iOS の場合は 【iOS】UITextField でのアルファベット大文字制限、長さ制限 を参照してください。環境
ホスト: Windows 10
Android Studio: 3.3.2
Java属性の設定で行う場合
レイアウトを開き対象の UITextField を選択して 右ペインの属性:digits を開いて編集します。
android:digits="ABCDEFGHIJKLMNOPQRSTUVWXYZ"他の制約もまとめて適用する場合
フィルターの準備
MyActivity.java// アルファベットフィルタ private InputFilter alphabetFilter = new InputFilter() { @Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { if (source.toString().matches("^[a-zA-Z]+$")) { return source.toString().toUpperCase(Locale.ROOT); } else { return ""; } } };EditText にフィルター設定
- onCreate 関数内などで実装
MyActivity.javaInputFilter myFilters[] = {alphabetFilter, new InputFilter.LengthFilter(5)}; // 大文字+アルファベットフィルタ+長さフィルタ EditText targetEditText = findViewById(R.id.edittext_target); targetEditText.setFilters(myFilters);実機テスト
キーボードにて数字入力ができない事、長さの制限がされていること、
小文字を入力した場合に大文字に自動変換されることを確認します。以上、お疲れ様でした!
- 投稿日:2019-03-27T09:20:57+09:00
Java で Azure Bing SpellCheck を利用する
Java で Azure Bing SpellCheckを利用するには
・自前でHTTPリクエストを作成する
・Azure Java SDKを利用する
の二通りがありますが、SDK利用の方法メモです。
案外たどり着くのに時間がかかりました。Maven
こちらです。これが意外に見つからなかったです。
https://mvnrepository.com/artifact/com.microsoft.azure.cognitiveservices/azure-cognitiveservices-spellcheck/1.0.2Sample
できないこと
HTTPレスポンスのJSONをそのまま取得してファイルに保存しておき、キャッシュとして利用することでAPI呼び出しの回数を減らすということを考えていたのですが、本家SDKではレスポンスをそのまま取得するメソッドは実装されていないように見えます。そりゃソースコードを変えれば可能なのでしょうけれど。
- 投稿日:2019-03-27T03:21:16+09:00
Javaの引数は値渡しなのか、参照渡しなのか
正直知ってても知らなくても困ることはないのですが、Javaの引数の渡し方のお話です。
Javaは参照渡しと言われることが多くて、でもなんだかそのあたり腹落ちせずもやもやしてたのがC++の勉強をしていて霧が晴れた感があったので記事にしてみました。
くり返しになりますが、別にJavaに限っていったら知っててても知らなくてもどうでもいいことです。
プリミティブ型の場合
public static void main(String[] args) { int a = 1; int b = 2; System.out.println("Before swap"); System.out.println("a = " + a); System.out.println("b = " + b); swap(a, b); System.out.println("After swap"); System.out.println("a = " + a); System.out.println("b = " + b); } static void swap(int x, int y) { System.out.println("In swap"); int t = x; x = y; y = t; System.out.println("x = " + x); System.out.println("y = " + y); }出力Before swap a = 1 b = 2 In swap x = 2 y = 1 After swap a = 1 b = 2
swapメソッドの引数x、yは呼び出し元のa、bのコピーであり異なる実体です。したがって、swapメソッドの中でxとyの値が入れ替わっても呼び出し元に影響は及びません。これがすなわち
値の値渡しです。オブジェクトの場合
public static void main(String[] args) { Integer c = new Integer(1); Integer d = new Integer(2); System.out.println("Before swap"); System.out.println("c = " + c); System.out.println("d = " + d); swap(c, d); System.out.println("After swap"); System.out.println("c = " + c); System.out.println("d = " + d); } static void swap(Integer x, Integer y) { System.out.println("In swap"); Integer t = x; x = y; y = t; System.out.println("x = " + x); System.out.println("y = " + y); }出力Before swap c = 1 d = 2 In swap x = 2 y = 1 After swap c = 1 d = 2結果はプリミティブ型と同じく、
swapメソッド内で値が入れ替わっても、呼び出し元の値は入れ替わりません。
swapメソッドにはIntegerクラスのインスタンスに対する参照が引数として渡されます。
ただし、引数に渡される参照は、プリミティブ型の場合と同じく呼び出し元における参照のコピーとなります。
つまり、swapメソッドでxとyの参照を入れ替えたとしても呼び出し元aとbの参照は変更されません。
これはすなわち参照の値渡しということなります。でも、オブジェクトの場合参照を引数に渡してるんだから参照渡しっていってもいいんじゃない?
以降は余談です。
厳密な意味での参照渡しって、たぶんC++でいうところの参照を引数として受け渡しすることだと思うんです。
でも、私が大昔すこしだけC言語をかじったときも引数の値渡し、参照渡しっていい方をしていた記憶があって、C言語の参照渡しってポインタを引数として渡すことだと思うですが、これも厳密にいうと
ポインタの値渡しです。正直なところ、C言語での文脈とか理解が曖昧なのですが、もし
ポインタの値渡しを参照渡しという文脈があるなら、Javaのオブジェクトだって、参照渡しといってもいいんじゃない?自分なりの結論
厳密にはJavaは値渡しである。
でも、暴論めいたことを言うと、参照渡しと言ってそれも間違ってはないっしょ。本当に大切なのは
それが値渡しだろうが参照渡しだろうが、Javaに関してはオブジェクト引数にわたす場合その参照が渡されることには違いない。
参照の向き先はメソッドの呼び出し元、メソッド内でもおなじになるので、メソッド内で参照介してオブジェクトを操作した場合、呼び出し元に副作用的に影響が及び得る、ということです。
- 投稿日:2019-03-27T00:56:45+09:00
テスト投稿
javaのstream
で特定のフィールドが一致するインスタンス毎の処理List<Hoge> hogeList = 初期化; Map<Integer,List<Hoge>> hogeMap = hogeList.stream().collect(Collectors.groupingBy(hoge -> hoge.getId())); for(Integer id : hogeMap.keySet()){ for(Hoge hoge : hogeMap.get(id)){ //hogeに対する処理 } }Primaryキーが複数の場合は(伝われ)Keyを文字列結合等すればよいと思う。
SQLのin句
複合主キー(カラムA, B)が設定されたテーブルから、
カラムA をin句での取得条件とし、
in句内すべての値が一致する、カラムB を取得したいときのクエリ。
※適当に考えたシチュエーションSELECT カラムB, count(*) FROM テーブル WHERE カラムA in (?) GROUP BY カラムB HAVING count(*) = 条件の個数(?の数)カラムC(bool) があったとして、
カラムA in (1,2,3) の場合 カラムC = true 、
カラムA in (4,5,6) の場合 カラムC = false
といった条件全てに当てはまる カラムB を取得したいみたいな時は、
上記クエリと、上記クエリをサブクエリとしたものとを内部結合し、
それぞれの取得条件内に カラムC の条件を追加すればいける気がする。パフォーマンスは度外視
自宅に環境がないため、すべて妄想。
適当にチャチャっと書いたのでおそらくミスが多い。
とりあえず投稿のテストです。内容はないよぅ。
お試し投稿なので多めに見てください。
今後書くことがあれば真面目に書きます。
- 投稿日:2019-03-27T00:13:37+09:00
Apache Arrow で Java と python のデータ交換を調査
今回は Apache Arrow を利用して Java と python でデータの交換について調べました。
はじめに
Apache Arrow を用いたデータ交換はメモリ内でコピーを行わずにシステム、言語間でコピーできる事を期待します。
結論を先に書くと、今回の調査では Apache Arrow 形式のバイト配列を経由して交換になりました。
ローカルディスクには書き出さなくてもよいのですが、Java でのシリアライズと python でのデシリアライズが行われるためメモリ内でのデータコピーが発生してしまいます。
今回紹介する方法の利点としては Apache Arrow という高速な共通フォーマットがあるため言語間の連携が簡単にできることだと思います。Apache Arrow での Java と python のデータ交換について
Apache Arrow では Java と python とのデータ交換に jvm というライブラリがありました。
このライブラリには java の Apache Arrow のオブジェクト VectorSchemaRoot を渡すと、python の RecordBatch に変換してくれる関数が実装されています。def record_batch(jvm_vector_schema_root): """ Construct a (Python) RecordBatch from a JVM VectorSchemaRoot Parameters ---------- jvm_vector_schema_root : org.apache.arrow.vector.VectorSchemaRoot Returns ------- record_batch: pyarrow.RecordBatch """そのため、py4j などを利用する事により、Java と python でのデータ交換を簡単にできると想定されます。
事前準備
py4j を使うために、必要な jar を取得します。
以下の pom で arrow と py4j の jar をローカルに持ってきます。<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>gtest</groupId> <artifactId>gtest</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>gtest</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.apache.arrow</groupId> <artifactId>arrow-vector</artifactId> <version>0.12.0</version> </dependency> <dependency> <groupId>net.sf.py4j</groupId> <artifactId>py4j</artifactId> <version>0.10.8.1</version> </dependency> </dependencies> </project>maven のコマンドは以下となります。
$ mvn dependency:copy-dependencies -DoutputDirectory=./lib -f ./pom.xmljvm のライブラリを試す
py4j のサンプルを参考に簡単な java のクラスを作成します。
また、py4j での動作検証をするために VecotrSchemaRoot を返す関数も実装します。import java.util.List; import java.util.ArrayList; import py4j.GatewayServer; import org.apache.arrow.memory.RootAllocator; import org.apache.arrow.vector.BitVector; import org.apache.arrow.vector.VectorSchemaRoot; public class Py4jExample { public static void main( final String[] args ) { Py4jExample app = new Py4jExample(); GatewayServer server = new GatewayServer( app ); server.start(); } /** * 試すために VectorSchemaRoot を作成する関数を用意. */ public static VectorSchemaRoot create() { RootAllocator allocator = new RootAllocator( Integer.MAX_VALUE ); BitVector vector = new BitVector( "test" , allocator ); vector.allocateNew( 1 ); vector.setSafe( 0 , 1 ); vector.setValueCount( 1 ); List list = new ArrayList(); list.add( vector ); VectorSchemaRoot root = new VectorSchemaRoot( list ); root.setRowCount( 1 ); return root; } }コンパイルし起動します。
$ javac -cp lib/*:. Py4jExample.java $ java -cp lib/*:. Py4jExample &python から呼び出す準備が整ったので、python の処理を書きます。
from py4j.java_gateway import JavaGateway import pyarrow as pa import pyarrow.jvm as j from pyarrow import RecordBatch gateway = JavaGateway() root = gateway.jvm.Py4jExample.create() rb = j.record_batch( root ) df = rb.to_pandas()このように jvm ライブラリを使えば、簡単に java から python の record_batch に変換ができると思いましたが・・・
$ python test.py Segmentation faultRecordBatch を取得するところまでは実行ができますが、to_pandas() を呼び出すと落ちるみたいです。
自分の環境が悪かったのか区別がつきませんが、すぐに分かりそうに無さそうだったため今回は諦める事にしました。Apache Arrow のバイト配列でのデータ交換
別な方法としては、Apache Arrow はファイルにバイナリとしてのフォーマットも実装されているため、バイト配列で Java と python で読み書きが可能です。
現在(2019/03時点)のpython の jvm の実装を見たところ、Java のオブジェクトを受け取り python のオブジェクトに変換する際にメモリでのコピーをしているようでした。
そのため、バイト配列でのデータ交換ではシリアライズ、デシリアライズが必要ですが、Java でのバイト配列へのシリアライズのみがコストとなります。バイト配列での Java と python のデータ交換
Java のクラスにバイト配列を作成する関数を追加します。
/** * 試すためにArrow のバイト配列を作成する関数を用意. */ public static byte[] createArrowFile() throws IOException { RootAllocator allocator = new RootAllocator( Integer.MAX_VALUE ); BitVector vector = new BitVector( "test" , allocator ); vector.allocateNew( 1 ); vector.setSafe( 0 , 1 ); vector.setValueCount( 1 ); List list = new ArrayList(); list.add( vector ); VectorSchemaRoot root = new VectorSchemaRoot( list ); root.setRowCount( 1 ); ByteArrayOutputStream out = new ByteArrayOutputStream(); ArrowFileWriter writer = new ArrowFileWriter( root, null, Channels.newChannel( out ) ); writer.start(); writer.writeBatch(); writer.end(); writer.close(); return out.toByteArray(); }このクラスをコンパイルし、再度起動させます。
python での処理はバイト配列から RecordBatch を取得するように修正を行います。from py4j.java_gateway import JavaGateway import pyarrow as pa import pyarrow.jvm as j from pyarrow import RecordBatch gateway = JavaGateway() reader = pa.RecordBatchFileReader( pa.BufferReader( gateway.jvm.Py4jExample.createArrowFile() ) ) rb = reader.get_record_batch(0); df = rb.to_pandas() print dfこちらの実行結果は予定通り、Java で作成された VectorSchemaRoot を python で RecordBatch として扱う事ができました。
$ python test2.py test 0 Trueまとめ
Java と python のデータ交換は現時点では強引に連携する実装になってしまいました。
しかし、Apache Arrow は pandas など python でデータ処理を行うライブラリとの相性が良い事と、独自のシリアライズ、デシリアライズを実装しなくても良いという利点があります。この調査の目的は現在開発を行っているファイルフォーマットが Java で実装されていて、データ処理で良く使われる python でも利用可能にするためにでした。
次回はこの調査を元にバイト配列で python からファイルフォーマットへの読み書きを行った実装と動作例を書きたいと思います。





