一般情况下当我们访问或修改不存在的属性、调用不存在的方法会抛出异常,而在Groovy中则可以通过实现相应的Hook Method钩子方法以避免异常发生

属性缺失
Groovy在MP元编程方面提供了丰富的特性,其中之一就是在访问、修改不存在的属性时,提供了一个钩子方法。下面即是一个简单的Groovy示例,当我们访问、修改Tiger类不存在的属性,即会抛出相应的异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
   | class MissPropertyDemo {
      static void testTiger() {         Tiger tiger = new Tiger(name: "Tony", type: "TIGER")
          assert tiger.name == "Tony"         assert tiger.type == "TIGER"
          try {                          def age = tiger.age         } catch (Exception e) {             assert e instanceof MissingPropertyException             println("Happen Missing Property Exception #1")         }
          try {                          tiger.age = 234         } catch (Exception e) {             assert e instanceof MissingPropertyException             println("Happen Missing Property Exception #2")         }
          try {                          def remark = Tiger.remark         } catch (Exception e) {             assert e instanceof MissingPropertyException             println("Happen Missing Property Exception #3")         }
          try {                          Tiger.remark = 234         } catch (Exception e) {             assert e instanceof MissingPropertyException             println("Happen Missing Property Exception #4")         }     }
  }
  class Tiger{     String name     String type }
  | 
 
测试结果如下所示

而由于Groovy为属性缺失这一场景提供了相应了钩子方法:propertyMissing、$static_propertyMissing。以避免直接抛出相应的异常,示例代码如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
   | class MissPropertyDemo {
      static void testLion() {         Lion lion = new Lion(name: "Tom", type: "LION")
          assert lion.name == "Tom"         assert lion.type == "LION"
                   def result = lion.age         assert result == "Not age Property For Get!"                  lion.age = 22
                   result = Lion.remark         assert result == "Not remark Static Property For Get!"                  Lion.remark = "危险动物"     } }
  class Lion{     String name     String type
      
 
 
 
      def propertyMissing(String propertyName) {         return  "Not ${propertyName} Property For Get!"     }
      
 
 
 
      void propertyMissing(String propertyName, Object args) {         println "Not ${propertyName} Property! For Set, args: ${args}"     }
      
 
 
 
      static def $static_propertyMissing(String propertyName) {         return "Not ${propertyName} Static Property For Get!"     }
      
 
 
 
      static void $static_propertyMissing(String propertyName, Object args) {         println "Not ${propertyName} Static Property For Set, args: ${args}"     } }
  | 
 
测试结果如下所示,符合预期

方法缺失
当我们调用一个不存在的方式时,即会抛出异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
   | class MissMethodDemo {     
 
      static void testCat() {         Cat cat = new Cat(name:"Tom", type:"CAT")
          try {                          cat.fly()         } catch (Exception e) {             assert e instanceof MissingMethodException             println("Happen Missing Method Exception #1")         }
          try {                          Cat.run()         } catch (Exception e) {             assert e instanceof MissingMethodException             println("Happen Missing Method Exception #2")         }     } }
  class Cat {     String name     String type }
  | 
 
测试结果如下,符合预期

对于非静态方法而言,我们可以实现methodMissing方法以避免抛出异常。示例代码如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
   | class MissMethodDemo {     
 
      static void testDog() {         Dog dog = new Dog(name:"Aaron", type:"DOG")                  String msg = dog.fly("5", "km")         assert msg == "[DOG] ==>> methodName: fly, args: [5, km]"     } }
  class Dog {     String name     String type
      
 
 
 
 
      def methodMissing(String methodName, Object args) {         return "[DOG] ==>> methodName: ${methodName}, args: ${args}"     } }
  | 
 
对于静态方法而言,我们可以实现$static_methodMissing方法以避免抛出异常。示例代码如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
   | class MissMethodDemo {     
 
      static void testChicken() {         assert Chicken.getInfo() == "I'm a CHICKEN"         assert Chicken.calcPrice() == "Missing Static Method: calcPrice"     } }
  class Chicken {     static String type = "CHICKEN"
      static String getInfo() {         return "I'm a ${type}"     }
      
 
 
 
 
      static def $static_methodMissing(String methodName, Object args) {         return "Missing Static Method: $methodName"     } }
  | 
 
与此同时,我们还可以通过invokeMethod方法进行动态选择的方法调用,示例代码如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
   | class MissMethodDemo {     
 
      static void testPig() {         Pig pig = new Pig(name:"Bob", type:"PIG")
                   def result1 = pig.swim()         assert result1 == "Yes, Bob can Swim..."
                   def result2 = pig.fly()         assert result2 == "Yes, Bob also can Fly~"
                   def result3 = pig.eat()         assert result3 == null     } }
  class Pig {     String name     String type
      String swimmable() {         return "Yes, ${name} can Swim..."     }
      String flyable() {         return "Yes, ${name} also can Fly~"     }
      
 
 
 
 
      def methodMissing(String methodName, Object args) {                  String newMethodName         switch (methodName) {             case "swim" : {                 newMethodName = methodName + "mable"                 break             }             case "fly" : {                 newMethodName = methodName + "able"                 break             }             default : newMethodName = null         }
          if(newMethodName) {             def result = this.invokeMethod( newMethodName, null )             return result         }         return null     } }
  | 
 
参考文献
- Groovy In Action · 2nd Edition   Dierk König、Guillaume Laforge著