Dönüş türü içeren Java yöntemi, dönüş deyimi olmadan derler


228

Soru 1:

Aşağıdaki kod bir return ifadesi olmadan neden derleniyor?

public int a() {
    while(true);
}

Uyarı: Bir süre sonra iade eklersem o zaman bir olsun Unreachable Code Error.

Soru 2:

Öte yandan, aşağıdaki kod neden derleniyor,

public int a() {
    while(0 == 0);
}

Aşağıdaki gibi olmasa bile.

public int a(int b) {
    while(b == b);
}

2
2. sorunun ikinci yarısı sayesinde stackoverflow.com/questions/16789832/… 'in kopyası değil .
TJ Crowder

Yanıtlar:


274

Soru 1:

Aşağıdaki kod bir return ifadesi olmadan neden derleniyor?

public int a() 
{
    while(true);
}

Bu JLS§8.4.7 kapsamındadır :

Bir yöntemin bir dönüş türüne (§8.4.5) sahip olduğu bildirilirse, yöntemin gövdesi normal şekilde tamamlanabilirse, derleme zamanı hatası oluşur (§14.1).

Başka bir deyişle, döndürme türüne sahip bir yöntem yalnızca değer döndüren bir döndürme deyimi kullanarak dönmelidir; yöntemin "vücudunun ucunu düşürmesine" izin verilmez. Bir yöntem gövdesindeki dönüş ifadeleriyle ilgili kesin kurallar için §14.17'ye bakın.

Bir yöntemin bir dönüş türüne sahip olması ve yine de herhangi bir dönüş ifadesi içermemesi mümkündür. İşte bir örnek:

class DizzyDean {
    int pitch() { throw new RuntimeException("90 mph?!"); }
}

Derleyici, döngünün hiçbir zaman sonlanmayacağını bildiğinden ( trueelbette her zaman doğrudur), işlevin "normal olarak geri dönemeyeceğini" (vücudunun ucunu düşürdüğünü) bilir ve bu nedenle hayır olmaması iyidir return.

Soru 2:

Öte yandan, aşağıdaki kod neden derleniyor,

public int a() 
{
    while(0 == 0);
}

Aşağıdaki gibi olmasa bile.

public int a(int b)
{
    while(b == b);
}

Bu 0 == 0durumda, derleyici döngünün asla sonlanmayacağını bilir (bu 0 == 0her zaman doğru olacaktır). Ama gelmez için biliyorum b == b.

Neden olmasın?

Derleyici sabit ifadeleri anlar (§15.28) . Alıntı §15.2 - İfade Biçimleri (garip bir şekilde bu cümle §15.28'de olmadığı için) :

Bazı ifadelerin derleme zamanında belirlenebilen bir değeri vardır. Bunlar sabit ifadelerdir (§15.28).

Senin içinde b == byer alan bir değişken olduğundan örneğin, bir sabit ifadesi değildir ve derleme zamanında belirlenecek belirtilmemiştir. Biz (eğer rağmen her zaman bu durumda gerçek olacak görebilirsiniz bolduğu bir doubleQBrute olarak, işaret , kolayca aptal olabilir Double.NaNki, değil ==kendisi ), ancak JLS sabit ifadeler derleme zamanında kararlı olduklarını sadece belirtir , derleyicinin sabit olmayan ifadeleri değerlendirmeye çalışmasına izin vermez. bayou.io neden olmasa da iyi bir noktaya değindi : Derleme zamanında değişkenleri içeren ifadeleri belirlemeye çalışmak için yola çıkmaya başlarsanız, nerede duruyorsunuz? b == baçıktır (er,NaNdeğerleri), ama ne olacak a + b == b + a? Yoksa (a + b) * 2 == a * 2 + b * 2? Çizgiyi sabitlerde çizmek mantıklıdır.

Dolayısıyla, ifadeyi "belirlemediğinden", derleyici döngünün asla sonlanmayacağını bilmez, bu nedenle yöntemin normal olarak geri dönebileceğini düşünür - ki buna izin verilmez, çünkü kullanılması gerekir return. Yani bir eksikliği hakkında şikayet ediyor return.


34

Belirtilen türde bir değer döndürmek için bir söz olarak değil bir yöntem dönüş türü düşünmek ilginç olabilir, ama bir söz olarak değil bir değer döndürmek için değil Belirtilen Çeşidi. Bu nedenle, asla bir şey iade etmezseniz, sözünü bozmazsınız ve bu nedenle aşağıdakilerden herhangi biri yasaldır:

  1. Sonsuza kadar döngü:

    X foo() {
        for (;;);
    }
  2. Sonsuza kadar tekrarlayan:

    X foo() {
        return foo();
    }
  3. Bir istisna atmak:

    X foo() {
        throw new Error();
    }

(Ben düşünmek için eğlenceli bir özyineleme bulmak: Derleyici yöntemi türünü X(ne olursa olsun) bir değer döndürecek inanıyor , ama bu doğru değil, çünkü nasıl oluşturmak veya temin etmek X.)


8

Bayt koduna bakıldığında, döndürülmekte olan şey tanımla eşleşmiyorsa, bir derleme hatası alırsınız.

Misal:

for(;;) bayt kodlarını gösterecektir:

L0
    LINENUMBER 6 L0
    FRAME SAME
    GOTO L0

Herhangi bir dönüş bayt kodu eksikliğine dikkat edin

Bu hiç bir geri dönüşü etkilemez ve bu nedenle yanlış türü döndürmez.

Karşılaştırma için aşağıdaki gibi bir yöntem:

public String getBar() { 
    return bar; 
}

Aşağıdaki bayt kodlarını döndürür:

public java.lang.String getBar();
    Code:
      0:   aload_0
      1:   getfield        #2; //Field bar:Ljava/lang/String;
      4:   areturn

"Referans döndür" anlamına gelen "dönüş" e dikkat edin

Şimdi aşağıdakileri yaparsak:

public String getBar() { 
    return 1; 
}

Aşağıdaki bayt kodlarını döndürür:

public String getBar();
  Code:
   0:   iconst_1
   1:   ireturn

Şimdi tanımdaki türün, ireturn'ün dönüş türüyle eşleşmediğini görebiliriz, bu da int int anlamına gelir.

Yani, aslında yöntemin bir dönüş yolu varsa, o yolun dönüş türüyle eşleşmesi gerekir. Ancak bayt kodunda hiçbir dönüş yolunun oluşturulmadığı ve dolayısıyla kuralın kesilmediği durumlar vardı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.