java - معلمات جافا الاختيارية




optional-parameters (11)

كيف أستخدم المعلمات الاختيارية في Java؟ ما مواصفات تدعم المعلمات الاختيارية؟


نسخة مختصرة :

باستخدام ثلاث نقاط :

public void foo(Object... x) {
    String first    =  x.length > 0 ? (String)x[0]  : "Hello";
    int duration    =  x.length > 1 ? Integer.parseInt((String) x[1])     : 888;
}   
foo("Hii", ); 
foo("Hii", 146); 

(بناءً على إجابة @ VitaliiFedorenko)


التحميل الزائد جيد ، ولكن إذا كان هناك الكثير من المتغيرات التي تحتاج إلى قيمة افتراضية ، فستنتهي بـ:

public void methodA(A arg1) {  }
public void methodA( B arg2,) {  }
public void methodA(C arg3) {  }
public void methodA(A arg1, B arg2) {  }
public void methodA(A arg1, C arg3) {  }
public void methodA( B arg2, C arg3) {  }
public void methodA(A arg1, B arg2, C arg3) {  }

لذا أقترح استخدام حجة المتغير المقدمة من جافا. هنا link للتوضيح.


تم ذكر VarArgs والتحميل الزائد. خيار آخر هو نمط منشئ ، والذي قد يبدو كالتالي:

 MyObject my = new MyObjectBuilder().setParam1(value)
                                 .setParam3(otherValue)
                                 .setParam6(thirdValue)
                                 .build();

على الرغم من أن هذا النمط سيكون الأنسب عندما تحتاج إلى معلمات اختيارية في مُنشئ.


في JDK> 1.5 يمكنك استخدامه مثل هذا ؛

public class NewClass1 {

    public static void main(String[] args) {

        try {
            someMethod(18); // Age : 18
            someMethod(18, "John Doe"); // Age & Name : 18 & John Doe
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static void someMethod(int age, String... names) {

        if (names.length > 0) {
            if (names[0] != null) {
                System.out.println("Age & Name : " + age + " & " + names[0]);
            }
        } else {
            System.out.println("Age : " + age);
        }
    }
}

للأسف ، لا تدعم جافا المعلمات الافتراضية مباشرةً.

ومع ذلك ، كتبت مجموعة من التعليقات التوضيحية لـ JavaBean ، وأحدها يدعم المعلمات الافتراضية مثل ما يلي:

protected void process(
        Processor processor,
        String item,
        @Default("Processor.Size.LARGE") Size size,
        @Default("red") String color,
        @Default("1") int quantity) {
    processor.process(item, size, color, quantity);
}
public void report(@Default("Hello") String message) {
    System.out.println("Message: " + message);
}

ينشئ معالج التعليق التوضيحي أسلوب التحميل الزائد لدعم هذا بشكل صحيح.

راجع http://code.google.com/p/javadude/wiki/Annotations

مثال كامل على http://code.google.com/p/javadude/wiki/AnnotationsDefaultParametersExample مثال


هناك عدة طرق لمحاكاة المعلمات الاختيارية في Java:

  1. زيادة الحمولة

    void foo(String a, Integer b) {
        //...
    }
    
    void foo(String a) {
        foo(a, 0); // here, 0 is a default value for b
    }
    
    foo("a", 2);
    foo("a");
    

    أحد قيود هذا الأسلوب هو أنه لا يعمل إذا كان لديك معلمتان اختياريتان من نفس النوع ويمكن حذف أي منهما.

  2. Varargs.

    أ) جميع المعلمات الاختيارية من نفس النوع:

    void foo(String a, Integer... b) {
        Integer b1 = b.length > 0 ? b[0] : 0;
        Integer b2 = b.length > 1 ? b[1] : 0;
        //...
    }
    
    foo("a");
    foo("a", 1, 2);
    

    ب) قد تختلف أنواع المعلمات الاختيارية:

    void foo(String a, Object... b) {
        Integer b1 = 0;
        String b2 = "";
        if (b.length > 0) {
          if (!(b[0] instanceof Integer)) { 
              throw new IllegalArgumentException("...");
          }
          b1 = (Integer)b[0];
        }
        if (b.length > 1) {
            if (!(b[1] instanceof String)) { 
                throw new IllegalArgumentException("...");
            }
            b2 = (String)b[1];
            //...
        }
        //...
    }
    
    foo("a");
    foo("a", 1);
    foo("a", 1, "b2");
    

    العيب الرئيسي لهذا النهج هو أنه إذا كانت المعلمات الاختيارية من أنواع مختلفة تفقد تفقد نوع ثابت. وعلاوة على ذلك ، إذا كان لكل معلمة معنى مختلف ، فأنت تحتاج إلى طريقة لتمييزها.

  3. بلا قيم. لمعالجة حدود النهج السابقة ، يمكنك السماح بالقيم الخالية ثم تحليل كل معلمة في نص أسلوب:

    void foo(String a, Integer b, Integer c) {
        b = b != null ? b : 0;
        c = c != null ? c : 0;
        //...
    }
    
    foo("a", null, 2);
    

    يجب توفير جميع قيم الوسيطات ، لكن القيم الافتراضية قد تكون فارغة.

  4. فئة اختيارية. يشبه هذا الأسلوب القيم الخالية ، ولكنه يستخدم فئة Java 8 الاختيارية للمعلمات التي لها قيمة افتراضية:

    void foo(String a, Optional<Integer> bOpt) {
        Integer b = bOpt.isPresent() ? bOpt.get() : 0;
        //...
    }
    
    foo("a", Optional.of(2));
    foo("a", Optional.<Integer>absent());
    

    اختياري يجعل عقد طريقة صريح للمتصل ، ومع ذلك ، قد يجد المرء مثل هذا التوقيع مطولاً للغاية.

    تحديث: يتضمن Java 8 class java.util.Optional خارج المربع ، لذلك ليس هناك حاجة لاستخدام الجوافة لهذا السبب بالذات في java 8. اسم الأسلوب مختلف قليلاً بالرغم من ذلك.

  5. نمط البناء. يتم استخدام نمط البناء للمنشئات ويتم تنفيذه عن طريق إدخال فئة Builder منفصلة:

     class Foo {
         private final String a; 
         private final Integer b;
    
         Foo(String a, Integer b) {
           this.a = a;
           this.b = b;
         }
    
         //...
     }
    
     class FooBuilder {
       private String a = ""; 
       private Integer b = 0;
    
       FooBuilder setA(String a) {
         this.a = a;
         return this;
       }
    
       FooBuilder setB(Integer b) {
         this.b = b;
         return this;
       }
    
       Foo build() {
         return new Foo(a, b);
       }
     }
    
     Foo foo = new FooBuilder().setA("a").build();
    
  6. خرائط. عندما يكون عدد المعلمات كبيرًا جدًا ، وعادةً ما يتم استخدام القيم الافتراضية لمعظمها ، فيمكنك تمرير وسيطات الأسلوب كخريطة لأسماء / قيمها:

    void foo(Map<String, Object> parameters) {
        String a = ""; 
        Integer b = 0;
        if (parameters.containsKey("a")) { 
            if (!(parameters.get("a") instanceof Integer)) { 
                throw new IllegalArgumentException("...");
            }
            a = (Integer)parameters.get("a");
        }
        if (parameters.containsKey("b")) { 
            //... 
        }
        //...
    }
    
    foo(ImmutableMap.<String, Object>of(
        "a", "a",
        "b", 2, 
        "d", "value")); 
    

يرجى ملاحظة أنه يمكنك الجمع بين أي من هذه الأساليب لتحقيق نتيجة مرغوبة.


يعتمد الأمر على ما تريد تحقيقه ، يجب أن يحل overaring overgages أو الأسلوب معظم السيناريوهات.

لكن ضع في اعتبارك عدم استخدام التحميل الزائد للطريقة. يجلب الارتباك.


يمكن للفارارج القيام بذلك (بطريقة ما). بخلاف ذلك ، يجب توفير جميع المتغيرات في إعلان الطريقة. إذا كنت تريد أن يكون المتغير اختياريًا ، فيمكنك زيادة الحمل على الطريقة باستخدام التوقيع الذي لا يتطلب المعلمة.

private boolean defaultOptionalFlagValue = true;

public void doSomething(boolean optionalFlag) {
    ...
}

public void doSomething() {
    doSomething(defaultOptionalFlagValue);
}

يمكنك استخدام فئة تشبه إلى حد كبير أداة البناء لاحتواء قيمك الاختيارية مثل هذه.

public class Options {
    private String someString = "default value";
    private int someInt= 0;
    public Options setSomeString(String someString) {
        this.someString = someString;
        return this;
    }
    public Options setSomeInt(int someInt) {
        this.someInt = someInt;
        return this;
    }
}

public static void foo(Consumer<Options> consumer) {
    Options options = new Options();
    consumer.accept(options);
    System.out.println("someString = " + options.someString + ", someInt = " + options.someInt);
}

استخدام مثل

foo(o -> o.setSomeString("something").setSomeInt(5));

الانتاج هو

someString = something, someInt = 5

لتخطي جميع القيم الاختيارية التي يجب عليك foo(o -> {}); مثل foo(o -> {}); أو إذا كنت تفضل ، يمكنك إنشاء طريقة foo() ثانية لا تأخذ المعلمات الاختيارية.

باستخدام هذا الأسلوب ، يمكنك تحديد القيم الاختيارية بأي ترتيب دون أي غموض. يمكنك أيضًا الحصول على معلمات من فئات مختلفة بخلاف varargs. سيكون هذا النهج أفضل إذا كان يمكنك استخدام التعليقات التوضيحية وتوليد التعليمات البرمجية لإنشاء فئة الخيارات.


يمكنك فعل الشيء باستخدام طريقة التحميل الزائد مثل هذا.

 public void load(String name){ }

 public void load(String name,int age){}

كما يمكنك استخدام التعليق التوضيحيNullable

public void load(@Nullable String name,int age){}

ببساطة تمرير فارغة كمعلمة الأولى.

إذا كنت تمرر متغير النوع نفسه ، فيمكنك استخدام هذا

public void load(String name...){}





optional-parameters