Neden geçersiz kılınan yöntemler geçersiz kılınan yöntemden daha geniş istisnalar atamıyor?


108

Kathe Sierra'nın SCJP 6 kitabını inceliyordum ve geçersiz kılınan yöntemde istisnalar atmanın bu açıklamalarına rastladım. Ben pek anlamadım. Biri bana açıklayabilir mi?

Geçersiz kılma yöntemi, geçersiz kılınan yöntem tarafından bildirilenlerden yeni veya daha geniş olan kontrol edilmiş istisnaları ATMAMALIDIR. Örneğin, bir FileNotFoundException bildiren bir yöntem, bir FileNotFoundException alt sınıfı olmadığı sürece SQLException, Exception veya başka bir çalışma zamanı dışı özel durum bildiren bir yöntem tarafından geçersiz kılınamaz.


1
işte size yardımcı olabilecek bir site: javapractices.com/topic/TopicAction.do?Id=129
Tim Bish

Yanıtlar:


161

Bu, bir yöntem belirli bir istisna atmayı bildirirse, bir alt sınıftaki geçersiz kılma yönteminin yalnızca bu istisnayı veya alt sınıfını atmayı bildirebileceği anlamına gelir. Örneğin:

class A {
   public void foo() throws IOException {..}
}

class B extends A {
   @Override
   public void foo() throws SocketException {..} // allowed

   @Override
   public void foo() throws SQLException {..} // NOT allowed
}

SocketException extends IOExceptionama SQLExceptiondeğil.

Bunun nedeni çok biçimliliktir:

A a = new B();
try {
    a.foo();
} catch (IOException ex) {
    // forced to catch this by the compiler
}

Eğer Batmaya karar vermişti SQLException, sonra derleyici size örneğine atıfta çünkü sen onu yakalamak için zorlamak olamazdı Bonun süper tarafından - A. Öte yandan, herhangi bir alt sınıfı, IOExceptionişleyen tümceler (catch veya throws) tarafından ele alınacaktır.IOException

Nesnelere üst sınıflarına göre başvurabilmeniz için gereken kural Liskov İkame İlkesidir.

Kontrol edilmeyen istisnalar herhangi bir yere atılabileceğinden, bu kurala tabi değildirler. İsterseniz bir belge biçimi olarak throws yan tümcesine denetlenmemiş bir istisna ekleyebilirsiniz, ancak derleyici bununla ilgili hiçbir şeyi zorlamaz.


Bu, arayüzleri uygularken de geçerli mi? Arayüz uygulamasının hala "geçersiz kılma" olarak adlandırılıp adlandırılmadığından emin değilim.
Muhammad Gelbana

@Override public void foo () {..} Buna izin verildiğini biliyorum ama bu durum için açıklama net değil.
nascar

4
@danip geçersiz kılma yöntemi, geçersiz kılma yönteminden atılan istisnaların herhangi bir alt kümesini atabilir. Boş küme de bir alt kümedir. Bu yüzden @Override public void foo() {...}yasaldır.
Geliştirici Marius Žilėnas

@Bozho olmamalı bir yöntem, belirli bir özel durum ilan etmesi halinde, bir alt sınıfta geçersiz kılma yöntemi yalnızca o durum veya alt sınıfı atmak ilan edebilir veya HAYIR hiç maddesi atar beyan
Raman sahasi

Öyleyse gerçek dünyada üstesinden gelinmesi nasıl? Uygulanan bir arayüzden bir yöntemi geçersiz kılmam gerekiyor, ancak benim uygulamam bir atma yavaşlaması içeriyor ve arayüzünki yok. Buradaki standart prosedür nedir?
ap

22

Geçersiz kılma yöntemi, geçersiz kılınan yöntemin istisnayı bildirip bildirmediğine bakılmaksızın, denetlenmemiş (çalışma zamanı) istisnaları atabilir

Misal:

class Super {
    public void test() {
        System.out.println("Super.test()");
    }
}

class Sub extends Super {
    @Override
    public void test() throws IndexOutOfBoundsException {
        // Method can throw any Unchecked Exception
        System.out.println("Sub.test()");
    }
}

class Sub2 extends Sub {
    @Override
    public void test() throws ArrayIndexOutOfBoundsException {
        // Any Unchecked Exception
        System.out.println("Sub2.test()");
    }
}

class Sub3 extends Sub2 {
    @Override
    public void test() {
        // Any Unchecked Exception or no exception
        System.out.println("Sub3.test()");
    }
}

class Sub4 extends Sub2 {
    @Override
    public void test() throws AssertionError {
        // Unchecked Exception IS-A RuntimeException or IS-A Error
        System.out.println("Sub4.test()");
    }
}

Arayüzünüz alt sınıfın yaptığı bir çalışma zamanı istisnasını bildirmediğinde bir hatayı veya uyarıyı nasıl zorlarsınız? Belgeleme amacıyla tutarlılığı zorlamaya çalışıyorum. Arayüz tipini tüm istisnalar için kontrol etmek, işaretli ve kontrol edilmemiş olarak kontrol etmek, arayüz tipini bulmak ve ardından sadece IOException veya IllegalArgumentException atıp atmadığını görmek için uygulamaya dalmaktan daha kolaydır.
anon58192932

14

Bence Java sözdizimi tasarımında bir başarısızlık. Çok biçimlilik, istisna işlemenin kullanımını sınırlamamalıdır. Aslında, diğer bilgisayar dilleri bunu yapmaz (C #).

Dahası, bir yöntem daha özel bir alt sınıfta geçersiz kılınır, böylece daha karmaşık ve bu nedenle yeni istisnalar atma olasılığı daha yüksektir.


8

Bu cevabı burada eski soruya veriyorum çünkü hiçbir cevap , geçersiz kılan yöntemin hiçbir şeyi atamayacağını söylemez, burada yine geçersiz kılma yönteminin atabileceği şey :

1) aynı istisnayı atın

public static class A 
{
    public void m1()
       throws IOException
    {
        System.out.println("A m1");
    }

}

public static class B 
    extends A
{
    @Override
    public void m1()
        throws IOException
    {
        System.out.println("B m1");
    }
}

2) geçersiz kılma yönteminin atılan istisnasının alt sınıfını atma

public static class A 
{
    public void m2()
       throws Exception
    {
        System.out.println("A m2");
    }

}

public static class B 
    extends A
{
    @Override
    public void m2()
        throws IOException
    {
        System.out.println("B m2");
    }
}

3) hiçbir şey atmayın.

public static class A 
{   
    public void m3()
       throws IOException
    {
        System.out.println("A m3");
    }
}

public static class B 
    extends A
{   
    @Override
    public void m3()
        //throws NOTHING
    {
        System.out.println("B m3");
    }
}

4) Atışlarda RuntimeExceptions olması gerekli değildir.

Atışlarda RuntimeExceptions olabilir veya olmayabilir, derleyici bundan şikayet etmez. RuntimeExceptions kontrol edilen istisnalar değildir. Yakalanmazlarsa yalnızca işaretli istisnaların atışlarda görünmesi gerekir.


6

Bunu göstermek için şunları göz önünde bulundurun:

public interface FileOperation {
  void perform(File file) throws FileNotFoundException;
}

public class OpenOnly implements FileOperation {
  void perform(File file) throws FileNotFoundException {
    FileReader r = new FileReader(file);
  }
}

Diyelim ki o zaman:

public class OpenClose implements FileOperation {
  void perform(File file) throws FileNotFoundException {
    FileReader r = new FileReader(file);
    r.close();
  }
}

Bu size bir derleme hatası verir, çünkü r.close () FileNotFoundException'dan daha geniş bir IOException oluşturur.

Bunu düzeltmek için yazarsanız:

public class OpenClose implements FileOperation {
  void perform(File file) throws IOException {
    FileReader r = new FileReader(file);
    r.close();
  }
}

Perform (...) işlemini uyguladığınız için farklı bir derleme hatası alırsınız, ancak arayüzün yöntem tanımına dahil olmayan bir istisna atarsınız.

Bu neden önemli? Arayüzün tüketicisinde şunlar olabilir:

FileOperation op = ...;
try {
  op.perform(file);
}
catch (FileNotFoundException x) {
  log(...);
}

IOException'ın atılmasına izin verildiyse, istemcinin kodu artık doğru değildir.

Kontrol edilmemiş istisnalar kullanırsanız bu tür sorunları önleyebileceğinizi unutmayın. (Yapmanı veya yapmamanı önermiyorum, bu felsefi bir mesele)


4

Bir röportaj sorusu alalım. Süper sınıfta NullPointerException oluşturan bir yöntem vardır. RuntimeException oluşturan bir yöntemle onu geçersiz kılabilir miyiz?

Bu soruyu yanıtlamak için, Kontrol Edilmemiş ve Kontrol Edilmiş istisnanın ne olduğunu bize bildirin.

  1. Kontrol edilen istisnalar, Temel try-catch-nihayet Özel Durum İşleme'de açıklandığı gibi açıkça yakalanmalı veya yayılmalıdır. Kontrol edilmeyen istisnaların bu şartı yoktur. Yakalanmaları veya atılmaları gerekmiyor.

  2. Java'da denetlenen istisnalar, java.lang.Exception sınıfını genişletir. Kontrol edilmeyen istisnalar java.lang.RuntimeException'ı genişletir.

genel sınıf NullPointerException RuntimeException'ı genişletir

Kontrol edilmeyen istisnalar java.lang.RuntimeException'ı genişletir. Bu nedenle NullPointerException bir Uncheked istisnasıdır.

Bir örnek alalım: Örnek 1:

    public class Parent {
       public void name()  throws NullPointerException {
           System.out.println(" this is parent");
       }
}

public class Child  extends Parent{
     public  void name() throws RuntimeException{
             System.out.println(" child ");
     }

     public static void main(String[] args) {
        Parent parent  = new Child();
        parent.name();// output => child
    }
}

Program başarıyla derlenecektir. Örnek 2:

    public class Parent {
       public void name()  throws RuntimeException {
           System.out.println(" this is parent");
       }
}

public class Child  extends Parent{
     public  void name() throws  NullPointerException {
             System.out.println(" child ");
     }

     public static void main(String[] args) {
        Parent parent  = new Child();
        parent.name();// output => child
    }
}

Program ayrıca başarıyla derlenecektir. Bu nedenle, Kontrolsüz istisnalar durumunda hiçbir şeyin olmadığı açıktır. Şimdi, Checked istisnaları durumunda ne olduğuna bir göz atalım. Örnek 3: Temel sınıf ve alt sınıfın her ikisi de kontrol edilen bir istisna attığında

    public class Parent {
       public void name()  throws IOException {
           System.out.println(" this is parent");
       }
}
public class Child  extends Parent{
     public  void name() throws IOException{
             System.out.println(" child ");
     }

     public static void main(String[] args) {
        Parent parent  = new Child();

        try {
            parent.name();// output=> child
        }catch( Exception e) {
            System.out.println(e);
        }

    }
}

Program başarıyla derlenecektir. Örnek 4: Alt sınıf yöntemi, aynı temel sınıf yöntemine kıyasla sınır denetimli istisna attığında.

import java.io.IOException;

public class Parent {
       public void name()  throws IOException {
           System.out.println(" this is parent");
       }
}
public class Child  extends Parent{
     public  void name() throws Exception{ // broader exception
             System.out.println(" child ");
     }

     public static void main(String[] args) {
        Parent parent  = new Child();

        try {
            parent.name();//output=> Compilation failure
        }catch( Exception e) {
            System.out.println(e);
        }

    }
}

Program derlenemeyecek. Bu nedenle, İşaretli istisnaları kullanırken dikkatli olmalıyız.


mükemmel cevap!
Gaurav

2

Diyelim ki, M1 yöntemini atan E1 yöntemiyle süper sınıf A'ya ve M1 yöntemini geçersiz kılan M2 yöntemiyle A'dan türetilen B sınıfı. M2, E1'den FARKLI veya DAHA AZ ÖZELLEŞTİRİLEN bir şey fırlatamaz.

Polimorfizm nedeniyle, A sınıfını kullanan müşteri B'yi Amış gibi ele alabilmelidir. Inharitance ===> Is-a (B is-a A). Ya M1'in bu kontrol edilen istisnayı attığını bildirdiği gibi, A sınıfı ile ilgili bu kod E1 istisnasını işliyorsa, ancak daha sonra farklı bir istisna türü atılmışsa? M1, IOException M2 atıyorsa, bir IOException olduğu için FileNotFoundException oluşturabilir. A'nın müşterileri bunu sorunsuz bir şekilde halledebilir. Atılan istisna daha geniş olsaydı, A'nın müşterilerinin bunu bilme şansı olmayacak ve bu nedenle yakalama şansı olmayacaktı.


Perhac :: bu hem işaretli hem de işaretsiz istisnalar için doğru mu? veya değişir mi?
ylnsagar

@ylnsagar, bu yalnızca kontrol edilen istisnalar içindir. Kontrol edilmeyen istisnalar (RuntimeException alt türleri) ayrıca 'programcı hataları' olarak da adlandırılabilir ve genel bir kural olarak deneme yakalama yapılmamalıdır, bu nedenle throws cümlesinde bildirilmeleri gerekmez. Kontrol edilmeyen bir istisna, herhangi bir zamanda herhangi bir koddan gerçekleşebilir. Yukarıdaki tartışma yalnızca kontrol edilen istisnalarla ilgilidir
Peter Perháč

@Perhac :: evet haklısın, ama benim anladığım kadarıyla makaleler okuyarak. Kontrol edilmeyen istisnalar için de geçerlidir. örneğin, bir süper sınıf yöntemi Null Pointer Exception atıyorsa ve yöntemi geçersiz kılan alt sınıf Exception atarsa. burada Exception süper bir Sıfır İşaretçi İstisnası sınıfıdır. O zaman derleyici buna izin vermez.
ylnsagar

1

Peki java.lang.Exception java.lang.Throwable'ı genişletir. java.io.FileNotFoundException, java.lang.Exception'ı genişletir. Dolayısıyla, bir yöntem java.io.FileNotFoundException atarsa, geçersiz kılma yönteminde, hiyerarşide FileNotFoundException'dan daha yüksek bir şey atamazsınız, örneğin java.lang.Exception atamazsınız. Yine de FileNotFoundException'ın bir alt sınıfını atabilirsiniz. Ancak, geçersiz kılma yönteminde FileNotFoundException'ı işlemeye zorlanacaksınız. Biraz kod yazın ve deneyin!

Kurallar oradadır, böylece özgünlüğü genişleterek orijinal atış bildirimini kaybetmezsiniz, çünkü polimorfizm, süper sınıfta geçersiz kılma yöntemini çağırabileceğiniz anlamına gelir.


1

Geçersiz kılma yöntemi, geçersiz kılınan yöntem tarafından bildirilenlerden yeni veya daha geniş olan kontrol edilmiş istisnaları ATMAMALIDIR.

Misal:

class Super {
    public void throwCheckedExceptionMethod() throws IOException {
        FileReader r = new FileReader(new File("aFile.txt"));
        r.close();
    }
}

class Sub extends Super {    
    @Override
    public void throwCheckedExceptionMethod() throws FileNotFoundException {
        // FileNotFoundException extends IOException
        FileReader r = new FileReader(new File("afile.txt"));
        try {
            // close() method throws IOException (that is unhandled)
            r.close();
        } catch (IOException e) {
        }
    }
}

class Sub2 extends Sub {
    @Override
    public void throwCheckedExceptionMethod() {
        // Overriding method can throw no exception
    }
}

1

Geçersiz kılma yöntemi, geçersiz kılınan yöntem tarafından bildirilenlerden yeni veya daha geniş olan kontrol edilmiş istisnaları ATMAMALIDIR.

Bu basitçe, mevcut bir yöntemi geçersiz kıldığınızda, bu aşırı yüklenmiş yöntemin attığı istisna, orijinal yöntemin oluşturduğu istisna veya alt sınıflarından herhangi biri olması gerektiği anlamına gelir .

Kontrol edilen tüm istisnaların işlenip işlenmediğini kontrol etmenin çalışma zamanında değil derleme zamanında yapıldığını unutmayın. Bu nedenle, derleme zamanında, Java derleyicisi, geçersiz kılınan yöntemin fırlattığı istisna türünü kontrol eder. Hangi geçersiz kılınan yöntemin çalıştırılacağına yalnızca çalışma zamanında karar verilebileceğinden, ne tür bir İstisna yakalamamız gerektiğini bilemeyiz.


Misal

Diyelim ki sınıfımız Ave onun alt sınıfımız var B. Ayöntemi vardır m1ve sınıf Bbu yöntemi geçersiz kılmıştır ( m2karışıklığı önlemek için onu çağıralım ..). Şimdi bakalım diyelim m1atar E1ve m2atar E2olan E1'ın üst sınıf. Şimdi aşağıdaki kod parçasını yazıyoruz:

A myAObj = new B();
myAObj.m1();

Bunun m1bir çağrıdan başka bir şey olmadığına dikkat edin m2(tekrar, aşırı yüklenmiş yöntemlerde yöntem imzaları aynıdır, bu nedenle karıştırmayın m1ve m2.. bu örnekte sadece farklılaşmak içindir ... ikisinin de imzası aynıdır). Ancak derleme zamanında, tüm java derleyicisinin yaptığı referans türüne gider ( Abu durumda Sınıf ), yöntemin mevcut olup olmadığını kontrol eder ve programcının onu işlemesini bekler. Yani belli ki atmak veya yakalamak olacaktır E1. Şimdi, çalışma zamanında, aşırı yüklenmiş yöntem atarsa E2, ki bu E1üst sınıftır, o zaman ... bu çok yanlıştır (aynı nedenle söyleyemeyiz B myBObj = new A()). Dolayısıyla Java buna izin vermiyor. Aşırı yüklenmiş yöntem tarafından atılan kontrol edilmeyen istisnalar aynı, alt sınıflar olmalı veya mevcut olmamalıdır.


class Üst {void method (), IndexOutOfBoundsException {System.out.println ("Ana yöntem") atar; }} sınıf Alt öğe genişler Üst {void yöntem () RuntimeException {System.out.println ("Alt yöntem") atar; } Ana sınıf, çalışma zamanı istisnasının bir alt öğesini atarsa ​​ve çocuk, Çalışma Zamanı istisnasının kendisini atarsa. Geçerli mi?
abhiagNitk

1

Bunu anlamak için, bir dosyayı okuyan, üzerinde bazı işlemler yapan ve bir sınıf örneğini döndüren yöntemi Mammaltanımlayan bir sınıfımız olduğu readAndGetbir örneği ele alalım Mammal.

class Mammal {
    public Mammal readAndGet() throws IOException {//read file and return Mammal`s object}
}

Sınıf Human, sınıfı genişletir Mammalve readAndGetörneği Humanyerine örneğini döndürmek için yöntemi geçersiz kılar Mammal.

class Human extends Mammal {
    @Override
    public Human readAndGet() throws FileNotFoundException {//read file and return Human object}
}

Aramak readAndGetiçin halletmemiz gerekecek IOExceptionçünkü bu kontrol edilmiş bir istisna ve memelininki readAndMethodonu fırlatıyor.

Mammal mammal = new Human();
try {
    Mammal obj = mammal.readAndGet();
} catch (IOException ex) {..}

Ve derleyicinin mammal.readAndGet()sınıf nesnesinden çağrıldığını biliyoruz, Mammalancak çalışma zamanı JVM , tutuyor olduğu için mammal.readAndGet()sınıftan bir çağrıya yapılan yöntem çağrısını çözecektir .Humanmammalnew Human()

Yöntem readAndMethoddan Mammalatıyor IOExceptionve çünkü bir kontrol istisna derleyici dediğimiz zaman bunu yakalamak için bizi zorlar readAndGetüzerindemammal

Şimdi varsayalım ki readAndGet, Humankontrol edilen herhangi bir istisna, örneğin İstisna ve çünkü çünkü tutuyor readAndGetörneğinden çağrılacağını biliyoruz .Humanmammalnew Human()

Derleyici için yöntem çağrıldığından Mammal, derleyici bizi yalnızca işlemeye zorlayacaktır, IOExceptionancak çalışma zamanında yöntemin işlenmeyen bir Exceptionistisna atacağını ve yöntem istisnayı atarsa ​​kodumuzun kırılacağını biliyoruz .

Bu nedenle derleyici seviyesinde engellenir ve sonunda JVM tarafından ele alınmayacağı için yeni veya daha geniş kontrol edilen istisnalar atmamıza izin verilmemektedir.

Yöntemleri geçersiz kılarken uymamız gereken başka kurallar da vardır ve nedenlerini öğrenmek için Yöntemi Geçersiz Kılma Kurallarını Neden Takip Etmeliyiz hakkında daha fazla bilgi edinebilirsiniz .


0

Aşağıdakilere hangi açıklamayı atfediyoruz?

class BaseClass {

    public  void print() {
        System.out.println("In Parent Class , Print Method");
    }

    public static void display() {
        System.out.println("In Parent Class, Display Method");
    }

}


class DerivedClass extends BaseClass {

    public  void print() throws Exception {
        System.out.println("In Derived Class, Print Method");
    }

    public static void display() {
        System.out.println("In Derived Class, Display Method");
    }
}

DerivedClass.java Sınıfı, print yöntemi bir İstisna attığında bir derleme zamanı istisnası atar, baseclass'ın print () metodu herhangi bir istisna atmaz

Bunu, İstisnanın RuntimeException'dan daha dar olduğu gerçeğine atfedebiliyorum, İstisna Yok (Çalışma Zamanı hatası), RuntimeException ve alt istisnaları olabilir.


0

Alt sınıfın geçersiz kılma yöntemi, yalnızca üst sınıfın yönteminin kontrol edilen istisnasının alt sınıfları olan birden fazla kontrol edilmiş istisna atabilir, ancak üst sınıfın yönteminin kontrol edilen istisnasıyla ilgisi olmayan birden fazla kontrol edilmiş istisna atamaz.


0

Java, size üst sınıfta istisnaları kısıtlama seçeneği sunar, çünkü istemcinin yakalanan şeyi kısıtlayacağını varsayar . IMHO, aslında bu "özelliği" asla kullanmamalısınız, çünkü müşterilerinizin yolda esnekliğe ihtiyacı olabilir.

Java, kötü tasarlanmış eski bir dildir. Modern dillerin böyle kısıtlamaları yoktur. Bu kusuru aşmanın en kolay yolu, throw Exceptiondaima temel sınıfınızı oluşturmaktır . Müşteriler daha spesifik İstisnalar atabilir ancak temel sınıflarınızı gerçekten geniş hale getirebilir.


0

Geçersiz kılınan yöntemlerde denetim ve denetlenmemiş istisnaları işleme kuralı

- Ebeveyn-sınıf yöntemi istisna bildirmediğinde , alt sınıf geçersiz kılma yöntemi bildirebilir ,

 1. No exception or
 2. Any number of unchecked exception
 3. but strictly no checked exception

-Ana-sınıf yöntemi denetlenmemiş bir istisna bildirdiğinde, alt sınıf geçersiz kılma yöntemi ,

 1. No exception or
 2. Any number of unchecked exception 
 3. but strictly no checked exception

- Ebeveyn-sınıf metodu kontrol edilen istisnayı ilan ettiğinde, alt sınıf geçersiz kılma metodu ,

 1. No exception or
 2. Same checked exception or
 3. Sub-type of checked exception or
 4. any number of unchecked exception

Yukarıdaki sonuçların tümü, hem kontrol edilen hem de kontrol edilmeyen istisnanın kombinasyonu ebeveyn-sınıf 'yönteminde bildirilmiş olsa bile doğru kalır

Referans

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.