2013年12月30日 星期一

[ In Action ] The Simple Groovy datatypes - Objects, objects everywhere

Preface: 
Groovy supports a limited set of datatypes at the language level; that is, it offers means for literal declaration and specialized operators. This set contains the simple datatypes for strings, regular expressions, and numbers, as well as the collective datatypes for ranges, lists, and maps. This chapter covers the simple datatypes; the next chapter introduces the collective datatypes. 

In Groovy, everything is an object. In order to explain the choices made by Groovy’s designers, we’ll first go over some basics of Java’s type system. We will then explain how Groovy addresses the difficulties presented, and finally examine how Groovy and Java can still interoperate with ease due to automatic boxing/unboxing. 

Java’s type system—primitives and references: 
Java distinguishes between primitive types (such as int , double , char , and byte) and reference types (such as Object and String). There is a fixed set of primitivetypes, and these are the only types that have value semantics—where the value of a variable of that type is the actual number (or character, or true/false value). You cannot create your own value types in Java. 

Reference types (everything apart from primitives) have reference semantics—the value of a variable of that type is only a reference to an object. Readers with a C/C++background may wish to think of a reference as a pointer—it’s a similar concept. If you change the value of a reference type variable, that has no effect on the object it was previously referring to—you’re just making the variable refer to a different object, or to no object at all. 

You cannot call methods on values of primitive types, and you cannot use them where Java expects objects of type java.lang.Object. This is particularly painful when working with collections that cannot handle primitive types, such as java.util.ArrayList. To get around this, Java has a wrapper type for each primitive type—a reference type that stores a value of the primitive type in an object. For example, the wrapper for int is java.lang.Integer

On the other hand, operators such as * in 3*2 or a*b are not supported for arbitrary reference types, but only for primitive types (with the exception of + , which is also supported for strings). As an example of why this causes pain, let’s consider a situation where you have two lists of integers, and you want to come up with a third list where the first element is the sum of the first elements of the other two lists, and so on. The Java code would be something like this: 
  1. // Java code!  
  2. ArrayList results = new ArrayList();  
  3. for (int i=0; i < listOne.size(); i++)  
  4. {  
  5.     Integer first  = (Integer)listOne.get(i);  
  6.     Integer second = (Integer)listTwo.get(i);  
  7.               
  8.     int sum = first.intValue()+second.intValue();  
  9.     results.add (new Integer(sum));  
  10. }  
Groovy’s answer—everything’s an object: 
Looking at the code block in the previous section, you can see that the problem is in the last two lines of the loop. To add the numbers, you must convert them fromInteger into int s. In order to then store the result in another list, you have to create a new Integer . Groovy adds the plus method to java.lang.Integer , letting you write this instead: 
  1. results.add (first.plus(second))  
So far, there’s nothing that couldn’t have been done in Java if the library designers had thought to include a plus method. However, Groovy allows operators to work on objects, enabling the replacement of the last section of the loop body: 
  1. // Java  
  2. int sum = first.intValue()+second.intValue();  
  3. results.add (new Integer(sum));  
with the more readable Groovy solution: 
  1. results.add (first + second)  
You’ll learn more about what operators are available and how you can specify your own implementations later. 

In order to make Groovy fully object-oriented, and because at the JVM level Java does not support object-oriented operations such as method calls on primitive types, the Groovy designers decided to do away with primitive types. When Groovy needs to store values that would have used Java’s primitive types, Groovy uses the wrapper classes already provided by the Java platform. Table 3.1 provides a complete list of these wrappers. 
 

While we have the Java primitives under the microscope, so to speak, it’s worth examining the numeric literal formats that Java and Groovy each use. They are slightly different because Groovy allows instances of java.math.BigDecimal and java.math.BigInteger to be specified using literals in addition to the usual binary floating-point types. Table 3.2 gives examples of each of the literal formats available for numeric types in Groovy. 
 

Interoperating with Java—automatic boxing and unboxing 
Converting a primitive value into an instance of a wrapper type is called boxing in Java and other languages that support the same notion. The reverse action—taking an instance of a wrapper and retrieving the primitive value—is called unboxing. This automatic boxing and unboxing is known as autoboxing

You’ve already seen that Groovy is designed to work well with Java, so what happens when a Java method takes primitive parameters or returns a primitive return type? How can you call that method from Groovy? Consider the existing method in the java.lang.String class: int indexOf(int ch) . You can call this method from Groovy like this: 
  1. assert 'ABCDE'.indexOf(67) == 2  
From Groovy’s point of view, we’re passing an Integer containing the value 67 (the Unicode value for the letter C), even though the method expects a parameter of primitive type int . Groovy takes care of the unboxing. The method returns a primitive type int that is boxed into an Integer as soon as it enters the world of Groovy. That way, we can compare it to the Integer with value 2 back in the Groovy script. Figure 3.1 shows the process of going from the Groovy world to the Java world and back. 
 

No intermediate unboxing: 
If in 1+1 both numbers are objects of type Integer , are those Integers unboxed to execute the plus operation on primitive types? No. Groovy is more object-oriented than Java. It executes this expression as 1.plus(1) , calling the plus() method of the first Integer object, and passing the second Integer object as an argument. The method call returns a new Integer object of value 2 . 

This is a powerful model. Calling methods on objects is what object-oriented languages should do. It opens the door for applying the full range of object-oriented capabilities to those operators. Let’s summarize. No matter how literals (numbers, strings, and so forth) appear in Groovy code, they are always objects. Only at the border to Java are they boxed and unboxed. Operators are a shorthand for method calls. Now that you have seen how Groovy handles types when you tell it what to expect, let’s examine what it does when you don’t give it any type information.

[ In Action ] The Simple Groovy datatypes - Working with numbers

Preface: 
The available numeric types and their declarations in Groovy were introduced in section 3.1. You have seen that for decimal numbers, the default type isjava.math.BigDecimal . This is a feature to get around the most common misconceptions about floating-point arithmetic. We’re going to look at which type is used where and what extra abilities have been provided for numbers in the GDK. 

Coercion with numeric operators: 
It is always important to understand what happens when you use one of the numeric operators. Most of the rules for the addition, multiplication, and subtraction operators are the same as in Java, but there are some changes regarding floating-point behavior, and BigInteger and java.math.BigDecimal also need to be included. The rules are straightforward. The first rule to match the situation is used. 

For the operations + , - , and * : 
* If either operand is a Float or a Double , the result is a Double.
* Otherwise, if either operand is a java.math.BigDecimal , the result is a java.math.BigDecimal
* Otherwise, if either operand is a BigInteger , the result is a BigInteger.
* Otherwise, if either operand is a Long , the result is a Long.
* Otherwise, the result is an Integer.

Table 3.9 depicts the scheme for quick lookup. Types are abbreviated by uppercase letters. 
 

Rules can be daunting without examples, so this behavior is demonstrated in table 3.10. 
 

In Java, results like in the fourth row are often surprising—for example, (1/2) is always zero because when both operands of division are integers, only integer division is performed. To get 0.5 in Java, you need to write (1f/2)

GDK methods for numbers: 
The GDK defines all applicable methods from table 3.4 to implement overridable operators for numbers such as plus , minus , power , and so forth. They all work without surprises. In addition, the abstoInteger , and round methods do what you’d expect. 

More interestingly, the GDK also defines the methods times , uptodownto , and step. They all take a closure argument. Listing 3.9 shows these methods in action: timesis just for repetition, upto is for walking a sequence of increasing numbers, downto is for decreasing numbers, and step is the general version that walks until the end value by successively adding a step width. 
- Listing 3.9 GDK methods on numbers 
  1. def store = ''  
  2. 10.times{       
  3.     store += 'x'  
  4. }  
  5. assert store == 'xxxxxxxxxx'  
  6.   
  7. store = ''  
  8. 1.upto(5) { number ->     
  9.     store += number  
  10. }  
  11. assert store == '12345'  
  12.   
  13. store = ''  
  14. 2.downto(-2) { number ->  
  15.     store += number + ' '  
  16. }  
  17. assert store == '2 1 0 -1 -2 '  
  18.   
  19. store = ''  
  20. 0.step(0.50.1 ){ number ->  
  21.     store += number + ' '  
  22. }  
  23.   
  24. assert store == '0 0.1 0.2 0.3 0.4 '  
Calling methods on numbers can feel unfamiliar at first when you come from Java. Just remember that numbers are objects and you can treat them as such. You have seen that in Groovy, numbers work the natural way and even guard you against the most common errors with floating-point arithmetic. In most cases, there is no need to remember all details of coercion. When the need arises, this section may serve as a reference.

[ In Action ] The Simple Groovy datatypes - Working with strings

Preface:
Groovy strings come in two flavors: plain strings and GStrings. Plain strings are instances of java.lang.String , and GStrings are instances of groovy.lang.GString .GStrings allow placeholder expressions to be resolved and evaluated at runtime. Many scripting languages have a similar feature, usually called string interpolation, but it’s more primitive than the GString feature of Groovy. Let’s start by looking at each flavor of string and how they appear in code.

Varieties of string literals:
Java allows only one way of specifying string literals: placing text in quotes “like this.” If you want to embed dynamic values within the string, you have to either call a formatting method (made easier but still far from simple in Java 1.5) or concatenate each constituent part. If you specify a string with a lot of backslashes in it (such as a Windows file name or a regular expression), your code becomes hard to read, because you have to double the backslashes. If you want a lot of text spanning several lines in the source code, you have to make each line contain a complete string (or several complete strings).

Groovy recognizes that not every use of string literals is the same, so it offers a variety of options. These are summarized in table 3.5.



The aim of each form is to specify the text data you want with the minimum of fuss. Each of the forms has a single feature that distinguishes it from the others:
- The single-quoted form
The single-quoted form is never treated as a GString, whatever its contents. This is closely equivalent to Java string literals.

- The double-quoted form
The double-quoted form is the equivalent of the single-quoted form, except that if the text contains unescaped dollar signs, it is treated as a GString instead of a plain string. GStrings are covered in more detail in the next section.

- The triple-quoted form 
The triple-quoted form (or multiline string literal) allows the literal to span several lines. New lines are always treated as '\n' regardless of the platform, but all other whitespace is preserved as it appears in the text file. Multiline string literals may also be GStrings, depending on whether single quotes or double quotes are used. Multiline string literals act similar to HERE -documents in Ruby or Perl.

- The slashy form 
The slashy form of string literal allows strings with backslashes to be specified simply without having to escape all the backslashes. This is particularly useful with regular expressions, as you’ll see later. Only when a backslash is followed by a u does it need to be escaped —at which point life is slightly harder, because specifying \u involves using a GString or specifying the Unicode escape sequence for a backslash.

Groovy uses a similar mechanism for specifying special characters, such as linefeeds and tabs. In addition to the Java escapes, dollar signs can be escaped in Groovy to allow them to be easily specified without the compiler treating the literal as a GString. The full set of escaped characters is specified in table 3.6.


Note that in a double-quoted string, single quotes don’t need to be escaped, and vice versa. In other words, 'I said, "Hi."' and "don't" both do what you hope they will. For the sake of consistency, both still can be escaped in each case. Likewise, dollar signs can be escaped in single-quoted strings, even though they don’t need to be. This makes it easier to switch between the forms.

Note that Java uses single quotes for character literals, but as you have seen, Groovy cannot do so because single quotes are already used to specify strings. However, you can achieve the same as in Java when providing the type explicitly:
  1. char      a = 'x'  // or Character a = 'x'  
The java.lang.String 'x' is coerced into a java.lang.Character . If you want to coerce a string into a character at other times, you can do so in either of the following ways:
  1. 'x' as char    
  2. 'x'.toCharacter()   
Whichever literal form is used, unless the compiler decides it is a GString, it ends up as an instance of java.lang.String , just like Java string literals. So far, we have only teased you with allusions to what GStrings are capable of. Now it’s time to spill the beans.

Working with GStrings:
GStrings are like strings with additional capabilities. They are literally declared in double quotes. What makes a double-quoted string literal a GString is the appearance of placeholders. Placeholders may appear in a full ${expression} syntax or an abbreviated $reference syntax. See the examples in listing 3.2.
- Listing 3.2 Working with GStrings
  1. me      = 'Tarzan'                         
  2. you     = 'Jane'                           
  3. line    = "me $me - you $you"    // Abbreviated dollar syntax          
  4. assert  line == 'me Tarzan - you Jane'     
  5. date = new Date(0)                                            
  6. out  = "Year $date.year Month $date.month Day $date.date"  // Extended abbreviation  
  7. assert out == 'Year 70 Month 0 Day 1'                         
  8. out = "Date is ${date.toGMTString()} !"  // Full syntax with curly braces              
  9. assert out == 'Date is 1 Jan 1970 00:00:00 GMT !'  
  10.   
  11. // Multiple-line GString  
  12. sql = """  
  13. SELECT FROM MyTable   
  14.        WHERE Year = $date.year  
  15. """            
  16.                  
  17. assert sql == """  
  18. SELECT FROM MyTable   
  19.        WHERE Year = 70  
  20. """  
  21.   
  22. // Literal dollar sign  
  23. out = "my 0.02\$"  
  24. assert out == 'my 0.02$'  
Although GStrings behave like java.lang.String objects for all operations that a programmer is usually concerned with, they are implemented differently to capture the fixed and the dynamic parts (the so-called values) separately. This is revealed by the following code:
  1. me      = 'Tarzan'  
  2. you     = 'Jane'  
  3. line    = "me $me - you $you"  
  4. assert line == 'me Tarzan - you Jane'  
  5. assert line instanceof GString  
  6. assert line.strings[0] == 'me '  
  7. assert line.strings[1] == ' - you '  
  8. assert line.values[0]  == 'Tarzan'  
  9. assert line.values[1]  == 'Jane'  
By the time the GString is converted into a java.lang.String (its toString method is called explicitly or implicitly), each value gets written to the string. Because the logic of how to write a value can be elaborate for certain value types, this behavior can be used in advanced ways.

From Java to Groovy:
Now that you have your strings easily declared, you can have some fun with them. Because they are objects of type java.lang.String , you can call String ’s methods on them or pass them as parameters wherever a string is expected, such as for easy console output:
  1. System.out.print("Hello Groovy!");  
This line is equally valid Java and Groovy. You can also pass a literal Groovy string in single quotes:
  1. System.out.print('Hello Groovy!');  
Because this is such a common task, the GDK provides a shortened syntax:
  1. print('Hello Groovy!');  
You can drop parentheses and semicolons, because they are optional and do not help readability in this case. The resulting Groovy style boils down to:
  1. print 'Hello Groovy!'  
Looking at this last line only, you cannot tell whether this is Groovy, Ruby, Perl, or one of several other line-oriented scripting languages. It may not look sophisticated, but in a way it is. It shows expressiveness—the art of revealing intent in the simplest possible way.

Listing 3.3 presents more of the mix-and-match between core Java and additional GDK capabilities. How would you judge the expressiveness of each line?
- Listing 3.3 What to do with strings
  1. greeting = 'Hello Groovy!'  
  2. assert greeting.startsWith('Hello')  
  3. assert greeting.getAt(0) == 'H'  
  4. assert greeting[0]       == 'H'  
  5. assert greeting.indexOf('Groovy') >= 0  
  6. assert greeting.contains('Groovy')  
  7. assert greeting[6..11]  == 'Groovy'  
  8. assert 'Hi' + greeting - 'Hello' + '?' - '!' == 'Hi Groovy?'   
  9. assert greeting.count('o') == 3  
  10. assert 'x'.padLeft(3)      == '  x'  
  11. assert 'x'.padRight(3,'_') == 'x__'  
  12. assert 'x'.center(3)       == ' x '  
  13. assert 'x' * 3             == 'xxx'  
These self-explanatory examples give an impression of what is possible with strings in Groovy. If you have ever worked with other scripting languages, you may notice that a useful piece of functionality is missing from listing 3.3: changing a string in place. Groovy cannot do so because it works on instances of java.lang.String and obeys Java’s invariant of strings being immutable.

Before you say “What a lame excuse!” here is Groovy’s answer to changing strings: Although you cannot work on String , you can still work on StringBuffer! On aStringBuffer, you can work with the << left shift operator for appending and the subscript operator for in-place assignments. Using the left shift operator on Stringreturns a StringBuffer. Here is the StringBuffer equivalent to listing 3.3:
  1. greeting = 'Hello'  
  2. assert greeting instanceof java.lang.String  
  3. greeting <<= ' Groovy'  // 1) Leftshift and assign at once  
  4. assert greeting instanceof java.lang.StringBuffer  
  5. greeting << '!'  // 2) Leftshift on StringBuffer  
  6. assert greeting.toString() == 'Hello Groovy!'  
  7. greeting[1..4] = 'i'  // Substring ‘ello’ becomes ‘i’  
  8. assert greeting.toString() == 'Hi Groovy!'  
Ps.
Although the expression stringRef << string returns a StringBuffer , that StringBuffer is not automatically assigned to the stringRef (see (1)). When used on a String, it needs explicit assignment; on StringBuffer it doesn’t. With a StringBuffer, the data in the existing object changed (see (2))—with a String we can’t change the existing data, so we have to return a new object instead.


[ Python 常見問題 ] How to shift a datetime object by 12 hours in python

Source From   Here   Question   Datetime   objects hurt my head for some reason. I am writing to figure out   how to shift a date time obje...