1. 程式人生 > >《Rails for Java Developers》讀書筆記1

《Rails for Java Developers》讀書筆記1

書名:《Rails for Java Developers》英文版PDF
所處章節:第二章 Programming Ruby
頁數範圍:38~71

Java/Ruby語法特性對比:
Java divides the world into primitive types and objects. The primitive
types represent numeric values of various ranges and precision:
int i;


primitive types can use infix math, for example:
1+1;


To represent arbitrarily large integers, Java uses the BigInteger class:
BigInteger twobil = new BigInteger("2000000000");


BigInteger cannot use infix mathematical notation you have
to say:
a.multiply(b)


Ruby transparently uses
the appropriate type as needed, Notice that x smoothly shifts from Fixnum to Bignum as necessary:
irb(main):004:0> x = 10**9
=> 1000000000
irb(main):005:0> x.class
=> Fixnum
irb(main):006:0> x *= 100
=> 100000000000
irb(main):007:0> x.class
=> Bignum

irb(main):018:0> 1.0.finite?
=> true
irb(main):019:0> (1.0/0.0).finite?
=> false


"?" by convention it is used for methods that return a
boolean

print(String.format("Hello, %s", name.toUpperCase()));

irb(main):005:0> "Hello, #{name.upcase}"
=> "Hello, READER"


In Java, you can use backslash escapes to represent characters:
print(String.format("Hello, \"%s\"\nWelcome to Java", name));

Ruby also uses backslash escapes:
irb(main):008:0> puts "Hello, \"#{name}\"\nWelcome to Ruby"
Hello, "Reader"
Welcome to Ruby


with %Q you can get rid of all these backslash escapes:
irb(main):011:0> puts %Q{"One", "Two", and "Three" are strings"}
"One", "Two", and "Three" are strings"


assertEquals('H', "Hello".charAt(0));

irb(main):015:0> ?A
=> 65
irb(main):019:0> ?H == "Hello".slice(0)
=> true
irb(main):022:0> ?o == "Hello"[-1]
=> true
irb(main):025:0> "Hello"[1,4]
=> "ello"


To turn off string interpolation,use a single-quoted string instead of a double-quoted one:
irb(main):028:0> "Hello, #{name.upcase}"
=> "Hello, READER"
irb(main):029:0> 'Hello, #{name.upcase}'
=> "Hello, \#{name.upcase}"


Java:
print("one\ntwo\nthree");

Ruby provides an explicit syntax for multiline strings called a here
document, or heredoc.
irb(main):035:0> puts <<MY_DELIMITER
irb(main):036:0" one
irb(main):037:0" two
irb(main):038:0" three
irb(main):039:0" MY_DELIMITER
one
two
three



Java:
public static String bleep(String input) {
return input.replaceAll("\\b\\w{4}\\b", "(bleep)");
}

Ruby use regular expressions, delimiting them with //:
irb(main):041:0> 'Are four letter words mean?'.gsub(/\b\w{4}\b/, "(bleep)")
=> "Are (bleep) letter words (bleep)?"


print("HELLO".toLowerCase());

irb(main):047:0> "HELLO".downcase()
=> "hello"
irb(main):048:0> "HELLO".downcase
=> "hello"


print(Math.cos(0));

irb(main):051:0> Math.cos(0)
=> 1.0
irb(main):051:0> Math.cos 0
=> 1.0


In Java, objects are type-safe. Objects know what they are capable of, type-safe and you cannot ask them to perform methods they do not have:
print("hello".cos(0));

Ruby objects are also type-safe:
irb(main):057:0> "hello".cos 0
NoMethodError: undefined method ‘cos' for "hello":String
from (irb):57


Type Safety Does Not Ensure Correctness!!!

public class PrintArgs {
public static void main(String[] args) {
for (int n=0; n<args.length; n++) {
System.out.println(args[n]);
}
}
}

ARGV.each {|x| puts x}
or
ARGV.each do |x|
puts x
end

$ ruby samples/print_args.rb one two three
one
two
three

irb(main):009:0> ['C', 'Java', 'Ruby'].each {|lang| puts "#{lang} is fun!"}
C is fun!
Java is fun!
Ruby is fun!
=> ["C", "Java", "Ruby"]

irb(main):002:0> ['C', 'Java', 'Ruby'] == %w{C Java Ruby}
=> true

irb(main):002:0> [1,2] + [3]
=> [1, 2, 3]
irb(main):003:0> [1,2,3] * 2
=> [1, 2, 3, 1, 2, 3]
irb(main):004:0> [1,2,1] - [2]
=> [1, 1]
irb(main):005:0> [1,2] / 2
NoMethodError: undefined method ‘/' for [1, 2]:Array
from (irb):5

irb(main):006:0> skills = ['C', 'Java']
=> ["C", "Java"]
irb(main):007:0> skills.push 'Ruby'
=> ["C", "Java", "Ruby"]
irb(main):008:0> skills.pop
=> "Ruby"


import java.util.*;
public class PrintEnv {
public static void main(String[] args) {
Map map = System.getenv();
for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
Map.Entry e = (Map.Entry) it.next();
System.out.println(String.format("%s: %s", e.getKey(), e.getValue()));
}
}
}

ENV.each {|k,v| puts "#{k}: #{v}"}

irb(main):037:0> dict = {:do => "a deer", :re => "a drop of golden sun"}
=> {:do=>"a deer", :re=>"a drop of golden sun"}

irb(main):013:0> dict.fetch(:do)
=> "a deer"
irb(main):014:0> dict.store(:so, "a needle pulling thread")
=> "a needle pulling thread"

irb(main):015:0> dict[:so]
=> "a needle pulling thread"
irb(main):016:0> dict[:dos] = "a beer"
=> "a beer"


import java.util.Map;
public class ForEach {
public static void main(String[] args) {
for (String arg: args) {
System.out.println(arg);
}
for (Map.Entry entry: System.getenv().entrySet()) {
System.out.println(
String.format("%s : %s", entry.getKey(), entry.getValue()));
}
}
}

irb(main):017:0> [1,2,3,4,5].collect {|x| x**2}
=> [1, 4, 9, 16, 25]

irb(main):021:0> [1,2,3,4,5].find_all {|x| x%2==0}
=> [2, 4]


We want to make two important points from these examples:
• Languages evolve and improve over time. Usually improvement
comes not from thin air but from ideas that have already been
explored elsewhere. Java’s For-Each syntax was inspired by other
languages that have similar features. The programmers who facilitate
this kind of cross-pollination are those who become fluent in
multiple programming languages.
• Languages evolve at many levels. Runtimes can change, language
syntax can change, and libraries can change. In Java, iteration
changes like the addition of For-Each are language changes. Similar
changes in Ruby are library changes, since each et. al. are
method calls. Library changes are easier to make than language
changes. (Many developers write libraries, few developers write
languages, and language evolution tends to be retarded by standards
bodies, backward compatibility, and so on.) Merely pointing
out that Java and Ruby enable different approaches to change is
not a value judgment. However, it may lead to value judgments
in a specific context (which you must provide). What parts of your
system need to change? On what timeline, and under whose direction?
Conversely, what parts need to stay rock-solid stable and be
guaranteed to work in the same fashion across different projects
over time?

if (n > 5) {
print("big");
} else {
print("little");
}

if n>5
puts "big"
else
puts "little"
end

or

puts(if (n>5)
"big"
else
"little"
end)


if (o != null) {
print("got o");
}

o = nil
puts o ? true : false

if lines > 1; puts "you have more than one line"; end

puts "you have more than one line" if lines > 1

puts "you've got lines" if lines != 0
puts "you've got lines" unless lines == 0

The following program runs an input loop, shouting back everything passed via stdin:
line = ""
puts "Shouting back #{line.upcase}" while line=gets


The ugliness here comes from using the boolean operator || to shoehorn
two statements into one to conform to the requirements of the statement
modifier form.
irb(main):026:0> i=1; puts(i*i) || i+=1 while i<=5
1
4
9
16
25

(1..5).each {|x| puts x*x}

irb(main):014:0> (1..10).max
=> 10
irb(main):015:0> (1...10).max
=> 9
irb(main):016:0> (1..10).exclude_end?
=> false
irb(main):017:0> (1...10).exclude_end?
=> true

("A".."C").each {|x| puts x*5}
AAAAA
BBBBB
CCCCC

irb(main):003:0> ('A'..'I').step(2) {|x| print x}
ACEGI


public static int numberGrade(char letter) {
switch(letter) {
case 'a':
return 100;
case 'b':
return 90;
case 'c':
return 80;
case 'd':
return 70;
case 'e':
case 'f':
return 0;
}
return 0;
}

def number_grade(letter)
case letter
when 'A': 100
when 'B': 90
when 'C': 80
when 'D': 70
else 0
end
end

def letter_grade(x)
case x
when 90..100: 'A'
when 80..90: 'B'
when 70..80: 'C'
when 60..70: 'D'
when Integer: 'F'
when /[A-F]/: x
else raise "not a grade: #{x}"
end
end

irb(main):018:0> case('John')
irb(main):019:1> when('John'): 'a name'
irb(main):020:1> when(String): 'a word'
irb(main):021:1> end
=> "a name"

You can also invoke the case equality operator directly; it is written as
a triple equals (===):
irb(main):002:0> (90..100) === 95
=> true
irb(main):003:0> (90..100) === 95.5
=> true
irb(main):004:0> (90..100) === 0
=> false
irb(main):005:0> Integer === 95
=> true
irb(main):006:0> Integer === 95.5
=> false


public class Person {
private String firstName;
private String lastName;

class Person

That’s it. There is no need to declare instance variables (the Ruby equivalent
of fields) because they come into existence automatically when
they are used.Ruby instance variables are
implicitly private, so this designation is unneeded as well.

Defining Constructors
In Java, Notice that the constructor
arguments share the same names as the private fields: firstName and
lastName. To disambiguate, you explicitly prefix the instance variables
with this.
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

In Ruby, instance
variables must begin with a @, so there is no danger of a name collision
with method parameters.
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end


public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFullName() {
return String.format("%s %s", firstName, lastName);
}

attr_accessor :first_name, :last_name
def full_name
"#{first_name} #{last_name}"
end

Ruby also provides attr_reader and attr_writer if you want read-only
or write-only properties.

p.first_name = 'Justin'
p.last_name = 'Gehtland'
puts "Hello from #{p.first_name}"


To a Java eye, this looks like direct access to the fields first_name and
last_name, but in Ruby these are method calls. Even the punctuation (=)
is part of a method name. To make this clearer, here is a hand-coded
version of the accessors:
# don't do this--use attr_accessor!
def first_name
@first_name
end
def first_name=(new_name)
@first_name = new_name
end


public void marry(Person other) {
String newLastName =
String.format("%s-%s", getLastName(), other.getLastName());
setLastName(newLastName);
other.setLastName(newLastName);
}

def marry(other)
other.last_name = self.last_name = "#{self.last_name}-#{other.last_name}"
end

If you forget to prefix a setter with self, you may create hard-to-find
bugs. Java does not suffer from this ambiguity, so be careful.


Sometimes methods apply to a class as a whole, instead of to any particular
instance of a class. In Java these are called static methods:
public static String getSpecies() {
return "Homo sapiens";
}

In Ruby, these methods are called class methods:
def self.species
"Homo sapiens"
end


public class Person {
private String firstName;
private String lastName;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFullName() {
return String.format("%s %s", firstName, lastName);
}
public void marry(Person other) {
String newLastName =
String.format("%s-%s", getLastName(), other.getLastName());
setLastName(newLastName);
other.setLastName(newLastName);
}
public static String getSpecies() {
return "Homo sapiens";
}
}

class Person
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
attr_accessor :first_name, :last_name
def full_name
"#{first_name} #{last_name}"
end
def marry(other)
other.last_name = self.last_name = "#{self.last_name}-#{other.last_name}"
end
def self.species
"Homo sapiens"
end
end



The == operator tests for identity. Strings s1 and s2 are == because they
point to the same object. Strings3 is not== to the others. It contains the
same characters, but it is at a different location in memory.
The equals method tests equality, which Java strings define to mean
“containing the same characters.” Thus, string s3.equals the others.
public void testEquals() {
String s1 = "Java rocks!";
String s2 = s1;
String s3 = new String("Java rocks!");
assertTrue(s1 == s2);
assertFalse(s1 == s3);
assertTrue(s1.equals(s3));
}

Ruby also distinguishes between identity and equality. Each unique
object has an object_id. Two objects are identical if they have the same
object_id, and the equal? method tests for this:
irb(main):001:0> s1 = s2 = "Ruby rocks!"
=> "Ruby rocks!"
irb(main):002:0> s1.object_id
=> 190400
irb(main):003:0> s2.object_id
=> 190400
irb(main):004:0> s2.equal? s1
=> true

irb(main):006:0> s3 = "Ruby rocks!"
=> "Ruby rocks!"
irb(main):007:0> s4 = "Ruby rocks!"
=> "Ruby rocks!"
irb(main):008:0> s3==s4
=> true
irb(main):009:0> s3.eql? s4
=> true
irb(main):010:0> s3.equal? s4
=> false

Java’s == tests for identity, while Ruby’s ==
usually tests for equality



import java.util.*;
public class AccessMe {
private String name;
private List stuff;
public AccessMe(String name) {
this.name = name;
stuff = new ArrayList();
}
public String getName() {
return name;
}
protected List getStuff() {
return stuff;
}
private void clear() {
name = null;
stuff = null;
}
}

Ruby does not have any equivalent for package private but supports
public, protected, and private:
class AccessMe
def initialize(name)
@name = name
@stuff = []
end
attr_accessor :name
protected
attr_accessor :stuff
private
def clear
@name = @stuff = nil
end
end


Although access control specifiers set a general rule for how you can
use a class, the general rule may need to bend in some circumstances.
For example, an object serializer may bypass protection modifiers to
access all of an object’s state. In Ruby, you can bypass access control
specifiers with send:
a = AccessMe.new("test")
a.send :stuff=, 'some stuff'
puts a.send(:stuff)


You can invoke
the access control methods more than once for the same symbol. At first
glance this may seem silly—why would a class want to have different
levels of access control at different times? One possibility is temporarily
setting methods public so that unit tests can test them:
def test_clear
AccessMe.send :public, :clear, :stuff
a = AccessMe.new("test")
a.clear
assert_nil a.stuff
end

This sample uses only techniques we have covered thus far. You can
use cleaner ways to set methods public for the duration of a test. One
approach is to use the extend method, described in Section 3.8, Mixins,
on page 90.

try {
methodThatOpensFile();
} catch (FileNotFoundException fnfe) {
System.out.println("File not found " + fnfe);
} catch (Exception e) {
System.out.println("Caught " + e);
}

begin
File.read 'nonexistent'
rescue SystemCallError => e
puts 'system call failed'
rescue Exception => e
puts 'generic failure of some kind'
else
puts 'nothing failed'
ensure
puts 'this always executes'
end

begin
1/0
rescue Exception => e
puts "Message " + e.message
puts "Backtrace " + e.backtrace.join("\n")
end

相關推薦

Rails for Java Developers讀書筆記1

書名:《Rails for Java Developers》英文版PDF 所處章節:第二章 Programming Ruby 頁數範圍:38~71Java/Ruby語法特性對比:Java divides the world into primitive types and o

《effective java讀書筆記1(建立和銷燬物件)

第1條:考慮用靜態工廠方法代替構造器 1.what is? 此處的靜態工廠方法與設計模式中的工廠模式不一樣。 比如類 class Person{ //A的構造器 public A(){}; //A的靜態工廠方法可以

深入理解Java虛擬機器讀書筆記1----Java記憶體區域與HotSpot虛擬機器物件

一 Java記憶體區域與HotSpot虛擬機器物件 1 Java技術體系、JDK、JRE?     Java技術體系包括:         · Java程式設計語言;   

深入理解Java虛擬機器讀書筆記(1):記憶體管理重要概念

深入理解Java虛擬機器讀書筆記(1):記憶體管理重要概念 說到Java記憶體管理,不得不先貼一張非常經典的圖,如下所示: 這些模組有些是執行緒私有的,有的則是執行緒共享的。下面一一對這些模組進行介紹: 一、程式計數器 程式計數器一塊比較小的記憶體空間,可以看做當前

深入理解Java虛擬機器讀書筆記-1

Java 虛擬機器記憶體結構 JVM 在執行過程中會把記憶體劃分為多個不同的資料區域,有的區域是所有執行緒共享的,如方法區和堆,還有的區域是執行緒隔離的,例如虛擬機器棧、本地方法棧和程式計數器。 1、程式計數器(Progress Counter Regist

【JavaEE】經典JAVA EE企業應用實戰-讀書筆記1

今天開始閱讀李剛的書《經典JAVA EE企業應用實戰 基於WebLogic JBoss的JSF+EJB3+JPA整合開發》這本書, 並記錄下讀書筆記,以方便以後參考。 Java EE應用大致可分為如下幾層: 1,Domain Object(領域物件)層:此層由系列的POJ

《深入理解java虛擬機器》讀書筆記1(走近java)

1)Java技術體系 java程式語言設計 各種硬體平臺上的java虛擬機器 class檔案格式 java api類庫 第三方java類庫 2)jdk和jre jdk:用於支援java開發的最小環境,包含java程式語言設計,java虛擬機器,

Effective Java讀書筆記1-考慮使用靜態工廠代替構造器

靜態工廠方法(Static factory method)的優點: 1.靜態工廠方法有名稱 在需要多個建構函式且建構函式的引數型別完全一樣時,可以使用靜態工廠方法。而且可以選擇靜態工廠的名稱以突出他們之間的區別 2.不必在每次呼叫他們的時候建立一個新的類 這使得使用靜

Ajax與Comet-JavaScript高級程序設計第21章讀書筆記(1)

set activex .html 規範 sta php 協議 num 刷新 Ajax(Asynchronous Javascript + XML)技術的核心是XMLHttpRequest對象,即: XHR。雖然名字中包含XML,但它所指的僅僅是這種無須刷新頁面即可從服務器

Java Web學習筆記-1

根路徑 text .get set 接口 context cat 方法 web應用 1.servlet理論上可以處理多種形式的請求響應形式 ,http只是其中之一 ,所以HttpServletRequest、 HttpServletResponse分別是ServletReq

Windows核心編程讀書筆記1

函數 create bre 這一 分配 例子 sys 常量 http 今天特別困啊,這是為什麽?!!剛剛把第一章看了一下,困到不行,所以寫blog清醒一下。 第一章標題是“錯誤處理”,看了之後嚇了一跳,難道第一章就講這麽高大上的東西?!不是不是,我現在的理解是,這章主要還是

《互聯網企業安全高級指南》讀書筆記1-5

讀書筆記 管理 .cn 1-1 bsp 團隊管理 而是 互聯網 業務 這本書一上市就買了,但一直沒有系統的總結下其中的知識點。 最近抽時間仔細讀並總結下。 非常認可書評裏微步在線CEO薛鋒的點評:   互聯網安全從業者最大的挑戰並非技術,而是如何建立正確的行業格局觀,並且能

drupal8 模塊開發 讀書筆記 1

影響 反轉 form module uil 例如 hide mac 模塊開發 這個依賴註入有個管理的東西,假設是InjectionManager然後框架,比如說是Framework 現在Framework 想要 實例化一個controller它就問InjectionMana

《黑客攻防技術寶典Web實戰篇@第2版》讀書筆記1:了解Web應用程序

金融 主機 border ket 邊界 輕量 在線 讀書 目的 讀書筆記第一部分對應原書的第一章,主要介紹了Web應用程序的發展,功能,安全狀況。 Web應用程序的發展歷程 早期的萬維網僅由Web站點構成,只是包含靜態文檔的信息庫,隨後人們發明了Web瀏覽器用來檢索和

《Effective Java讀書筆記 - 最小化類的可變性

有效 down private 讀書筆記 工廠 public 限定 如果 構造器 Item 15 最小化類的可變性 effective java 如何做到讓類不可變? 不提供改變對象狀態的方法。(mutators) 確保類不會被繼承,即用final來限定類。 讓所有的

假期讀書筆記1

工程 最終 如何 編碼習慣 模型 軟件需求 包括 程序 養成 要學習軟件工程,學會如何系統的思考,以及養成良好的編碼習慣,想學好軟件工程,就必須知道軟件工程的目標、過程和原則: 軟件工程目標:生產具有正確性、可用性以及開銷合宜的產品。正確性指軟件產品達到預期功能的程度。可

讀書筆記——1.2.16

開發 想是 如果 專業 意義 說明 一起 關於 AD   首先是第一章,書中例舉出了從小孩玩的紙飛機,到“飛屋”,到萊特兄弟的飛機最後到我們看到的飛機。我想到的是,有的人從興趣出發,覺得某些項目也好,工程也好,需要去實現。有的人放棄了,止步於紙飛機,有的人堅持了,做出了航模

Java源碼筆記(1) java.lang.Object 之 native分析

ons 一個 head pri demo def shared 筆記 log 包路徑:java.lang.*: java.lang.Object:   一、Object類是java類樹的根,所有類的超類。   二、方法及成員:    private static nat

Java編程思想》(Thinking in Java讀書筆記——01對象導論

動態 執行 線程 情況 依賴關系 AI UC 技巧 復制 1.9 容器 關於容器,最常用的就是Collection接口裏的Set、List和Map所衍生的各種實現類,還有較為少用但又不可或缺的Queue。 它們都有相同的點,即:提供了類似數組類型的數據聚合功能(有部分類型也

《進化:運維技術變革與實踐探索》讀書筆記1 —— 以應用為核心

應用 運維 規範 服務 第一章介紹的是運維的本質,開頭以Netflix 公司(業界微服務架構的最佳實踐者)為例,介紹了在其內部"運維工程師"的角色。在Netflix 內部沒有運維工程師這一角色,取而代之的是SRE(site Reliability Engineer)