java - كيف يمكنني refactor هذه الحلقة؟




refactoring (3)

إذا كنت تستخدم Java 8 ، فيمكنك أيضًا استدعاء forEach أو map على Stream forEach ، على سبيل المثال

yourStream.forEach(doStuff());

حيث doStuff() هو consumer يتعامل مع السلسلة أو استخدم yourStream.forEach(s -> doStuff()) إذا كنت لا تريد التعامل مع السلسلة do stuff فقط.

يمكنك الحصول على دفق كما يلي:

Stream.of(yourArray) // or Arrays.stream(yourArray)
      .forEach(doStuff());

ول قائمتك:

list.stream()
    .forEach(doStuff());

الفائدة الرئيسية لاستخدام الجداول هي إمكانية القراءة على الأرجح. قد يفقد الأمر فيما يتعلق بالأداء وقد يفقد أيضًا إذا كنت لا ترغب في الاتصال بـ Stream.of/Arrays.stream أو Collection.stream() لمجرد الحصول على الدفق.

إذا كنت ترغب حقًا في الحفاظ على طريقة something(...) (القدرة على التعامل مع كل من: varargs والقائمة) ، فأنت لا تزال بحاجة إلى طريقة محمّلة بشكل زائد أو استخدم اقتراح Andy Turner مع أسلوب Object -Parameter-method.

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

الآن يجب أن أضيف طريقة جديدة مثل هذه تعمل عبر حلقة لكل:

public void something(Item... items) {
    for (Item i : items) {
        doStuff();
    }
}

public void something(List<Item> items) {
    for (Item i : items) {
        doStuff();
    }
}

بمعنى آخر ، بالضبط نفس الطريقة مرتين لكل من المصفوفات والقوائم البدائية. هل هناك أي طريقة ل refactor لطيف هذا في طريقة واحدة؟


لا يمكنك (*) عدم القيام بذلك بطريقة واحدة. Item[] List<Item> أنواع غير مرتبطة.

يجب عليك إجراء أحد الأحمال الزائدة للاتصال بآخر: إما يستدعي something(Item... items) something(List<Item>) أو يستدعي something(Item... items) something(List<Item>) something(Item... items) .

من بين الخيارين ، من الأفضل للحمولة الزائدة للصفيف استدعاء التحميل الزائد للقائمة:

public void something(Item... items) {
  something(Arrays.asList(item));
}

هذا رخيص ، لأنه لا ينسخ الصفيف ، بل يلفه: إنشاء List هو O(1) .

إذا كنت تريد استدعاء التحميل الزائد للصفيف من التحميل الزائد للقائمة:

public void something(List<Item> items) {
  something(items.toArray(new Item[0]));
}

سيكون هذا أكثر تكلفة ، نظرًا لأن استدعاء toArray يجب عليه إنشاء صفيف toArray : إنها عملية O(n) ، حيث يكون n هو حجم القائمة. ومع ذلك ، فإن لديها ميزة طفيفة تتمثل في عدم تمكن something من استبدال محتويات List ، حيث يتم تجاهل أي تحديثات للصفيف بعد التنفيذ.

(*) يمكنك ذلك ، لكن سيكون من الإجمالي حقًا ، وليس آمنًا على الكتابة ، حيث يتعين عليك قبول معلمة Object ، حيث لا يوجد نوع شائع آخر شائع من List<Item> Item[] ؛ وكنت لا تزال بحاجة إلى تكرار الحلقات للنوعين ؛ ويجب أن تتعامل مع إمكانية تمرير نوع غير ذي صلة تمامًا (في وقت التشغيل):

public void something(Object obj) {
  if (obj instanceof List) {
    for (Object element : (List<?>) obj) {
      Item item = (Item) element;  // Potential ClassCastException.
      doStuff();
    }
  } else if (obj instanceof Item[]) {
    for (Item item : (Item[]) obj) {
      doStuff();
    }
  } else {
    throw new IllegalArgumentException();
  }
}

ما هذه الفوضى. أشكر صانع لالأحمال الزائدة.


يمكنك تطبيق طريقة واحدة ، في هذه الحالة ، الطريقة الثانية لأنها تحتوي على قائمة كمعلمة. بدلاً من الطريقة الأولى ، يمكنك تحويل الصفيف في قائمة باستخدام Arrays.asList(items) ، ثم يمكنك استدعاء الطريقة الأولى. لذلك ، في النهاية ، سيكون لديك طريقة واحدة فقط (تحتوي على قائمة كمعلمة).

أيضًا ، إذا كانت قائمة العناصر تحتوي على عناصر قليلة ، يمكنك استخدام تعبيرات lambda من Java 8:

items.foreach(item -> doStuff(item));

لذلك ، لن يكون لديك طريقة تحتوي على حلقة واحدة فقط وسيكون الرمز أسهل في القراءة.





refactoring