Java >> Java tutorial >  >> Tag >> public

Løsning af Hide Utility Class Public Constructor Sonar Advarsel

1. Oversigt

Hjælpeklasser indeholder kun statisk medlemmer, som vi grupperer omkring et bestemt emne . Således er klasserne selv statsløse, mens deres medlemmer indeholder kode, der er beregnet til at blive genbrugt på tværs af flere lag.

I denne vejledning vil vi forklare, hvorfor statiske kodeanalysatorer rapporterer, at hjælpeklasser ikke bør have offentlige konstruktører. Vi vil se på at løse dette problem ved at implementere en privat konstruktør. Derudover vil vi undersøge, hvilke Lombok-annoteringer, der kan hjælpe os med at generere en. Vi viser også, hvordan du deaktiverer disse advarsler.

Til sidst vil vi evaluere nogle alternative tilgange til implementering af hjælpeklasser i Java.

2. Hjælpeklasser

I modsætning til klasser, der definerer objekter, gemmer hjælpeklasser ingen data eller tilstand. De indeholder kun adfærd . Hjælpeprogrammer indeholder kun statiske medlemmer. Alle deres metoder er statiske, mens data kun videregives som metodeargumenter.

2.1. Hvorfor hjælpeklasser?

I objektorienteret programmering søger vi at modellere vores problemdomæne og samle familier med lignende funktionalitet.

Vi kan også vælge at skrive rene funktioner for at modellere almindelig adfærd på tværs af vores kodebase, især ved brug af funktionel programmering . I modsætning til objektmetoder er disse rene funktioner ikke relateret til en forekomst af noget objekt. Men de har brug for et hjem. Java har ikke en bestemt type afsat til at rumme et sæt funktioner, så vi opretter ofte en hjælpeklasse.

Gode ​​eksempler på populære hjælpeklasser i Java er Arrays og Samlinger fra java.util , samt StringUtils formular org.apache.commons.lang3 .

2.2. Implementering i Java

Java giver ikke et særligt nøgleord eller en måde at oprette hjælpeklasser på. Således opretter vi normalt en hjælpeklasse som en almindelig Java-klasse, men med kun statiske medlemmer :

public final class StringUtils {

    public static boolean isEmpty(String source) {
        return source == null || source.length() == 0;
    }

    public static String wrap(String source, String wrapWith) {
        return isEmpty(source) ? source : wrapWith + source + wrapWith;
    }
}

I vores eksempel markerede vi værktøjsklassen som offentlig og endelig . Hjælpeprogrammer offentliggøres normalt, da de er beregnet til at blive genbrugt på tværs af flere lag.

finalen søgeord forhindrer underklassificering. Da hjælpeklasser ikke er designet til nedarvning , vi bør ikke underklassificere dem.

2.3. Advarsel om offentlig konstruktør

Lad os prøve at analysere vores eksempelværktøjsklasse ved hjælp af SonarQube, et populært statisk kodeanalyseværktøj. Vi kan køre en SonarQube-analyse på et Java-projekt ved hjælp af build-værktøjet plugin, i dette tilfælde Maven:

mvn clean verify sonar:sonar -Dsonar.host.url=http://localhost:9000 -Dsonar.login=XYXYXYXY

Den statiske kodeanalyse resulterer i en større kodelugt. SonarQube advarer os om at skjule den implicitte offentlige konstruktør i vores hjælpeklasse :

Selvom vi ikke tilføjede en konstruktør til vores hjælpeklasse, tilføjede Java implicit en standard offentlig. Således gør det muligt for API-brugere at oprette en forekomst af det:

StringUtils utils = new StringUtils();

Dette er et misbrug af vores hjælpeklasser, da det ikke er designet til at blive instansieret. Derfor råder SonarQube-reglen os til at tilføje en privat konstruktør for at skjule den offentlige standard.

3. Tilføjelse af en privat konstruktør

Lad os nu løse den rapporterede kodelugt ved at tilføje en privat konstruktør i vores hjælpeklasse.

3.1. Standard privat konstruktør

Lad os tilføje en privat konstruktør uden argumenter til vores hjælpeklasse. Vi vil aldrig rigtig bruge denne private konstruktør . Det er derfor en god praksis at kaste en undtagelse, hvis den hedder:

public final class StringUtils {

    private StringUtils() {
        throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
    }
  
    // public static methods
}

Vi skal bemærke, at den private konstruktør heller ikke kan testes. Denne tilgang vil således resultere i én linje med udækket kode i vores kodedækningsmålinger.

3.2. Brug af Lombok NoArgsConstructor

Vi kan gøre brug af NoArgsConstructor Lombok annotation til generer den private konstruktør automatisk :

@NoArgsConstructor(access= AccessLevel.PRIVATE)
public final class StringUtils {

    // public static methods
}

På denne måde kan vi undgå manuelt at tilføje en ekstra linje med udækket kode.

3.3. Brug af Lombok UtilityClass

Vi kan også bruge UtilityClass Lombok-annotering, der markerer en hel klasse som et hjælpeprogram :

@UtilityClass
public class StringUtils {

    // public static methods
}

I dette tilfælde vil Lombok automatisk:

  • generer en privat konstruktør, der kaster en undtagelse
  • marker som fejl alle eksplicitte konstruktører, vi tilføjer
  • marker klassen final

Vi bør bemærke, at UtilityClass på nuværende tidspunkt annotering er stadig en eksperimentel funktion.

4. Deaktivering af advarslen

Hvis vi beslutter os for ikke at følge den anbefalede løsning, har vi også mulighed for at deaktivere den offentlige konstruktøradvarsel.

4.1. Undertrykkelse af advarsel

Lad os gøre brug af Javas SuppressWarnings annotering for at deaktivere advarslen på et enkelt klasseniveau :

@SuppressWarnings("java:S1118")
public final class StringUtils {

    // public static methods
}

Vi bør videregive det korrekte SonarQube regel-id skal som en værdiparameter. Vi kan finde det i SonarQube server UI:

4.2. Deaktivering af en regel

I SonarQube out-of-the-box kvalitetsprofilen er vi ikke i stand til at deaktivere nogen af ​​de foruddefinerede regler. For således at deaktivere advarslen på hele projektniveau , skal vi først oprette en tilpasset kvalitetsprofil:

I vores tilpassede kvalitetsprofil kan vi søge efter og deaktivere enhver af de foruddefinerede Java-regler.

5. Alternative implementeringer

Lad os se på nogle mulige alternative måder, hvordan man laver hjælpeprogrammer udover at bruge klasser.

5.1. Statiske grænseflademetoder

Siden Java 8 kan vi definere og implementere statisk metoder i grænseflader :

public interface StringUtils {

    static boolean isEmpty(String source) {
        return source == null || source.length() == 0;
    }

    static String wrap(String source, String wrapWith) {
        return isEmpty(source) ? source : wrapWith + source + wrapWith;
    }
}

Da vi ikke kan instansiere grænseflader, eliminerede vi instansieringsproblemet med hjælpeklassen. Men vi skaber et andet problem. Da grænseflader er designet til at blive implementeret af andre klasser, kan en API-bruger fejlagtigt implementere denne grænseflade.

Derudover kan grænseflader ikke indeholde private konstanter og statiske initialiseringer.

5.2. Statiske enummetoder

Enums er beholdere med administrerede forekomster. Vi kan dog oprette et hjælpeprogram som en enum med nul forekomster, der kun indeholder statiske metoder :

public enum StringUtils {;

    public static boolean isEmpty(String source) {
        return source == null || source.length() == 0;
    }

    public static String wrap(String source, String wrapWith) {
        return isEmpty(source) ? source : wrapWith + source + wrapWith;
    }
}

Da vi ikke kan instansiere enum-typer, eliminerede vi instansieringsproblemet med hjælpeklassen. På den anden side, som navnet antyder, er enum-typer designet til at skabe faktiske opregninger, ikke brugsklasser.

6. Konklusion

I denne artikel undersøgte vi hjælpeklasser og forklarede, hvorfor de ikke burde have offentlige konstruktører .

I eksemplerne dækkede vi implementering af en privat konstruktør manuelt og brug af Lombok-annoteringer. Dernæst så vi, hvordan man undertrykker og deaktiverer den relaterede SonarQube-advarsel. Til sidst så vi på to alternative måder at skabe hjælpeprogrammer på ved hjælp af grænseflader og enums.

Som altid er kildekoden tilgængelig på GitHub.


No
Java tag