Hvilke fejl bør man undgå, når man programmerer i Java? I det følgende afsnit besvarer vi dette spørgsmål.
Java er et populært sprog med en etableret position i verden af softwareudvikling. Det er et stærkt og alsidigt programmeringssprog. Omkring 3 milliarder enheder på verdensplan kører på Java og derfor blev der begået mindst 3 milliarder fejl, da den blev brugt. I denne artikel vil vi fokusere på, hvordan man undgår at lave flere.
1. Få undtagelse for samtidig ændring
Det er langt den mest almindelige fejl, jeg er stødt på. I begyndelsen af min karriere begik jeg den også mange gange. Fejlen opstår, når man forsøger at ændre samlingen, mens man itererer gennem den. Den ConcurrentModificationUdtagelse kan også opstå, når du arbejder med flere tråde, men lad os nu fokusere på et basisscenarie.
Antag, at du har en Samling af brugere, hvor nogle af dem er voksne, og andre ikke er. Din opgave er at filtrere børnene fra.
for (Bruger : brugere) {
if (!user.isAdult()) {
users.remove(user);
}
}
Kører den førnævnte Kode ender med at få ConcurrentModificationUdtagelse. Hvor gik vi galt i byen? Før vi afsluttede vores iteration, forsøgte vi at fjerne nogle elementer. Det er det, der udløser undtagelsen.
Hvordan kan jeg undgå det?
Der er et par tilgange, der kan hjælpe i det tilfælde. Først og fremmest skal du drage fordel af Java 8's godhed - Strøm.
List adults = users.stream()
.filter(User::isAdult)
.toList();
Brug af en Prædikat filter har vi gjort det omvendte af den tidligere betingelse - nu bestemmer vi, hvilke elementer der skal inkluderes. Fordelen ved en sådan tilgang er, at det er nemt at kæde andre funktioner sammen efter fjernelsen, f.eks. kort. Men prøv for guds skyld ikke at gøre noget i stil med nedenstående:
Det kunne også ende i ConcurrentModificationUdtagelse fordi du ændrer strømkilden. Det kan også give dig nogle flere undtagelser, som ikke er nemme at fejlfinde.
At løse ConcurrentModificationUdtagelse i et single-thread-scenarie. Du kan også skifte til at bruge direkte Iterator og dens fjern() metoden, eller du kan simpelthen lade være med at fjerne elementer under iterationen. Min anbefaling er dog at bruge Vandløb - Det er 2022.
2. Gemme adgangskoder som strenge
Da jeg bliver mere og mere involveret i cybersikkerhed, ville jeg ikke være tro mod mig selv, hvis jeg ikke nævnte mindst én Java-fejl der kan føre til et sikkerhedsproblem. Lagring af adgangskoder modtaget fra brugere i en Streng objekt er netop noget, du skal være bange for.
Problemet (eller måske fordelen) ved Streng er, at den er uforanderlig. I cyberverdenen skaber det en potentiel trussel, da du ikke kan slette værdien af en engang oprettet Streng objekt. Den angriber, der får adgang til din computers hukommelse, kan finde adgangskoder i klartekst der.
For det andet er strenge i Java internaliseres af JVM'en og gemmes i PermGen-rummet eller i heap-rummet. Når du opretter en Streng objektet, bliver det cached, og det bliver først fjernet, når Garbage Collector begynder at gøre sit arbejde. Du kan ikke være sikker på, hvornår din adgangskode bliver slettet fra String-poolen, da Garbage Collector arbejder på en ikke-deterministisk måde.
Hvordan undgår man det?
Den anbefalede tilgang er at bruge char[] eller, endnu bedre, et bibliotek, der understøtter lagring af adgangskoder som char[]f.eks.Password4j. Den char[] er foranderlig og kan ændres, efter at den er blevet initialiseret. Når du har behandlet en adgangskode, kan du bare slette char[] password-array ved at skrive tilfældige tegn i det. Hvis angriberne får adgang til din computers hukommelse, vil de kun se nogle tilfældige værdier, som ikke har noget at gøre med brugernes adgangskoder.
3. (U)håndtering af undtagelser
Nybegyndere og også mere avancerede programmører ved ikke, hvordan de skal håndtere undtagelser korrekt. Deres største synd i den forbindelse er bare at ignorere dem. DET ER ALDRIG EN GOD TILGANG.
Desværre kan vi ikke give dig en universalløsning, der passer til alle. Undtagelses' scenarie, du støder på. Du skal tænke på hvert enkelt tilfælde. Men vi kan give dig nogle råd om, hvordan du kommer i gang med det emne.
Hvordan kan jeg undgå det?
Ignorerer Undtagelseer aldrig en god praksis. Undtagelses er smidt ind af en eller anden grund, så du bør ikke ignorere dem.
try {...} catch(Exception e) { log(e); } er sjældent den rigtige tilgang til Undtagelse håndtering.
Kast Undtagelsevise en fejldialog til brugeren eller i det mindste tilføje en omfattende besked til loggen.
Hvis du ikke har håndteret dine undtagelser (hvilket du ikke bør), så forklar dig i det mindste i kommentaren.
4. Brug af nul
Desværre er det ret almindeligt at finde en Java-funktion, der i nogle tilfælde returnerer en nul. Problemet er, at en sådan funktion tvinger sin klient til at udføre et null-tjek på resultatet. Uden det vil NullPointerUdtagelse bliver kastet.
Den anden ting er at sende en nul værdi. Hvorfor tænkte du overhovedet på det? I et sådant tilfælde skal funktionen udføre et null-check. Når man bruger tredjepartsbiblioteker, kan man ikke ændre funktionernes inderside. Hvad gør man så?
Endnu vigtigere er det, at andre udviklere, der læser din kode og ser, at du passerer nul vil nok være forvirret over, hvorfor du vælger en så bizar måde at implementere din funktion på.
Hvordan kan jeg undgå det?
Returner ikke en nul værdi! Nogensinde! Hvis din funktion returnerer en eller anden form for Samlingkan du bare returnere en tom Samling. Hvis du arbejder med enkeltobjekter, kan du bruge designmønsteret for null-objekter. Siden Java 8, er det implementeret som Valgfrit. Bortset fra det er den mindst anbefalede fremgangsmåde at rejse en Undtagelse.
5. Tung sammenkædning af strenge
Forhåbentlig er det ikke en fejl, du begår, da det er det mest populære (eller måske næstmest populære efter FizzBuzz) interviewspørgsmål. Som du burde vide nu, er en Streng objektet er uforanderligt i Java - Når den først er oprettet, kan den ikke ændres. Så sammenkædning af Streng bogstaver betyder en masse unødvendig hukommelsesallokering. Sammenkædning af Streng objekter hver gang kræver oprettelse af en midlertidig StringBuilder objekt og ændre det tilbage til en streng. Derfor er denne løsning absolut ikke egnet, hvis vi ønsker at kombinere et stort antal tegn.
Hvordan kan jeg undgå det?
For at løse det problem skal du bruge StringBuilder. Det skaber et foranderligt objekt, som let kan manipuleres. Du kan selvfølgelig altid bruge StringBuffer hvis din projekt bruges i en samtidig kontekst.
6. Ikke at bruge eksisterende løsninger
Når man udvikler software, er det et must at kende det grundlæggende i det sprog, man skriver i, men det er ikke nok. Mange algoritmiske problemer, du støder på, når du implementerer en ny funktion, er allerede blevet løst af en anden. Alt for mange gange har jeg set nogen implementere en sikkerhedsalgoritme fra bunden. En sådan tilgang er fejlbehæftet. En person kan ikke teste en så kompleks løsning grundigt. Den kollektive viden hos hold der består af middelgode programmører, er næsten altid bedre end et enkelt vidunderbarns storhed. Java-udvikler. Du behøver ikke at opfinde den dybe tallerken igen - du skal bare tilpasse den eksisterende løsning, så den passer til dine behov.
Hvordan kan jeg undgå det?
Prøv at søge efter biblioteker, der behandler det problem, du arbejder med. Prøv at finde lignende løsninger. Mange af de biblioteker, der er tilgængelige på nettet, er gratis og er blevet finpudset og testet af erfarne udviklere og hele Java-community'et. Vær ikke bange for at bruge dem.
7. Ikke tid nok til at skrive test
Det er fristende at tro, at vores kode altid vil køre perfekt. Ikke at skrive test til kode er den værste synd i Java softwareudviklere. Mange af os foretrækker manuelle og udforskende tests i stedet for enhedstests, hvilket er skørt. Hvorfor spilde tid på at skrive tests, når du kan fokusere på at levere verdens bedste kode til dit projekt, som SLET ikke har nogen bugs?<joke>. Det viser sig, at virkeligheden er brutal, og vi kan ikke levere kode af høj kvalitet uden at skrive tests.
Hvordan kan jeg undgå det?
Du bør altid forberede tests til din kode. Jeg ved godt, at TDD-tilgangen ikke er så nem at vedligeholde, men du bør i det mindste lave tests, der dækker alle de situationer, hvor din kode kan køre. Det inkluderer test af ekstraordinære situationer. Unit-tests er nødvendige. Du er nødt til at lave dem for hver funktion i dit projekt, hvis du vil sikre dig, at din kode er nem at refaktorere og udvide i den videre udvikling.
En ting mere. Oprethold en høj standard for din testkode - det er det hele værd. Det er onkel Bobs råd, og jeg er helt enig i det.
Glem heller ikke andre typer af tests. Integrationstest er en ting, du bør overveje i alle dine projekter.
8. Glem alt om adgangsmodifikatorer
Privat og offentligt, ikke sandt? Hvordan kan vi glemme dem? Det viser sig, at der er flere. Da du først begyndte at lære Javahar du helt sikkert lært om beskyttede adgangsmodifikatorer. De kan være nyttige i nogle tilfælde, så det er værd at kende til deres eksistens.
Java-udviklere synes ofte at glemme pakkeomfanget. Det er let ikke at huske at bruge det, da det er implicit og ikke kræver nogen Java nøgleord. Pakkeomfanget er vigtigt. Det giver dig mulighed for at teste en beskyttet metode. Beskyttede elementer er tilgængelige fra testklassens sti, så længe pakken er den samme.
Hvordan kan jeg undgå det?
Husk den beskyttede modifikator, og at pakkens omfang giver dig mulighed for at teste den.
9. Brug af ren JavaEE i stedet for Spring
Det næste skridt efter læring Java SE er at lære at køre Java på servere, hvordan man laver en applikation på virksomhedsniveau.
Nybegyndere falder ofte i en fælde, når de skal lære JavaEE, da der findes et stort antal tutorials om det. Selv 'Thinking in Java', den Java-programmører' nævner JavaEE og siger ikke noget om de andre muligheder.
Hvordan kan jeg undgå det?
JavaEE er en sang fra fortiden. I dag er Spring en go-to-ting, og Java EE er bare rart at have. Alle moderne applikationer på virksomhedsniveau bruger Spring, så du bør kraftigt overveje at lære det her.