Edited at

JavaエンジニアのためのRuby入門

More than 1 year has passed since last update.

ディップ Advent Calendar の17日目です:)


はじめに


どんな記事?

JavaエンジニアがRubyを書くようになり、

これJavaの◯◯みたいなことだったのか!」と思ったことを共有する記事です。

今回はコーディングについて書きます…!


目次

クラス

インスタンス化

メソッド

インスタンス化(引数あり)

配列/リスト

Map/ハッシュ

知っておくと役立ったこと

おわりに


クラス


Java


Father.java

// デフォルトパッケージ

public class Father {
}



Ruby


father.rb

class Father

end


インスタンス化


Java


Main.java

// デフォルトパッケージ

public class Main {

public static void main(String[] args) {
Father father = new Father();
}

}



Ruby


main.rb

require './father.rb' # ./father.rbを読み込む。javaでいうimportに似ています。

father = Father.new



メソッド


Java


宣言


Father.java

public class Father {

// staticなメソッド
public static void hello() {
System.out.println("Hello...");
}

// 非staticなメソッド(インスタンスメソッド)
public void tellTheTruth() {
System.out.println("I am your father.");
}

// 非staticなメソッド(インスタンスメソッド):引数あり
public void fuga(String words) {
System.out.println(words);
}

}



呼び出し


Main.java

public class Main {

public static void main(String[] args) {
Father.hello(); // Hello...
Father father = new Father();
father.tellTheTruth(); // I am your father.
father.fuga("Nooo!!"); // Nooo!!
}

}



Ruby


宣言


father.rb

class Father

# クラスメソッド
def self.hello
puts 'Hello...'
end

# インスタンスメソッド(引数なし)
# snake_case記法
def tell_the_truth
puts 'I am your father.'
end

# インスタンスメソッド(引数あり)
def fuga(words)
puts words
end
end



呼び出し


main.rb

require './father.rb'

Father.hello # hoge

father = Father.new

father.tell_the_truth() # I am your father.
father.tell_the_truth # I am your father. ()は省略可能。メンバの呼び出しに見えますが、メソッドの呼び出しです。

father.fuga('nooooo!!') # nooooo!!
father.fuga 'nooooo!!' # nooooo!! ()は省略可能。よく使用されますが、メソッドの右辺などでは分かりづらくなるので避けた方が良いでしょう。



インスタンス化(引数あり)

前述のインスタンス化では引数なしのコンストラクタでしたが、今回は引数を持つコンストラクタでよりオブジェクト感を出していきます。


Java


Father.java

public class Father {

private String name;

public Father(String name) {
this.name = name;
}

public void tellTheTruth() {
System.out.println("I am " + name + "...");
}

}



Ruby


father.rb

class Father

attr_accessor :name

def initialize(name)
@name = name
end

def tell_the_truth
puts "I am #{name}..."
end
end


initializeがいわゆるコンストラクタです。

また、@hogeはインスタンス変数を表します。

Javaではよく、フィールドとかメンバ変数とか呼ばれるものですね。


文字列について


  • 文字列はシングルクォーテーション'で囲みましょう。


    • ダブルクオーテーション"は式展開時に使用します。

    • 文字列はStringクラスのインスタンスです。




attr_accessor / アクセサについて

attr_accessorはアクセサ(いわゆるgetter/setter)を定義するものです。

実際は、以下のコードを記述しているのと同じです。

def name

@name
end

def name=(val)
@name = val
end

Javaの以下と同じです。

public String getName() {

return name;
}

public void setName(String name) {
this.name = name;
}


配列/リスト


Java


Main.java

package com.company;

import java.util.Arrays;
import java.util.List;

public class Main {
public static void main(String[] args) {
List<String> words = Arrays.asList("pen", "pineapple", "apple", "pen");

// java5-7
for (String word : words) {
System.out.println(word);
}
// java8以降
words.forEach(System.out::println);
}
}



Ruby


ppap.rb

words = ['pen', 'pineapple', 'apple', 'pen']

puts words[0] # pen

words.each do |word|
# 以下の処理をループ実行する。
# wordにはループされたオブジェクトが格納されている。
# よって、最初のループは'pen'がコンソールに表示される。
puts word
end


配列はArrayクラスで表現されます。

Array - Rubyリファレンス

配列の繰り返しは#eachがしばしば使用されます。

for文もありますが、まずは#eachを覚えておけば大概のループは大丈夫でしょう。

doからendで表されるブロックについては、以下の記事が非常にわかりやすいです。

[Ruby] ブロックやProcの使いどころを理解する

(混乱する可能性があるので、ストックして後で読む方が良いかもしれません。)

また、文字列の配列は以下の書き方で生成されることも頭の片隅に置いておくと、

他の人が書いたコードを読んでドキドキする可能性が低くなるでしょう。

# 文字列の配列を生成する

words = %w(pen pineapple apple pen)

このあたりは、Rubyで%記法(パーセント記法)を使うが非常に参考になります。

(ストック推奨)


Map/ハッシュ


Java


Main.java

import java.util.HashMap;

import java.util.Map;

public class Main {

public static void main(String[] args) {
Map<String, String> map = new HashMap<>();

map.put("name", "ディップ");
map.put("service", "ナースではたらこ");

System.out.println(map.get("name")); // ディップ
System.out.println(map.get("service")); // ナースではたらこ
}

}



Ruby

Rubyにおけるハッシュはいくつか書き方が用意されています。


main.rb

# 1 文字列をキーとする

dip = {'name' => 'ディップ', 'service' => 'ナースではたらこ'}

puts dip['name'] # ディップ
puts dip['service'] # ナースではたらこ

# 2 シンボルをキーとする。
dip = {name: 'ディップ', service: 'ナースではたらこ'}

puts dip[:name] # ディップ
puts dip[:service] # ナースではたらこ


書き方は上記だけではなく、また、バージョンによってもサポートが異なります。

以下の記事が非常にわかりやすいので目を通すと良いでしょう。

Rubyのhash宣言方法いろいろ


知っておくと役立ったこと


名前空間について(Foo::Bar.newについて)

以下の書き方を見て戸惑うことがあるかもしれません。

Foo::Bar.new

こちらは、実際には以下のクラスをインスタンス化している処理です。

module Foo

class Bar
end
end

moduleの役割の一つに名前空間の提供があります。(他にはメソッドの提供などの機能を持ちます。)

Javaでいうパッケージに近い概念ですね。


Bar.java

package foo;

public class Bar {
}



Fuga.java

package hoge;

import foo.Bar;

public class Fuga {
Bar bar = new Bar();
}


上記と似ています。


NullPointerExceptionではなく、NoMethodErrorが発生する

RubyのnilはJavaでいうnullに似ていますが、多少異なります。


nil は NilClass クラスの唯一のインスタンスです。 nil は false オブジェクトとともに偽を表し、 その他の全てのオブジェクトは真です。

class NilClass (Ruby 2.3.0)


よって、nilクラスに存在しないメソッドを呼び出した際は、

NullPointerExceptionというような例外ではなく、NoMethodErrorという例外が発生します。


main.rb

# 定義していないメソッドを呼び出す。

nil.special_method

# NilClassにはspecial_methodとうメソッドはないので、以下のエラーが出力される。

undefined method `special_method' for nil:NilClass (NoMethodError)


おわりに

Rubyは文法が美しい上、組み込みクラスが便利で、使えば使うほど手に馴染む言語だと個人的に思います。

Javaから入ると「型宣言がないと何か不安!!」みたいになるかもしれませんが、すぐに慣れると思います。(3日で慣れました。)

他言語を始めると元の言語への見方も変わるので、是非始めてみるのはいかがでしょうか。