// null_safety.groovy — ?., ?:, safe indexing and avoiding NullPointerException. def order = [id: 'PO-1', customer: [name: 'Acme', address: null]] // Safe navigation: stop at null instead of throwing println order.customer?.address?.city // null (no exception) println order.shipTo?.name // null: missing key // Elvis: a default when the value is null or "false" println order.customer?.address?.city ?: 'no city' // Elvis assignment (Groovy 3+) def note = null note ?= 'default note' println note // Safe index on lists and maps def items = null println items?[0] // null println items?.size() ?: 0 // 0 // with a chain of calls def email = ' AP@ACME.TEST ' println email?.trim()?.toLowerCase() // Empty collections are safe to iterate def lines = order.lines ?: [] lines.each { println it } // prints nothing println "lines: ${lines.size()}" // Asserting non-null with a helpful message def requireId(Map o) { Objects.requireNonNull(o?.id, 'order id is required') } try { requireId([:]) } catch (NullPointerException e) { println "Caught: ${e.message}" }