Java'da nihayet bir bloktan geri dönme


177

Son zamanlarda Java nihayet bir blok dönüş ifadesi mümkün olduğunu bulmak için şaşırdım.

Birçok insanın ' Sonunda bir maddede geri dönme ' bölümünde anlatıldığı gibi yapmanın kötü bir şey olduğunu düşünüyor gibi görünüyor . Biraz daha derine katarak , nihayet bloklarda diğer akış kontrolü türlerinin bazı korkunç örneklerini gösteren ' Java'nın dönüşü her zaman olmaz ' buldum .

Benim sorum şu: Herkes sonunda bir blokta bir return deyiminin (veya başka bir akış kontrolünün) daha iyi / daha okunabilir kod ürettiği bir örnek verebilir mi?

Yanıtlar:


90

Verilen örnekler nedeni yeterli değildir nihayet gelen akış denetimi kullanın.

"Daha iyi" olduğu konusunda tutarlı bir örnek olsa bile, kodunuzu daha sonra korumak zorunda olan ve inceliklerin farkında olmayabilecek geliştiriciyi düşünün. Zavallı geliştirici sen bile olabilirsin ....


5
Elbette. Sanırım birisi bana iyilik açısından gerçekten etkileyici bir örnek verebilirse soruyorum.
Matt Sheppard

@MattSheppard daos'ta genellikle bir sorgunun çıkışını bir deneme
Blake

148

Yıllar önce bunun neden olduğu bir hatayı izlemek için gerçekten zor bir zaman geçirdim. Kod şöyle bir şeydi:

Object problemMethod() {
    Object rtn = null;
    try {
        rtn = somethingThatThrewAnException();
    }
    finally {
        doSomeCleanup();
        return rtn;
    }
}

Olan şey, istisnanın başka bir kodda atılmış olmasıdır. Yöntemde yakalanıp günlüğe kaydedildi ve yeniden düzenlendi somethingThatThrewAnException(). Ancak istisna geçmişte yayılmıyordu problemMethod(). Bu uzun bir süre sonra nihayet dönüş yöntemi aşağı izledi. Nihayet bloğundaki döndürme yöntemi, temelde deneme bloğunda gerçekleşen istisnanın yakalanmasa bile çoğalmasını durduruyordu.

Diğerlerinin söylediği gibi, Java özelliklerine göre nihayet bir bloktan dönmek yasal olsa da, bu KÖTÜ bir şeydir ve yapılmamalıdır.


Geri dönüşü nereye koymalı?
parsecer

@parsecer denemek blok içinde bir
şeyThatThrewAnException

@parsecer, ?? Sonunda her zamanki gibi yap.
Pacerier

21

javac sonunda -Xlint: kullanırsanız dönüş uyarısı verecektir. Aslında javac uyarı vermedi - kodda bir sorun varsa, derlenemedi. Ne yazık ki geriye dönük uyumluluk, beklenmedik ustaca aptallığın yasaklanamayacağı anlamına gelir.

Sonunda bloklardan istisnalar atılabilir, ancak bu durumda sergilenen davranış neredeyse kesinlikle istediğiniz şeydir.


13

Son olarak {} bloklarına kontrol yapıları ve geri dönüşler eklemek, neredeyse tüm geliştirme dillerine dağılmış olan "sadece yapabilmeniz için" kötüye kullanımın başka bir örneğidir. Jason kolayca bir bakım kabusu olabileceğini öne sürdü - fonksiyonlardan erken dönüşlere karşı olan argümanlar bu "geç dönüşler" vakası için daha geçerlidir.

Son olarak, önceki kodda ne olursa olsun, kendinizden sonra tamamen toplanmanıza izin vermek için bir amaç için bloklar vardır. Aslında bu ısmarlama denetim ekleyerek söylemek gergin görebiliyordu rağmen dosya işaretçileri, veritabanı bağlantıları vb kapanış / serbest olduğunu.

İşlevin dönüşünü etkileyen her şey try {} bloğunda olmalıdır. Harici bir durumu kontrol ettiğiniz, zaman alan bir işlem yaptığınız, ardından geçersiz hale gelmesi durumunda bu durumu tekrar kontrol ettiğiniz bir yöntem olsa bile, yine de {} - sonunda oturduysa {} denemesinin içindeki ikinci kontrolü istersiniz. ve uzun işlem başarısız olursa, bu durumu gereksiz yere ikinci kez kontrol edersiniz.


6

Basit bir Groovy Testi:

public class Instance {

  List<String> runningThreads = new ArrayList<String>()

  void test(boolean returnInFinally) {

    println "\ntest(returnInFinally: $returnInFinally)"
    println "--------------------------------------------------------------------------"
    println "before execute"
    String result = execute(returnInFinally, false)
    println "after execute -> result: " + result
    println "--------------------------------------------------------------------------"

    println "before execute"
    try {
      result = execute(returnInFinally, true)
      println "after execute -> result: " + result
    } catch (Exception ex) {
      println "execute threw exception: " + ex.getMessage()
    }  
    println "--------------------------------------------------------------------------\n"

  }

  String execute(boolean returnInFinally, boolean throwError) {
      String thread = Thread.currentThread().getName()
      println "...execute(returnInFinally: $returnInFinally, throwError: $throwError) - thread: $thread"
      runningThreads.add(thread)
      try {
        if (throwError) {
          println "...error in execute, throw exception"
          throw new Exception("as you liked :-)")
        }
        println "...return 'OK' from execute"
        return "OK"
      } finally {
        println "...pass finally block"
        if (returnInFinally) return "return value from FINALLY ^^"
        // runningThreads.remove(thread)
      }
  }
}

Instance instance = new Instance()
instance.test(false)
instance.test(true)

Çıktı:

test(returnInFinally: false)
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: false, throwError: false) - thread: Thread-116
...return 'OK' from execute
...pass finally block
after execute -> result: OK
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: false, throwError: true) - thread: Thread-116
...error in execute, throw exception
...pass finally block
execute threw exception: as you liked :-)
-----------------------------------------------------------------------------


test(returnInFinally: true)
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: true, throwError: false) - thread: Thread-116
...return 'OK' from execute
...pass finally block
after execute -> result: return value from FINALLY ^^
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: true, throwError: true) - thread: Thread-116
...error in execute, throw exception
...pass finally block
after execute -> result: return value from FINALLY ^^
-----------------------------------------------------------------------------

Soru:

Benim için ilginç bir nokta, Groovy'nin örtük getirilerle nasıl başa çıktığını görmekti. Groovy'de, sonunda bir değer bırakarak (dönüş olmadan) bir yöntemden "geri dönmek" mümkündür. Sonunda deyiminde runningThreads.remove (..) satırını kaldırırsanız ne olacağını düşünüyorsunuz - bu normal dönüş değerinin ("Tamam") üzerine yazacak ve istisnayı kapsayacak mı ?!


0

Bir finallybloğun içinden geri dönmek exceptionskaybolmaya neden olur .

Son olarak bir bloğun içindeki bir return ifadesi, try veya catch bloğuna atılabilecek herhangi bir istisnanın atılmasına neden olur.

Göre Java Dil Şartname:

Try bloğunun yürütülmesi başka herhangi bir R nedeni için aniden tamamlanırsa, nihayet blok yürütülür ve sonra bir seçenek vardır:

   If the finally block completes normally, then the try statement
   completes  abruptly for reason R.

   If the finally block completes abruptly for reason S, then the try
   statement  completes abruptly for reason S (and reason R is
   discarded).

Not: JLS 14.17'ye göre - bir iade ifadesi her zaman aniden tamamlanır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.