Slide 1

Slide 1 text

TWELVE TIPS FOR WRITING MORE READABLE JAVA CODE With Jeanne Boyarsky & Ken Fogel Slides available after the presentation at https://speakerdeck.com/boyarsky @jeanneboyarsky @omniprof

Slide 2

Slide 2 text

Who are we Jeanne Boyarsky • Java Champion • Java Author • Developer in NYC • @jeanneboyarsky Ken Fogel §Java Champion §JCP Executive Committee Member §Dawson College Research Scholar in Residence §@omniprof @jeanneboyarsky @omniprof

Slide 3

Slide 3 text

NAMING STUFF IN JAVA Classes, Interfaces, Records, Enums, Methods and Variables, oh my. @jeanneboyarsky @omniprof

Slide 4

Slide 4 text

It’s a bird, it’s a plane, its § A noun § Variables, Enum, Interface, Class, Record § A verb § Methods § All capitals § Constants § Not containing a dollar sign $ § Not an abbreviation, except for maybe WTF § In camel case when a phrase @jeanneboyarsky @omniprof

Slide 5

Slide 5 text

THERE IS NOTHING IN THE REAL WORLD NAMED X, Y, OR Z It’s programming and not algebra. @jeanneboyarsky @omniprof

Slide 6

Slide 6 text

var f = "jeanne"; var l = "boyarsky"; var s = f + l; System.out.println(s.length()); @jeanneboyarsky @omniprof

Slide 7

Slide 7 text

var firstName = "jeanne"; var lastName = "boyarsky"; var fullName = firstName + lastName; System.out.println(fullName.length()); @jeanneboyarsky @omniprof

Slide 8

Slide 8 text

DON’T BE TOO CLEVER, THE PERSON WHO WILL REPLACE YOU ONCE YOU LEAVE MUST UNDERSTAND YOUR CODE. There is no award for code that works but which no one can figure out how. @jeanneboyarsky @omniprof

Slide 9

Slide 9 text

private BigDecimal loanCalculationTooClever(BigDecimal presentValue, BigDecimal annualPercentageRate, BigDecimal numberOfPayments) throws ArithmeticException { return presentValue.multiply(annualPercentageRate.divide( new BigDecimal("12"), MathContext.DECIMAL64). divide(BigDecimal.ONE.subtract(BigDecimal.ONE. add(annualPercentageRate.divide(new BigDecimal("12"), MathContext.DECIMAL64)).pow(-numberOfPayments.intValue(), MathContext.DECIMAL64 )), MathContext.DECIMAL64)).setScale(2, RoundingMode.HALF_EVEN); } @jeanneboyarsky @omniprof n rate rate PV PMT - + - ´ = ) 1 ( 1 Clever, compact, and unintelligible

Slide 10

Slide 10 text

private BigDecimal loanCalculationStepByStep(BigDecimal presentValue, BigDecimal annualPercentageRate, BigDecimal numberOfPayments) throws ArithmeticException { var ratePerPayment = annualPercentageRate.divide( new BigDecimal("12"), MathContext.DECIMAL64); var divisor = BigDecimal.ONE.add(ratePerPayment); divisor = divisor.pow(-numberOfPayments.intValueExact(), MathContext.DECIMAL64); divisor = BigDecimal.ONE.subtract(divisor); var result = ratePerPayment.divide(divisor, MathContext.DECIMAL64); result = presentValue.multiply(result); result = result.setScale(2, RoundingMode.HALF_EVEN); return result; } @jeanneboyarsky @omniprof Expressive and intelligible n rate rate PV PMT - + - ´ = ) 1 ( 1

Slide 11

Slide 11 text

CYCLOMATIC COMPLEXITY VERSUS K.I.S.S. You can make too many decisions. @jeanneboyarsky @omniprof

Slide 12

Slide 12 text

public int weird(int number) { var result=0; var random = new Random(); if (number % 2 == 0) { try { while (random.nextInt(3) % 2 != 0) result++; } catch (ArithmeticException e) { result = 0; } } else { result = 1; } return result; } @jeanneboyarsky @omniprof

Slide 13

Slide 13 text

public int weird(int number) { var result=0; if (number % 2 != 0) result = 1; else result = silly(result); return result; } @jeanneboyarsky @omniprof

Slide 14

Slide 14 text

private int silly(int result) { var random = new Random(); try { while (random.nextInt(3) % 2 != 0) { result++; } } catch (ArithmeticException e) { result = 0; } return result; } @jeanneboyarsky @omniprof

Slide 15

Slide 15 text

DON’T ABUSE STATIC Do you have a good reason for making anything static? Probably not. @jeanneboyarsky @omniprof

Slide 16

Slide 16 text

@jeanneboyarsky @omniprof public class BadPassLine { private static int Bankroll; private static int defaultBank; private static int bet; private static int win = 0; private static int lost = 0; private static int point; public static void main(String[] args){ . . . } public static int gamebegin() { . . . } public static void gamestart(){ . . . } public static int rollingDice(){ . . . } } After 3 Java courses, this is what a student submitted for a PassLine dice game as a warm-up assignment in their 4th Java course with me. Impress me, I said. This student depressed me.

Slide 17

Slide 17 text

IF IT DON’T FIT THE SCREEN, THEN MAYBE YOUR METHOD IS TOO LONG If it doesn’t fit on a screen, then it's too long. No turning the screen to portrait mode or use 6- point text. @jeanneboyarsky @omniprof

Slide 18

Slide 18 text

142: int userId = request.getIntParameter("user_id"); 143: int loggedInUserId = SessionFacade.getUserSession().getUserId(); 144: context.put("loggedInUserId", loggedInUserId); 145: context.put("isCurrentUser", userId == loggedInUserId); ... 12: 383: if (canListAllCows() || 384: (canGrantCows() && (userId == loggedInUserId))) { 385: CowsDao dao = DataAccessDriver.newCowsDao(); 386: List cows = dao.selectCowsByUser(userId); 387: prepCowsListPage(false, userId, cows); 388: } @jeanneboyarsky @omniprof

Slide 19

Slide 19 text

THE MAGIC NUMBER FOR A METHOD IS 1, THE NUMBER OF TASKS THE METHOD CARRIES OUT You may have many responsibilities in your day-to-day life, but your methods should only have a Single Responsibility. @jeanneboyarsky @omniprof

Slide 20

Slide 20 text

private static void playGame() { System.out.println(); int bet = 0; while (true) { System.out.println("\nYou have $" + currentCash); System.out.println("Insert a bet amount:"); if (reader.hasNextInt()) { bet = reader.nextInt(); if (!(checkIfInvalidBet(bet))) { break; } } else { System.out.println("You can only put whole numbers!"); } } Let’s play How Many Tasks Can You Find In This One Method?

Slide 21

Slide 21 text

if (bet != 0) { boolean victory; int point = 0; int total; while (true) { total = roll2Dice(); if (point == 0) { if (total == 7 || total == 11) { victory = true; break; } if (total == 2 || total == 3 || total == 12) { victory = false; break; } point = total; System.out.println("\nThe point is now " +point + "\n"); @jeanneboyarsky @omniprof

Slide 22

Slide 22 text

} else { if (total == 7) { victory = false; break; } if (total == point) { victory = true; break; } } } if (victory) { currentCash += bet; System.out.println(“You have won this round! \n"); } else { currentCash -= bet; System.out.println("Sorry, you lost this round! \n"); } } } @jeanneboyarsky @omniprof

Slide 23

Slide 23 text

THE STRING CLASS IS FULL OF POORLY AND BADLY NAMED METHODS. Use methods from a string whose name your boss could even understand. @jeanneboyarsky @omniprof

Slide 24

Slide 24 text

if (email.indexOf("@") != -1) { System.out.println( email.substring( email.indexOf("@") + 1)); } @jeanneboyarsky @omniprof

Slide 25

Slide 25 text

if (email.contains("@")) { System.out.println( email.replaceFirst("^.*@", "")); } @jeanneboyarsky @omniprof

Slide 26

Slide 26 text

if (email.contains("@")) { var startOfString = "^"; var anyChars = ".*"; var at = "@"; var regex = startOfString + anyChars + at; System.out.println( email.replaceFirst(regex, "")); } @jeanneboyarsky @omniprof

Slide 27

Slide 27 text

ROW, ROW, ROW YOUR CODE, GENTLY DOWN THE STREAM Collections and for loops should be like water and oil, don’t mix them. @jeanneboyarsky @omniprof

Slide 28

Slide 28 text

// Pre stream public OptionalInt max(List list) { if (list.isEmpty()) { return OptionalInt.empty(); } Collections.sort(list); int max = list.get(list.size()-1); return(OptionalInt.of(max)); } @jeanneboyarsky @omniprof // Post stream public OptionalInt maxStream(List list) { return list.stream().mapToInt(x -> x).max(); }

Slide 29

Slide 29 text

THE TIME HAS COME TO SAY GOODBYE TO CONCATENATION FOR LONG STRINGS. LONG LIVE TEXT BLOCKS! All rise JSON strings!. @jeanneboyarsky @omniprof

Slide 30

Slide 30 text

public String getJson(String search) { String json = "{" + " \"query\": \"%s\"" + " \"start\": \"1\"," + " \"end\": \"10\"" + "}"; return String.format(json, search); } @jeanneboyarsky @omniprof

Slide 31

Slide 31 text

public String getJson(String search) { Path path = Path.of( ""src/main/resources/query.json"); String json = null; try { json = Files.readString(path); } catch (IOException e) { throw new UncheckedIOException(e); } return String.format(json, search); } @jeanneboyarsky @omniprof

Slide 32

Slide 32 text

public String getJson(String search) { String json = """ { "query": "%s" "start": "1" "end": "10" }"""; return String.format(json, search); } @jeanneboyarsky @omniprof

Slide 33

Slide 33 text

THE TRADITIONAL SWITCH IS FROM THE 1950S. TIME TO CODE LIKE ITS 2022 Switch expression, Switch statement, Switch pattern matching. It is time to finally say goodbye to fall thru in the absence of a break. @jeanneboyarsky @omniprof

Slide 34

Slide 34 text

double value = 0; switch (point) { case NORTH: value = 12.12; break; case SOUTH: value = 14.14; break; case EAST: value = 16.16; break; case WEST: value = 18.18; break; } The 1950s just called and they want their switch back. @jeanneboyarsky @omniprof

Slide 35

Slide 35 text

// switch statement switch (point) { case NORTH -> doNorth(); case SOUTH -> doSouth(); case EAST -> { doEast(); doEastern(); } case WEST -> doWest(); default -> doLost(); }; // switch expression double value = switch (point) { case NORTH -> 12.12; case SOUTH -> 14.14; case EAST -> 16.16; case WEST -> 18.18; default -> 0.0; }; Now’s the time to say goodbye to break. @jeanneboyarsky @omniprof

Slide 36

Slide 36 text

Object value = 4; switch (value) { case null -> System.out.println("null"); case String s -> System.out.println("String"); case Integer i when i > 1 && i < 6 -> System.out.println("Integer"); default -> System.out.println("Something else"); } The future is the Pattern Matching Switch! @jeanneboyarsky @omniprof

Slide 37

Slide 37 text

WE NEED MORE RECORDS! Only teenage turtles should be mutable. @jeanneboyarsky @omniprof

Slide 38

Slide 38 text

public class Book { private String title; private String numPages; public Book(String title, String numPages) { super(); this.title = title; this.numPages = numPages; } public String getTitle() { return title; } public String getNumPages() { return numPages; } @jeanneboyarsky @omniprof

Slide 39

Slide 39 text

public record Book(String title, String numPages) { } Book book = new Book( "Breaking and entering", 289); System.out.println(book.title()); System.out.println(book.toString()); @jeanneboyarsky @omniprof

Slide 40

Slide 40 text

Automatically get • final record • private final instance variables • public accessors • constructor taking both fields • equals • hashCode • toString @jeanneboyarsky @omniprof

Slide 41

Slide 41 text

FOR MORE This deck – on Speakerdeck shortly New Java features - https://speakerdeck.com/boyarsky/2022-java17-refactoring New Java features - https://speakerdeck.com/boyarsky/2022-devnexus-java12-17 @jeanneboyarsky @omniprof

Slide 42

Slide 42 text

BOOK GIVEAWAY! @jeanneboyarsky @omniprof