20190503のJavaに関する記事は3件です。

【初心者向け】JavaGoldが解説するPythonの基礎 パート2

概要

パート1に引き続きPythonの基礎的内容をシェアできればと思います!
ご覧になっていない方は、まずはパート1を^^

アジェンダ

・if文
・for文
・関数
・例外処理
・pass文
・スコープ
・クラス
・クロージャ
・引数
・終わりに

if文

Javaのswitch~case構文は存在しないが、「in」と言うキーワードを使うことで同じような実装が可能。「elif」は、「else if」の略。

・if文

val1 = 1
val2 = 2

if val1 == val2:
  print('test1')
elif val1 > val2:
  print('test2')
else:
  print('test3') # test3

・「in」キーワードを使用した、switch文ライクな書き方

val3 = 3

if val3 == 1:
  print('test1')
elif val3 in(2,3):
  print('test2') # test2
elif val3 in(3,4):
  print('test3')
else:
  print('test4')

for文

for文は、Javaのforeach文に相当。range関数と組み合わせて使うことが多い。

・for文とrange関数

for i in range(3):
  print(i) # 0、1、2と順に表示

・for文と文字列(リストや辞書なども使用可能)

for c in 'test':
  print(c) # t, e, s, tと順に表示

ちなみに。。。
Pythonは、while文はあるが、do-while文は存在しない。

関数

関数の定義には「def」を使用。※引数は全て参照渡し。値渡し。

def fnc(a, b=1): # bはデフォルト値付きの引数
  return a + b # 戻り値

# 関数呼び出し
print(fnc(10)) # 11 

・関数を呼び出す際に、引数名を指定することで定義順を無視することが可能。

def fnc(a, b, c):
  print(a, b, c)

# 関数呼び出し
fnc(c=3, a=1, b=2)# 1 2 3

■ 関数とメソッドの違い
ほとんど一緒の様なものと思って良いです!

関数:特定のクラスには縛られないもの。モジュール内にdefで定義されたもの。
クラス内のインスタンス化する前のdefで定義したものは関数。
書き方: 関数( 引数 )

メソッド:特定のクラス(またはそのクラスのインスタンス)専用のもの。クラス内にdefで定義されたもの。クラスがインスタンス化された後、関数がメソッドになる。
書き方: 値.メソッド( 引数 )

例えば len("文 字 列") は "文 字 列" の長さを取得する関数なのに、 "文 字 列".split() は文字を空白文字で分割する メソッド (オブジェクト.関数) ですね。
基本的にはメソッドの場合は、そのオブジェクト固有の処理が多いです。
例えば "文字列".split や "文字列".startswith などです。これは文字列固有です。
ですが len は文字列にも、リストにも使えます。 len("文字列") len([0, 1, 2]) なのです。こういった場合は、Pythonでは関数で用意されています。

・Pythonの関数(オブジェクト) と オブジェクト.関数() の違いは何ですか?
http://blog.pyq.jp/entry/2017/09/14/100000

※関数の全ての引数は参照渡しされるが、渡されたオブジェクトの型(mutable型とimmutable型)で挙動が異なる!
変更可能(mutable)な型では元の値は変更される。一方、変更不可(immutable)な型では元の値は変更されない。
変更不可(immutable)な型をもつオブジェクトが渡されたときは値渡し。

■変更不可(immutable)な型
・int, float, complexといった数値型
・文字列型(string)
・タプル型(tuple)
・bytes
・Frozen Set型

■変更可能(mutable)な型
・リスト型(list)
・バイト配列(bytearray)
・集合型(set)
・辞書型(dictionary)

例外処理

「try~except~else~finally」という構文で処理。
exceptがJavaで言うcatch文で”例外が発生した時に実行する文、elseはexceptに補足されなかった処理を記述する。

try:
  x = 10 / 0
except Exception as e:
  print(e) # division by zero
# 例外が発生しなかった場合に行う処理  
else:
  print('test1')
# 例外発生有無に関係なく必ず走る処理 
finally:
  print('test2')# test2

・明示的に例外を発生させるには「raise」を使用する。(Javaではthrow文)

try:
  raise Exception('test3')
except Exception as e:
  print(e) # test3

pass文

「何もしない」ことを明示するための構文。Javaにはない。

例えば、以下の様な時に使用する。
・条件分岐のときに何も実行しない
・例外が発生したときに何もしない
・関数やクラスの実装が明確でない

# 偶数のみ出力
for i in range(10): 
if(i % 2) == 0:
  print(i)
else:
  pass

スコープ

スコープの種類は以下の4種類。頭文字を取ってLEGB と言われている。

①ローカルスコープ(Local scope)
→関数内のみ。ローカルスコープからはビルトインスコープやモジュールスコープの変数や関数を参照することはできるが、変数に値を代入(上書き)することは不可。

②エンクロージング(Enclosing (function's) scope)
→関数の中で関数が定義されている、そんな場合に初めて意識するスコープで、端的にいうと関数の外側のローカルスコープ。

③グローバルスコープ(Global Scope)
→モジュール(ファイル全体)内全体。

④ビルトインスコープ(Built-in scope)
→組み込み変数(None)や組み込み関数(print関数)のスコープで、どこからでも参照可能。

スコープの詳細についてこちらの記事を参考にさせて頂きました。
詳細が記載されていますので、時間がある方はご覧下さい。

クラス

コンストラクタ(初期化メソッド)は「__init__」もしくは「_new__」にし、第一引数には必ず「self」を定義する。selfにするのは慣例で、thisとか好きな名前にすることも可能。
selfは自身のインスタンスを表すオブジェクト。インスタンスを受け取る引数名

Name.class
class Name:
  # クラス変数    
  LANG = 'JP'

  # コンストラクタ
  def __init__(self):
    self.name = ''

  # getter
  def getName(self):
    return self.name

  # setter
  def setName(self, name):
    self.name = name

taro = Name()
taro.setName('イチロー')
print(taro.getName()) # イチロー
print(Member.LANG) # JP

クロージャ

関数のローカル変数を参照するような関数。
関数呼び出しが終わってもローカル変数を参照し続けられる。
Javascriptのクロージャとほぼ同等。

クロージャの詳細についてはこちらの記事に載っています。

引数

引数の種類は以下の4種類。

①通常の引数

②デフォルト値付きの引数
→関数呼び出しの際に省略された場合に採用するデフォルト値を定義した引数のこと。

#②デフォルト値付きの引数
def fnc(a, b = 1):
  return a + b # 戻り値

③可変長の引数
→1つ以上の値を受け取る引数のこと。引数名の前にアスタリスク(*)を付ければこの引数になる。関数側では受け取った可変長引数はタプルとして扱う。

#③可変長の引数
def fnc(a, b, *args):
  print(a, b, args)

fnc('a','b','c','d','e') # a b ('c','d','e')

④キーワード付きの可変長の引数
→引数を指定する際に、キーワードを付ける必要がある可変長の引数。
引数名の前にアスタリスク(*)を二つ付ければこの引数になる。なお、関数側では受け取った可変長引数は、定義時に付けた名前を持つ辞書型のデータとして扱う。

#④キーワード付きの可変長の引数
def fnc(a, b, **args):
  print(a, b, args)

fnc('a','b',arg1 = 'c',arg2 = 'd',arg3 = 'e')# a b {'arg1': 'c', 'arg3': 'e', 'arg2': 'd'}
#fnc('a','b','c','d','e') ←キーワード指定しないとエラーになる

終わりに

パート1 & 2でおおよそのPythonの基礎を説明しました。
PythonにはWEBフレームワークや、機械学習ライブラリが豊富にあるのでこの基礎と組み合わせればやりたいことは実現できる?はず!!
自分はこれからPythonを使ったWebAPIを作りたいと思います:raised_hand:

参考文献

・Pythonの関数(オブジェクト) と オブジェクト.関数() の違いは何ですか?
http://blog.pyq.jp/entry/2017/09/14/100000

・Pythonのスコープについて
http://note.crohaco.net/2017/python-scope/

・【Python】クロージャ(関数閉方)とは
https://qiita.com/naomi7325/items/57d141f2e56d644bdf5f

・Pythonにおける値渡しと参照渡し
https://crimnut.hateblo.jp/entry/2018/09/05/070000

・AmadaShirou. Programing Keikensya No Tameno Python Saisoku Nyumon (Japanese Edition) Kindle 版

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Spring bootのテストでフィールドインジェクションしたクラスをSpring コンテナ使わずにテストする

ある程度のJavaの経験者であれば至極あたりまえのことなのですが、私と同じような問題をかかえ、「あ、そういえばそうか」的な感じの方もいらっしゃると思いますので書きます。ただのリフレクションの話です。
ただし、この方法がテスト設計として正しいとか正しくないかは別の知識になりますのであくまで方法の一つとしての記述になります。(アンチパターンの可能性もあります!)
書いててなんですが、今後はコンストラクタインジェクションを使用した設計で行こうと思ったきっかけとなった方法でもあります。

Spring の機能(コンテナ)を使ってテストするときの問題

私が従事しているプロジェクトではアプリの立ち上げにいろいろな情報を読み込むためか3分ほどかかり(貸与いただいているPCでは)テストが走るまでが遅いです。リズムよくユニットテストのサイクルしたいのに、Springコンテナを使ったテスト毎にこの時間はがかかるので、テストしたくない理由に十分なものでした。

たとえば、以下のようにテストでSpringコンテナを呼び出すとき(Spring boot ver 1.Xです。)

 テスト対象クラス

@Service
public class ParentService {

    @Autowired
    ChildService childService;// フィールドインジェクション

    public SampleForm generateSample(int n) {
        //ここで注入
        int calNumber = childService.calculate(n);
        return this.prepared(calNumber);
    }

    private SampleForm prepared(int calNumber) {
        int newN = calNumber * 2;
        SampleForm sample = new SampleForm();
        sample.setCalNumber(newN);
        return sample;
    }

}

テスト

@ActiveProfiles("test")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfig.class)
@WebIntegrationTest(randomPort = true)
@Transactional
public class SampleTest {

    @Autowired
    ParentService parentService;

    @Test
    public void generateメソッドに2を与えると4を持ったSampleFormが得られる() {
        SampleForm sample = parentService.generateSample(2)
        assertThat(sample.getCalNumber(), is(4));
    }
}

のように行いますが、
たとえばこの程度の短いテストを行う毎回に数分待つのではやってられません。

そこでいままでは例えば上記のような場合は ParentService.prepared
メソッドをpublicにして

//Springコンテナ機能を使わない。
public class SampleTest {

    ParentService parentService = new ParenteService();

    @Test
    public void preparedメソッドに2を与えると4を持ったSampleFormが得られる() {
        SampleForm sample = parentService.prepared(2)
        assertThat(sample.getCalNumber(), is(4));
    }
}

にしたり、なるべくメソッド内部でフィールドインジェクションのメソッドを呼ばないようにしたり、依存オブジェクトを引数にして渡したりするなどしてPOJOでテストできるようにしていました。フィールドインジェクションして呼び出したクラスはSpringコンテナを使用しないと注入されないためそのままPOJOとしてnewしたものにはnullでセットされます。以下のように書いた場合は
ParentService.generateSample 内で呼び出したchildeService.caluclateの時NullPointerExceptionが発生します。

public class SampleTest {

    ParentService parentService = new ParentService();

    @Test
    public void generateメソッドに2を与えると4を持ったSampleFormが得られる() {
        /*
        generateSampleメソッド内でchildService.caluclateを呼び出すが、このテストでは
        new ParentService()としているためchildServiceはnullなので例外が発生する
        */
        SampleForm sample = parentService.generateSample(2)//Exception!      
        assertThat(sample.getCalNumber(), is(4));
    }
}

ChildService.caluclateメソッドもpublicであり、別のテストでその検証を行い、ParentService.prepared もテストで検証ができれば
Parentservice.generateSample は正しいはずなのでテストしなくても正しいはずといえると思います(上記のような簡単な例であれば)。しかし、設計としてもともとParentService.preparedは外部から呼び出すメソッドとしておらず、テストのためにpublicにするのははたして正しいといえるのでしょうか?違う気がします。
また実際はこんな簡単な実装ではないのでやはりフィールドインジェクションにて注入したオブジェクトを持ったメソッドをテストしたいことが出てきます。

そこでふと思いました。
「動的言語であれば動的にフィールドにアクセスしてセットしたり、動的にメソッド定義できるのにな。。。まてよ?Javaにもリフレクションがあるな。」と。
普段Javaという言語では動的にフィールドを触ったりすることはありません。JavaScriptであれば動的にフィールド名を参照したりオブジェクトをメソッドを追加したりするのは当たり前の感覚で行えますが、Javaでの開発ではプロダクションコードに対して行うことは普通は(私の浅い知識の中では)ないと思います。理由はいろいろあると思いますがJavaの特性として静的型付けによる安全性が損なわれるというのが私の理解です。なのでリフレクションを使うという発想はまるでありませんでしたが上記のようなテストを行うために使えるんじゃないかと考えました。

そして以下のように書きました。

public class SampleTest {


    ParentService parentService = new ParentService();

    @Before
    public void setUp() {
        Class<?> c = parentService.getClass();
        parentService = (ParentService)c.newInstance();
        Field f = c.getDeclaredField("childService");
        f.setAccessible(true);
        f.set(parentService , new ChildService());

    }

    @Test
    public void generateメソッドに2を与えると4を持ったSampleFormが得られる() {
        /*
        generateSampleメソッド内でchildService.caluclateを呼び出す。リフレクションで
        でセットしているため以下のテストが可能である。
        */
        SampleForm sample = parentService.generateSample(2)        
        assertThat(sample.getCalNumber(), is(4));
    }
}

以上のように書くことでSpringコンテナを使わずにフィールドにアクセスしてセットし、
テストを行うことができます。よってテスト開始までの時間をまたずテストが可能になりました。
例ではnewしてChildServiceを渡していますが、振る舞いをもたせたmockをセットすることも可能です。

ただし、冒頭にも触れたように、そもそもインジェクションってなんだ?位の知識しかありませんでしたので上記方法を考えたことがきっかけになり、Springに関する本を読み返したり以下のブログを読んだりして設計を見直していこうと思うに至りました。

参考
SpringでField InjectionよりConstructor Injectionが推奨される理由

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaを使ってブラウザに「HelloWorld」を表示させる

【Javaで「Hello World」を表示させる 】

環境
・OS:macOS バージョン10.14.4
・Eclipseインストール済み

オペレーション
・まずはEclipseを起動。
・Eclipse後、メニューから「ファイル」-「新規」-「プロジェクト」をクリック。

・「web」-「動的 Web プロジェクト」をクリック。
・「次へ>」をクリック。

・「プロジェクト名:」には任意の名前を入力。
 今回は「HelloWorld」を使用。
・完了をクリック。

・プロジェクトが作成されることを確認する

・作成したプロジェクト(「HelloWorld」)で右クリック。
・「新規」-「ファイル」をクリック。
・「HelloWorld」-「WebContents」をクリック。
・ファイル名に任意の名前を入力。
 今回は「HelloWorld.jsp」を入力。
・完了をクリック。
・下記ソースを入力し保存する。
<!DOCTYPE html>


HelloWorld


HelloWorld
div>

・作成したファイル(HelloWorld.jsp)を右クリック。
・「実行」-「サーバーで実行」をクリック。
・「完了」をクリック。

・画面に以下のような表示がされる。

・パスをコピーする。

・ブラウザにコピペしてエンター。
・以下のように表示されたら成功。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む