Java >> Java tutorial >  >> Tag >> throw

Kaster undtagelser i konstruktører

1. Oversigt

Undtagelser giver adskillelse af fejlhåndteringskode fra programmets normale flow. Det er ikke ualmindeligt at kaste en undtagelse under instansieringen af ​​et objekt.

I denne artikel vil vi undersøge alle detaljer om at smide undtagelser i konstruktører.

2. Smid undtagelser i konstruktører

Konstruktører er specielle typer metoder, der påberåbes for at skabe et objekt. I de følgende afsnit vil vi se på, hvordan man kaster undtagelser, hvilke undtagelser der skal kastes, og hvorfor vi ville kaste undtagelser i konstruktører.

2.1. Hvordan?

At smide undtagelser i konstruktøren er ikke anderledes end at gøre det i enhver anden metode. Lad os starte med at oprette et Dyr klasse med en no-arg-konstruktør:

public Animal() throws InstantiationException {
    throw new InstantiationException("Cannot be instantiated");
}

Her smider vi InstantiationException , hvilket er en markeret undtagelse.

2.2. Hvilke?

Selvom det er tilladt at smide enhver form for undtagelse, så lad os etablere nogle bedste fremgangsmåder.

For det første ønsker vi ikke at smide "java.lang.Exception" . Dette skyldes, at den, der ringer, umuligt kan identificere, hvilken slags undtagelse og dermed håndtere den.

For det andet bør vi smide en markeret undtagelse, hvis den, der ringer, skal tvangshåndtere den.

For det tredje bør vi smide en umarkeret undtagelse, hvis en opkalder ikke kan komme sig fra undtagelsen.

Det er vigtigt at bemærke, at denne praksis er lige anvendelig for både metoder og konstruktører .

2.3. Hvorfor?

Lad os i dette afsnit forstå, hvorfor vi måske ønsker at smide undtagelser i konstruktøren.

Argumentvalidering er en almindelig brugssag til at smide undtagelser i konstruktøren. Konstruktører bruges mest til at tildele værdier af variabler. Hvis argumenterne sendt til konstruktøren er ugyldige, kan vi smide undtagelser. Lad os overveje et hurtigt eksempel:

public Animal(String id, int age) {
    if (id == null)
        throw new NullPointerException("Id cannot be null");
    if (age < 0)
        throw new IllegalArgumentException("Age cannot be negative");
}

I ovenstående eksempel udfører vi argumentvalidering før initialisering af objektet. Dette er med til at sikre, at vi kun opretter gyldige objekter.

Her, hvis id videregivet til Dyret objektet er null , kan vi smide NullPointerException For argumenter, der ikke er nul, men stadig er ugyldige, såsom en negativ værdi for alder , kan vi smide en IllegalArgumentException .

Sikkerhedstjek er en anden almindelig brugssag til at smide undtagelser i konstruktøren. Nogle af objekterne skal have sikkerhedstjek under deres oprettelse. Vi kan kaste undtagelser, hvis konstruktøren udfører en muligvis usikker eller følsom operation.

Lad os overveje vores Dyr klasse indlæser attributter fra en brugerinputfil:

public Animal(File file) throws SecurityException, IOException {
    if (file.isAbsolute()) {
        throw new SecurityException("Traversal attempt");
    }
    if (!file.getCanonicalPath()
        .equals(file.getAbsolutePath())) {
        throw new SecurityException("Traversal attempt");
    }
}

I vores eksempel ovenfor forhindrede vi Path Traversal-angrebet. Dette opnås ved ikke at tillade absolutte stier og mappegennemgang. Overvej f.eks. filen "a/../b.txt". Her er den kanoniske sti og den absolutte sti forskellige, hvilket kan være et potentielt Directory Traversal-angreb.

3. Nedarvede undtagelser hos konstruktører

Lad os nu tale om håndtering af superklasse-undtagelser i konstruktører.

Lad os oprette en børneklasse, Bird , der udvider vores Dyr klasse:

public class Bird extends Animal {
    public Bird() throws ReflectiveOperationException {
        super();
    }
    public Bird(String id, int age) {
        super(id, age);
    }
}

Siden super() skal være den første linje i konstruktøren, kan vi ikke bare indsætte en try-catch blok for at håndtere den kontrollerede undtagelse, som er smidt af superklassen.

Siden vores forældreklasse Dyr kaster den kontrollerede undtagelse InstantiationException , vi kan ikke håndtere undtagelsen i Fuglen konstruktør. I stedet kan vi udbrede den samme undtagelse eller dens overordnede undtagelse.

Det er vigtigt at bemærke, at reglen for undtagelseshåndtering med hensyn til metodetilsidesættelse er anderledes. I metodetilsidesættelse, hvis superklassemetoden erklærer en undtagelse, kan den underklassetilsidesatte metode erklære den samme, underklasseundtagelse eller ingen undtagelse, men kan ikke erklære en overordnet undtagelse.

På den anden side behøver ukontrollerede undtagelser ikke deklareres, og de kan heller ikke håndteres inde i underklassekonstruktører.

4. Sikkerhedsbekymringer

At smide en undtagelse i en konstruktør kan føre til delvist initialiserede objekter. Som beskrevet i Guideline 7.3 i Java Secure Coding Guidelines, er delvist initialiserede objekter af en ikke-finale klasse tilbøjelige til en sikkerhedsproblemer kendt som et Finalizer-angreb.

Kort sagt induceres et Finalizer-angreb ved at underklassificere delvist initialiserede objekter og tilsidesætte dets finalize() metode og forsøger at oprette en ny forekomst af den underklasse. Dette vil muligvis omgå sikkerhedstjek udført inde i underklassens konstruktør.

Tilsidesættelse af finalize() metode og markere den endelig kan forhindre dette angreb.

Men finalize() metoden er blevet forældet i Java 9, hvilket forhindrer denne type angreb.

5. Konklusion

I dette selvstudie har vi lært om at smide undtagelser i konstruktører sammen med de tilhørende fordele og sikkerhedsproblemer. Vi tog også et kig på nogle bedste fremgangsmåder til at smide undtagelser i konstruktører.

Som altid er kildekoden, der bruges i denne tutorial, tilgængelig på GitHub.


No
Java tag