Wat is het standaardgebruik als de schakelaar voor een opsomming is?

Stel dat ik een opsomming heb Colormet 2 mogelijke waarden: REDen BLUE:

public enum Color {
    RED,
    BLUE
}

Stel nu dat ik een switch-statement heb voor deze opsomming waar ik code heb voor beide mogelijke waarden:

Color color = getColor(); // a method which returns a value of enum "Color"
switch (color) {
case RED:
   ...
   break;
case BLUE:
   ...
   break;
default:
   break;
}

Aangezien ik een codeblok heb voor beide mogelijke waarden van de enum, wat is dan het gebruik van defaultin de bovenstaande code?

Moet ik een uitzondering maken als de code op de een of andere manier het default-blok op deze manier bereikt?

Color color = getColor(); // a method which returns a value of enum "Color"
switch (color) {
case RED:
   ...
   break;
case BLUE:
   ...
   break;
default:
   throw new IllegalArgumentException("This should not have happened");
}

Antwoord 1, autoriteit 100%

Het is een goede gewoonte om een ​​Exception te gooien, zoals je in het tweede voorbeeld hebt laten zien. Je verbetert de onderhoudbaarheid van je code door snel te falen.

In dit geval zou het betekenen dat als je later (misschien jaren later) een enum-waarde toevoegt en het de switch-statement bereikt, je de fout onmiddellijk zult ontdekken.

Als de standaardwaarde niet was ingesteld, zou de code misschien zelfs met de nieuwe enum-waarde doorlopen en mogelijk ongewenst gedrag vertonen.


Antwoord 2, autoriteit 60%

De andere antwoorden zijn correct door te zeggen dat je een defaultbranch moet implementeren die een uitzondering genereert, voor het geval er in de toekomst een nieuwe waarde aan je opsomming wordt toegevoegd. Ik zou echter nog een stap verder gaan en me afvragen waarom je überhaupt een switch-statement gebruikt.

In tegenstelling tot talen als C++ en C#, vertegenwoordigt Java Enum-waarden als werkelijke objecten, wat betekent dat u objectgeoriënteerd programmeren kunt gebruiken. Laten we zeggen dat het doel van uw methode is om voor elke kleur een RGB-waarde te geven:

switch (color)
    case RED:
       return "#ff0000";
    ...

Als je wilt dat elke kleur een RGB-waarde heeft, moet je dat waarschijnlijk als onderdeel van de beschrijving opnemen:

public enum Color
{
    RED("#FF0000"),
    BLUE("#0000FF");
    String rgb;
    public Color(String rgb) {
        this.rgb = rgb;
    }
    public getRgb() { return this.rgb; }
}

Op die manier bent u, als u later een nieuwe kleur toevoegt, vrijwel gedwongen om een ​​RGB-waarde op te geven. Het is zelfs nog sneller dan de andere benadering, omdat je tijdens het compileren zult mislukken in plaats van tijdens het uitvoeren.

Houd er rekening mee dat je zelfs nog ingewikkelder dingen kunt doen als dat nodig is, inclusief dat elke kleur zijn eigen aangepaste implementatie van een abstracte methode biedt. Enums in Java zijn echt krachtig en objectgeoriënteerd, en in de meeste gevallen heb ik gemerkt dat ik kan voorkomen dat ik ze in de eerste plaats moet switch.


Antwoord 3, autoriteit 13%

Compilatietijd van de switch-cases garandeert geen volledigheid van runtime.

Klasse met een switch-statement gecompileerd tegen een oudere versie van enum kan worden uitgevoerd met een nieuwere enum-versie (met meer waarden). Dat is een veelvoorkomend geval bij bibliotheekafhankelijkheden.

Om deze redenen beschouwt de compiler de switchzonder default-case als onvolledig.


Antwoord 4, autoriteit 9%

In kleine programma’s is daar geen praktisch nut voor, maar denk aan een complex systeem dat door een groot aantal bestanden en ontwikkelaars wordt verspreid – als u de enumin één bestand definieert en het in nog een, en later voegt iemand een waarde toe aan de enumzonder de switch-instructie bij te werken, je zult het erg handig vinden…


Antwoord 5, autoriteit 8%

Als je alle mogelijkheden hebt behandeld met je verschillende casesen de defaultniet kan gebeuren, is dit de klassieke use case voor beweringen:

Color color = getColor(); // a method which returns a value of enum "Color"
switch (color) {
    case RED:
       // ...
       break;
    case BLUE:
       // ...
       break;
    default:
       assert false; // This cannot happen
       // or:
       throw new AssertionError("Invalid Colors enum");
}

Antwoord 6, autoriteit 7%

Om aan IDE’s en andere statische linters te voldoen, laat ik de standaardcase vaak staan ​​als een no-op, samen met een opmerking als // Can't happenof // Unreachable

d.w.z. als de switch het typische doet om alle mogelijke enum-waarden te verwerken, expliciet of via fall-throughs, dan is het standaardgeval waarschijnlijk een programmeerfout.

Afhankelijk van de toepassing plaats ik soms een bewering in de case om tijdens de ontwikkeling te beschermen tegen programmeerfouten. Maar dit heeft een beperkte waarde in de verzendcode (tenzij u verzendt met ingeschakelde beweringen.)

Nogmaals, afhankelijk van de situatie ben ik er misschien van overtuigd om een ​​fout te genereren, omdat dit in werkelijkheid een onherstelbare situatie is — niets dat de gebruiker kan doen, zal een waarschijnlijke programmeerfout corrigeren.


Antwoord 7, autoriteit 7%

Ja, je zou het moeten doen. Je mag enumwijzigen, maar verander switchniet. In de toekomst zal het tot fouten leiden. Ik denk dat throw new IllegalArgumentException(msg)gooien de goede gewoonte is.


Antwoord 8, autoriteit 6%

Als de enum-constanten te veel zijn en u slechts enkele gevallen hoeft te verwerken, dan zal de defaultde rest van de constanten afhandelen.

Enum-constanten zijn ook referenties, als de referentie nog niet is ingesteld, of null. Het kan zijn dat u ook met dergelijke gevallen te maken krijgt.


Antwoord 9, autoriteit 6%

Ja, het is dode code totdat iemand een waarde toevoegt aan de opsomming, waardoor je switch-statement het principe van ‘fail fast’ volgt (https://en.wikipedia.org/wiki/Fail-fast)

Dit kan betrekking hebben op deze vraag: Hoe zorg je voor volledigheid in een enum-switch tijdens het compileren?


Antwoord 10, autoriteit 3%

Afgezien van de mogelijke toekomstige uitbreiding van de opsomming, waar velen op hebben gewezen, kan iemand op een dag je getColor()‘verbeteren’ of het in een afgeleide klasse overschrijven en het een ongeldige waarde. Natuurlijk zou een compiler dat moeten opvangen, tenzij iemand expliciet onveilige typecasting forceert…

Maar er gebeuren gewoon slechte dingen, en het is een goede gewoonte om geen onverwacht elseof default-pad onbewaakt te laten.


Antwoord 11, autoriteit 3%

Het verbaast me dat niemand anders dit heeft genoemd. Je kunt een int casten naar een enum en het zal niet gooien alleen omdat de waarde niet een van de opgesomde waarden is. Dit betekent (onder andere) dat de compiler niet kan zien dat alle enum-waarden in de schakelaar staan.

Zelfs als je je code correct schrijft, komt dit echt naar voren bij het serialiseren van objecten die enums bevatten. Een toekomstige versie kan toevoegen aan de opsomming en je code verslikt zich bij het teruglezen ervan, of iemand die chaos wil creëren, kan een nieuwe waarde erin zetten. Hoe dan ook, het is zelden goed om van de schakelaar af te komen. Dus we gooien er standaard in, tenzij we beter weten.

Other episodes