[{"data":1,"prerenderedAt":36680},["ShallowReactive",2],{"section-lessons-troubleshooting":3},[4,60,575,1048,1439,1669,2078,2404,2618,3042,3323,3530,3760,4311,4548,4825,5059,5373,5531,5683,6569,6683,6916,7443,7700,7961,8400,8728,9463,9772,10137,10602,11053,11464,11990,12324,12932,13265,13509,14081,14381,14725,15179,15488,15847,16495,17036,17897,18455,18602,19721,20415,20818,21332,21637,22400,22859,23231,23560,24095,24837,25726,26098,26775,27399,28255,28838,29217,30070,30605,31023,31563,32068,33108,33715,33938,34088,34625,35077,35376,35925,35955,35980,36005,36030,36055,36080,36105,36130,36155,36180,36205,36230,36255,36280,36305,36330,36355,36380,36405,36430,36455,36480,36505,36530,36555,36580,36605,36630,36655],{"id":5,"title":6,"body":7,"description":17,"extension":51,"meta":52,"navigation":55,"path":56,"seo":57,"stem":58,"__hash__":59},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch01-why-java-for-frc\u002F1.1-why-java-for-frc.md","Why Java for FRC?",{"type":8,"value":9,"toc":47},"minimark",[10,14,18],[11,12,6],"h1",{"id":13},"why-java-for-frc",[15,16,17],"p",{},"Java is one of the most popular languages in the world, and the standard for most FRC teams.",[19,20,21,29,35,41],"ul",{},[22,23,24,28],"li",{},[25,26,27],"strong",{},"Static Typing:"," Catch errors at compile-time before they reach the robot.",[22,30,31,34],{},[25,32,33],{},"Object-Oriented:"," Perfect for modeling physical systems like motors and sensors.",[22,36,37,40],{},[25,38,39],{},"Performance:"," The JVM (Java Virtual Machine) is fast enough for real-time control loops.",[22,42,43,46],{},[25,44,45],{},"Ecosystem:"," Access to WPILib, thousands of libraries, and years of documentation.",{"title":48,"searchDepth":49,"depth":49,"links":50},"",2,[],"md",{"outlineRef":53,"status":54},"1.1 — Why Java for FRC?","existing — deck's original motivational slide, pulled verbatim. Intro only — no exercise, no CSA source; 1.2 is where the real lesson content starts.",true,"\u002Fshockwave-curriculum\u002Flessons\u002Fch01-why-java-for-frc\u002F1-why-java-for-frc",{"title":6,"description":17},"shockwave-curriculum\u002Flessons\u002Fch01-why-java-for-frc\u002F1.1-why-java-for-frc","BUSgek9NWwnfapsWxxhcfsj7bzHRV2q-TYfyDERCsMY",{"id":61,"title":62,"body":63,"description":48,"extension":51,"meta":568,"navigation":55,"path":571,"seo":572,"stem":573,"__hash__":574},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch01-why-java-for-frc\u002F1.2-intro-to-algorithms-programming-and-compilers.md","Intro to Algorithms, Programming and Compilers",{"type":8,"value":64,"toc":557},[65,68,73,80,87,91,103,154,185,208,225,229,240,249,252,266,270,280,283,310,313,317,333,336,383,397,401,423,430,434,444,459,463,498,502,542,553],[11,66,62],{"id":67},"intro-to-algorithms-programming-and-compilers",[69,70,72],"h2",{"id":71},"algorithms","Algorithms",[15,74,75,76,79],{},"An algorithm is just a set of ordered steps to solve a problem — a recipe, directions to a house, and a Java program are all algorithms. Steps run in order, one at a time — this is called ",[25,77,78],{},"sequencing",".",[15,81,82,83,86],{},"Before writing real code, it helps to plan the steps first: in plain English, a diagram, or ",[25,84,85],{},"pseudocode"," (simplified fake-code written on paper, not run by anything). Getting the steps straight on paper first is what turns a half-formed idea into code that actually works.",[69,88,90],{"id":89},"your-first-java-program","Your First Java Program",[15,92,93,94,98,99,102],{},"Every Java program lives inside a ",[95,96,97],"code",{},"class",", and every class you run needs a ",[95,100,101],{},"main"," method — that's where the program starts running.",[104,105,109],"pre",{"className":106,"code":107,"language":108,"meta":48,"style":48},"language-java shiki shiki-themes github-light github-dark","public class MyClass\n{\n    public static void main(String[] args)\n    {\n        System.out.println(\"Hi there!\");\n    }\n}\n","java",[95,110,111,119,124,130,136,142,148],{"__ignoreMap":48},[112,113,116],"span",{"class":114,"line":115},"line",1,[112,117,118],{},"public class MyClass\n",[112,120,121],{"class":114,"line":49},[112,122,123],{},"{\n",[112,125,127],{"class":114,"line":126},3,[112,128,129],{},"    public static void main(String[] args)\n",[112,131,133],{"class":114,"line":132},4,[112,134,135],{},"    {\n",[112,137,139],{"class":114,"line":138},5,[112,140,141],{},"        System.out.println(\"Hi there!\");\n",[112,143,145],{"class":114,"line":144},6,[112,146,147],{},"    }\n",[112,149,151],{"class":114,"line":150},7,[112,152,153],{},"}\n",[15,155,156,157,160,161,164,165,168,169,172,173,176,177,180,181,184],{},"Every open curly brace ",[95,158,159],{},"{"," needs a matching close ",[95,162,163],{},"}",". Each word in ",[95,166,167],{},"public static void main(String[] args)"," gets its own full explanation later — ",[95,170,171],{},"String[] args"," in Ch.4, ",[95,174,175],{},"public","\u002F",[95,178,179],{},"static"," more fully in Ch.7, where ",[95,182,183],{},"void"," fits among method return types in Ch.9 — for now, treat the whole line as fixed boilerplate every program starts with.",[15,186,187,188,191,192,195,196,199,200,203,204,207],{},"When you compile normally (",[95,189,190],{},"javac",", or most IDEs), the file has to be named the same as its ",[95,193,194],{},"public class"," — ",[95,197,198],{},"MyClass.java"," for ",[95,201,202],{},"public class MyClass",". Running a single file directly with ",[95,205,206],{},"java MyClass.java"," doesn't enforce this, but matching the names is still the habit to build.",[15,209,210,213,214,217,218,220,221,224],{},[25,211,212],{},"On Java 25:"," you may also see an even shorter ",[95,215,216],{},"void main() { ... }"," with no ",[95,219,97],{}," and no ",[95,222,223],{},"public static"," — a newer shortcut for quick scripts (JEP 512). This course always uses the full form shown above, since it works unchanged on Java 17 too.",[69,226,228],{"id":227},"every-statement-ends-with-a-semicolon","Every Statement Ends With a Semicolon",[15,230,231,232,235,236,239],{},"Each individual instruction is a ",[25,233,234],{},"statement",", and every statement ends with ",[95,237,238],{},";"," — think of it like a period ending a sentence.",[104,241,243],{"className":106,"code":242,"language":108,"meta":48,"style":48},"System.out.println(\"Hi there!\");\n",[95,244,245],{"__ignoreMap":48},[112,246,247],{"class":114,"line":115},[112,248,242],{},[15,250,251],{},"Miss it, and the program won't compile. This is one of the most common mistakes when you're starting out — expect it, don't stress about it.",[15,253,254,255,257,258,260,261,263,264,79],{},"Not everything ends in ",[95,256,238],{},". A line that opens a block, like the ",[95,259,97],{}," or ",[95,262,101],{}," line above, has no semicolon before its ",[95,265,159],{},[69,267,269],{"id":268},"compiling-how-your-code-actually-runs","Compiling: How Your Code Actually Runs",[15,271,272,273,276,277,79],{},"Computers don't understand Java directly. A ",[25,274,275],{},"compiler"," checks your code for mistakes and translates it into something the computer can run. If it finds a mistake, it stops and tells you — that's a ",[25,278,279],{},"syntax error",[15,281,282],{},"For this course, you have two ways to write and run your code:",[19,284,285,299],{},[22,286,287,290,291,298],{},[25,288,289],{},"Use your own IDE",", like ",[292,293,297],"a",{"href":294,"rel":295},"https:\u002F\u002Fcode.visualstudio.com\u002F",[296],"nofollow","VS Code"," with the Java extension — genuinely how most FRC teams write real robot code, so it's good practice either way.",[22,300,301,290,304,309],{},[25,302,303],{},"Use an online IDE",[292,305,308],{"href":306,"rel":307},"https:\u002F\u002Freplit.com\u002F",[296],"Replit",", if you don't want to install anything yet.",[15,311,312],{},"Write and run your code in one of those to see it actually work. This lesson's own exercises are multiple-choice and reorder (Micro-Parsons) puzzles, so you don't need to submit code anywhere to complete them — a text-submit coding checker, for later chapters, is still being built.",[69,314,316],{"id":315},"keywords-and-naming","Keywords and Naming",[15,318,319,320,322,323,325,326,328,329,332],{},"Words like ",[95,321,175],{},", ",[95,324,97],{},", and ",[95,327,183],{}," are ",[25,330,331],{},"keywords"," — reserved words with a fixed meaning in Java. Keywords are always lowercase.",[15,334,335],{},"Everything else — every name you pick yourself — follows one of three styles:",[19,337,338,350,366],{},[22,339,340,343,344,322,347,79],{},[25,341,342],{},"lowerCamelCase"," — variables and methods start lowercase, then capitalize each new word: ",[95,345,346],{},"motorSpeed",[95,348,349],{},"calculateTotal()",[22,351,352,355,356,322,359,362,363,79],{},[25,353,354],{},"PascalCase"," (also called UpperCamelCase) — classes and interfaces capitalize every word, including the first: ",[95,357,358],{},"System",[95,360,361],{},"String",", or a class you write yourself like ",[95,364,365],{},"Drivetrain",[22,367,368,371,372,322,375,378,379,382],{},[25,369,370],{},"SCREAMING_SNAKE_CASE"," — constants (values that never change) are all uppercase with underscores between words: ",[95,373,374],{},"MAX_SPEED",[95,376,377],{},"PI",". You'll meet real constants starting in Ch.7.4; ",[95,380,381],{},"final",", what actually makes a value a constant, gets full treatment in Ch.23.",[15,384,385,386,389,390,392,393,396],{},"That's why ",[95,387,388],{},"System.out.println(...)"," looks the way it does: ",[95,391,358],{}," is a class, so it's PascalCase. ",[95,394,395],{},"println"," is a method — here it's just one word, so there's no second word to capitalize, but it still starts lowercase like every method name does.",[69,398,400],{"id":399},"syntax-errors-vs-run-time-errors","Syntax Errors vs. Run-Time Errors",[19,402,403,417],{},[22,404,405,406,408,409,411,412,260,414,79],{},"A ",[25,407,279],{}," is caught by the compiler, before your program ever runs — a missing ",[95,410,238],{},", an unmatched ",[95,413,159],{},[95,415,416],{},"\"",[22,418,405,419,422],{},[25,420,421],{},"run-time error"," happens while the program is running, after it already compiled — like dividing a whole number by zero.",[15,424,425,426,429],{},"Both are normal. Finding and fixing errors is called ",[25,427,428],{},"debugging"," — informally, an error is a \"bug.\" If you're stuck, explaining your code line-by-line out loud — even to an inanimate object, a real technique called \"rubber duck debugging\" — often reveals the problem before you finish explaining it.",[69,431,433],{"id":432},"comments","Comments",[15,435,436,439,440,443],{},[95,437,438],{},"\u002F\u002F"," starts a comment that runs to the end of the line; ",[95,441,442],{},"\u002F* ... *\u002F"," comments out everything in between, even across multiple lines. The compiler ignores comments completely — they exist to explain your code to yourself and your teammates.",[104,445,447],{"className":106,"code":446,"language":108,"meta":48,"style":48},"\u002F\u002F this line is ignored by the compiler\nSystem.out.println(\"Hi there!\"); \u002F\u002F so is this part, after the \u002F\u002F\n",[95,448,449,454],{"__ignoreMap":48},[112,450,451],{"class":114,"line":115},[112,452,453],{},"\u002F\u002F this line is ignored by the compiler\n",[112,455,456],{"class":114,"line":49},[112,457,458],{},"System.out.println(\"Hi there!\"); \u002F\u002F so is this part, after the \u002F\u002F\n",[69,460,462],{"id":461},"common-pitfalls","Common Pitfalls",[19,464,465,471,487],{},[22,466,467,470],{},[25,468,469],{},"Missing a semicolon."," The single most common first error — check the end of the line the compiler points at, and the line just before it.",[22,472,473,476,477,479,480,322,482,322,484,486],{},[25,474,475],{},"Mismatched capitalization."," ",[95,478,358],{}," is capitalized (it's a class); ",[95,481,175],{},[95,483,97],{},[95,485,183],{}," are not (they're keywords). Java is case-sensitive everywhere.",[22,488,489,492,493,497],{},[25,490,491],{},"Trusting the error's line number completely."," The compiler tells you where it ",[494,495,496],"em",{},"noticed"," the problem, which is sometimes a line or two after where the actual mistake is.",[69,499,501],{"id":500},"key-takeaways","Key Takeaways",[19,503,504,507,510,519,524,527,530,533],{},[22,505,506],{},"An algorithm is an ordered set of steps, run one at a time (sequencing) — you already use these outside of code.",[22,508,509],{},"Planning steps in plain English or pseudocode before coding turns a half-formed idea into working code.",[22,511,512,513,515,516,518],{},"Every Java program has a ",[95,514,97],{},", and a ",[95,517,101],{}," method where it starts running.",[22,520,521,522,79],{},"Every statement ends with ",[95,523,238],{},[22,525,526],{},"Three naming styles: lowerCamelCase (variables\u002Fmethods), PascalCase (classes\u002Finterfaces), SCREAMING_SNAKE_CASE (constants).",[22,528,529],{},"A compiler checks your code and translates it to run; a syntax error is a mistake it catches before your program ever runs.",[22,531,532],{},"Write and run code in a real IDE (like VS Code) or an online one; this lesson's exercises are multiple-choice and reorder puzzles, not a code checker.",[22,534,535,537,538,541],{},[95,536,438],{}," and ",[95,539,540],{},"\u002F* *\u002F"," are comments — the compiler ignores them completely.",[15,543,544,545,548,549,552],{},"Derived from ",[95,546,547],{},"csawesome-2026",": ",[95,550,551],{},"unit-1-using-objects-and-methods\u002F1.01-introduction-to-algorithms-programming-and-compilers.md"," (CSA 1.1)",[554,555,556],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":48,"searchDepth":49,"depth":49,"links":558},[559,560,561,562,563,564,565,566,567],{"id":71,"depth":49,"text":72},{"id":89,"depth":49,"text":90},{"id":227,"depth":49,"text":228},{"id":268,"depth":49,"text":269},{"id":315,"depth":49,"text":316},{"id":399,"depth":49,"text":400},{"id":432,"depth":49,"text":433},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":569,"status":570},"1.2 — Intro to Algorithms, Programming and Compilers (CSA 1.1)","new — authored lesson (fuller depth than the teaser slide)","\u002Fshockwave-curriculum\u002Flessons\u002Fch01-why-java-for-frc\u002F2-intro-to-algorithms-programming-and-compilers",{"title":62,"description":48},"shockwave-curriculum\u002Flessons\u002Fch01-why-java-for-frc\u002F1.2-intro-to-algorithms-programming-and-compilers","vzGueAT-iaSXnqLjkwEvhQMYs4qGSQ0Hm5xaO-kVGBk",{"id":576,"title":577,"body":578,"description":48,"extension":51,"meta":1042,"navigation":55,"path":1044,"seo":1045,"stem":1046,"__hash__":1047},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.1-variables-and-data-types.md","Variables & Data Types",{"type":8,"value":579,"toc":1034},[580,583,587,594,597,665,668,695,714,718,721,730,739,748,765,768,777,790,797,801,824,839,854,861,874,878,913,915,970,972,1024,1032],[11,581,577],{"id":582},"variables-data-types",[69,584,586],{"id":585},"primitive-types-a-small-fixed-list","Primitive Types: a Small, Fixed List",[15,588,589,590,593],{},"Java has exactly 8 ",[25,591,592],{},"primitive types"," — the only types built directly into the language. A primitive variable holds its value directly, with nothing more underneath it.",[15,595,596],{},"The ones you'll use constantly in FRC code:",[19,598,599,612,627,637,653],{},[22,600,601,604,605,260,608,611],{},[95,602,603],{},"int"," — a whole number, like ",[95,606,607],{},"5",[95,609,610],{},"-12",". CAN IDs, ports, loop counters.",[22,613,614,617,618,620,621,548,624,79],{},[95,615,616],{},"long"," — a bigger whole number, for values too large for ",[95,619,603],{}," (like a timestamp). Written with an ",[95,622,623],{},"L",[95,625,626],{},"100L",[22,628,629,632,633,636],{},[95,630,631],{},"double"," — a decimal number, like ",[95,634,635],{},"0.85",". Almost anything measured — speed, distance, voltage.",[22,638,639,642,643,548,646,649,650,652],{},[95,640,641],{},"float"," — a smaller, less precise decimal number. Written with an ",[95,644,645],{},"f",[95,647,648],{},"1.5f",". Most FRC code (including WPILib itself) prefers ",[95,651,631],{}," instead.",[22,654,655,658,659,260,662,79],{},[95,656,657],{},"boolean"," — only ever ",[95,660,661],{},"true",[95,663,664],{},"false",[15,666,667],{},"The rest exist too, but you'll rarely reach for them directly:",[19,669,670,682],{},[22,671,672,322,675,678,679,681],{},[95,673,674],{},"byte",[95,676,677],{},"short"," — smaller whole numbers than ",[95,680,603],{},". Rarely needed.",[22,683,684,687,688,691,692,694],{},[95,685,686],{},"char"," — one single character, like ",[95,689,690],{},"'A'",". You won't use this much on its own, but it's worth knowing: this is what ",[95,693,361],{}," is actually built from underneath.",[15,696,697,698,701,702,704,705,707,708,710,711,713],{},"That's the full list — nothing else in Java is a primitive. ",[25,699,700],{},"Everything else is built out of these 8"," (or references to objects built out of them), most obviously ",[95,703,361],{},", which conceptually is a sequence of ",[95,706,686],{},"s glued together. Later, when you write your own classes (starting in Ch.7), those will be built by bundling primitives together — a robot subsystem might combine a ",[95,709,631],{}," for speed, a ",[95,712,657],{}," for \"is it ready,\" and more, all wrapped into one object. Keep this in the back of your mind going forward: every new type you meet is either one of this fixed list, or something built on top of it.",[69,715,717],{"id":716},"declaring-and-assigning","Declaring and Assigning",[15,719,720],{},"To create a variable, write its type, then its name, then a semicolon:",[104,722,724],{"className":106,"code":723,"language":108,"meta":48,"style":48},"int motorSpeed;\n",[95,725,726],{"__ignoreMap":48},[112,727,728],{"class":114,"line":115},[112,729,723],{},[15,731,732,734,735,738],{},[95,733,346],{}," now exists, but it doesn't hold a value yet. Give it one with ",[95,736,737],{},"=",":",[104,740,742],{"className":106,"code":741,"language":108,"meta":48,"style":48},"motorSpeed = 5;\n",[95,743,744],{"__ignoreMap":48},[112,745,746],{"class":114,"line":115},[112,747,741],{},[15,749,750,751,758,759,761,762,764],{},"Read that line as: ",[25,752,753,755,756,79],{},[95,754,346],{}," gets assigned the value ",[95,757,607],{}," Not \"motorSpeed equals 5\" — ",[95,760,737],{}," in code isn't the same as ",[95,763,737],{}," in math class. It's an instruction: take what's on the right, and store it in the box on the left.",[15,766,767],{},"Usually you do both steps at once:",[104,769,771],{"className":106,"code":770,"language":108,"meta":48,"style":48},"int motorSpeed = 5;\n",[95,772,773],{"__ignoreMap":48},[112,774,775],{"class":114,"line":115},[112,776,770],{},[15,778,779,780],{},"Read this the same way: ",[25,781,782,784,785,787,788,79],{},[95,783,346],{},", of type ",[95,786,603],{},", is assigned the value ",[95,789,607],{},[15,791,792,793,796],{},"A variable declared inside a method body, like everything here, is called a ",[25,794,795],{},"local variable"," — it only exists inside that method. (Java has other kinds of variables too — you'll meet those once classes and methods are on the table, starting in Ch.7.)",[69,798,800],{"id":799},"naming-variables-camelcase","Naming Variables (camelCase)",[15,802,803,804,537,807,810,811,814,815,260,817,819,820,823],{},"A name must start with a letter (",[95,805,806],{},"_",[95,808,809],{},"$"," are technically allowed too, but not digits), can't contain spaces, and can't be a ",[25,812,813],{},"keyword"," — a reserved word like ",[95,816,603],{},[95,818,97],{}," that already means something fixed to Java. Java's style — you'll see this in every piece of code from here on — is ",[25,821,822],{},"camelCase",": start lowercase, then capitalize the first letter of each new word.",[104,825,827],{"className":106,"code":826,"language":108,"meta":48,"style":48},"double maxSpeed = 0.85;   \u002F\u002F not max_speed, not MaxSpeed\nboolean isReady = false;\n",[95,828,829,834],{"__ignoreMap":48},[112,830,831],{"class":114,"line":115},[112,832,833],{},"double maxSpeed = 0.85;   \u002F\u002F not max_speed, not MaxSpeed\n",[112,835,836],{"class":114,"line":49},[112,837,838],{},"boolean isReady = false;\n",[15,840,841,842,845,846,849,850,853],{},"Pick a name that says what the value ",[494,843,844],{},"is",". ",[95,847,848],{},"speed"," tells you something; ",[95,851,852],{},"x"," doesn't.",[15,855,856,857,860],{},"You can declare more than one variable of the same type in a single statement, separated by commas: ",[95,858,859],{},"int wins = 0, losses = 0;",". It's legal, but one variable per line (as everywhere else in this course) is easier to read — you'll mostly see the combined form in other people's code.",[15,862,863],{},[494,864,865,866,869,870,873],{},"Aside: modern Java also lets you write ",[95,867,868],{},"var motorSpeed = 5;"," and have the compiler figure out the type from the value. This course always spells out the type instead, since seeing it is part of learning what it is — but you'll see ",[95,871,872],{},"var"," in real-world code.",[69,875,877],{"id":876},"worked-example","Worked Example",[104,879,881],{"className":106,"code":880,"language":108,"meta":48,"style":48},"int motorSpeed = 5;         \u002F\u002F a whole number — no decimal needed here\ndouble maxOutput = 0.85;    \u002F\u002F a percentage like 85% — needs a decimal\nboolean isReady = false;    \u002F\u002F only ever true or false\nString robotName = \"Titan\"; \u002F\u002F text, built out of primitives under the hood\n\nSystem.out.println(\"Robot \" + robotName + \" is set to speed \" + motorSpeed);\n",[95,882,883,888,893,898,903,908],{"__ignoreMap":48},[112,884,885],{"class":114,"line":115},[112,886,887],{},"int motorSpeed = 5;         \u002F\u002F a whole number — no decimal needed here\n",[112,889,890],{"class":114,"line":49},[112,891,892],{},"double maxOutput = 0.85;    \u002F\u002F a percentage like 85% — needs a decimal\n",[112,894,895],{"class":114,"line":126},[112,896,897],{},"boolean isReady = false;    \u002F\u002F only ever true or false\n",[112,899,900],{"class":114,"line":132},[112,901,902],{},"String robotName = \"Titan\"; \u002F\u002F text, built out of primitives under the hood\n",[112,904,905],{"class":114,"line":138},[112,906,907],{"emptyLinePlaceholder":55},"\n",[112,909,910],{"class":114,"line":144},[112,911,912],{},"System.out.println(\"Robot \" + robotName + \" is set to speed \" + motorSpeed);\n",[69,914,462],{"id":461},[19,916,917,936,951],{},[22,918,919,476,922,925,926,928,929,932,933,79],{},[25,920,921],{},"Never put a variable's name inside quotes.",[95,923,924],{},"System.out.println(\"motorSpeed\")"," prints the literal word ",[95,927,346],{},", not the number stored in it. Only actual words\u002Fsentences go inside ",[95,930,931],{},"\"\"","; variables get attached with ",[95,934,935],{},"+",[22,937,938,476,941,537,943,946,947,950],{},[25,939,940],{},"Case matters.",[95,942,346],{},[95,944,945],{},"motorspeed"," are two different variables to Java. Mistype one and you'll usually get a ",[95,948,949],{},"cannot find symbol"," error — but if both names happen to exist, Java quietly uses the wrong one, with no error at all.",[22,952,953,956,957,959,960,962,963,965,966,969],{},[25,954,955],{},"Match the type to the value."," If a value has a decimal point, it needs ",[95,958,631],{},", not ",[95,961,603],{}," — a decimal value in an ",[95,964,603],{}," variable won't compile (\"possible lossy conversion\"); only an explicit ",[95,967,968],{},"(int)"," cast (covered in 2.4) cuts off the decimal.",[69,971,501],{"id":500},[19,973,974,995,1007,1010,1015,1021],{},[22,975,976,977,322,979,322,981,322,983,322,985,987,988,322,990,322,992,994],{},"Java has exactly 8 primitive types. ",[95,978,603],{},[95,980,616],{},[95,982,631],{},[95,984,641],{},[95,986,657],{}," are the common ones in FRC code; ",[95,989,674],{},[95,991,677],{},[95,993,686],{}," exist but are rarely used directly.",[22,996,997,998,1000,1001,1003,1004,1006],{},"Everything else (",[95,999,361],{},", and every class you'll write) is built out of these 8 — ",[95,1002,361],{}," is a sequence of ",[95,1005,686],{},"s.",[22,1008,1009],{},"A variable is a named box that holds a value, and that value can change.",[22,1011,1012,1014],{},[95,1013,737],{}," means \"gets assigned,\" not \"equals.\"",[22,1016,1017,1018,1020],{},"A variable declared inside a method is a ",[25,1019,795],{}," — it only exists in that method. There are other kinds too, covered starting in Ch.7.",[22,1022,1023],{},"Variable names use camelCase and should describe what the value is.",[15,1025,544,1026,548,1028,1031],{},[95,1027,547],{},[95,1029,1030],{},"unit-1-using-objects-and-methods\u002F1.02-variables-and-data-types.md"," (CSA 1.2)",[554,1033,556],{},{"title":48,"searchDepth":49,"depth":49,"links":1035},[1036,1037,1038,1039,1040,1041],{"id":585,"depth":49,"text":586},{"id":716,"depth":49,"text":717},{"id":799,"depth":49,"text":800},{"id":876,"depth":49,"text":877},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":1043,"status":570},"2.1 — Variables and Data Types (CSA 1.2)","\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F1-variables-and-data-types",{"title":577,"description":48},"shockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.1-variables-and-data-types","7XezYC_sk0QmY5xlLPqoLh9qS3a4KiNXI8b3Oa024Fg",{"id":1049,"title":1050,"body":1051,"description":48,"extension":51,"meta":1433,"navigation":55,"path":1435,"seo":1436,"stem":1437,"__hash__":1438},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.2-expressions-and-output.md","Expressions & Output",{"type":8,"value":1052,"toc":1422},[1053,1056,1060,1063,1077,1097,1103,1115,1130,1136,1151,1160,1186,1201,1205,1214,1223,1232,1241,1245,1260,1275,1283,1296,1321,1345,1347,1378,1380,1412,1420],[11,1054,1050],{"id":1055},"expressions-output",[69,1057,1059],{"id":1058},"printing-output","Printing Output",[15,1061,1062],{},"Two ways to print in Java:",[19,1064,1065,1071],{},[22,1066,1067,1070],{},[95,1068,1069],{},"System.out.println(value)"," — prints, then moves to a new line.",[22,1072,1073,1076],{},[95,1074,1075],{},"System.out.print(value)"," — prints, and stays on the same line.",[104,1078,1080],{"className":106,"code":1079,"language":108,"meta":48,"style":48},"System.out.print(\"Score: \");\nSystem.out.println(24);\n\u002F\u002F Output: Score: 24\n",[95,1081,1082,1087,1092],{"__ignoreMap":48},[112,1083,1084],{"class":114,"line":115},[112,1085,1086],{},"System.out.print(\"Score: \");\n",[112,1088,1089],{"class":114,"line":49},[112,1090,1091],{},"System.out.println(24);\n",[112,1093,1094],{"class":114,"line":126},[112,1095,1096],{},"\u002F\u002F Output: Score: 24\n",[69,1098,1100,1101],{"id":1099},"joining-text-and-values-with","Joining Text and Values With ",[95,1102,935],{},[15,1104,1105,1107,1108,1110,1111,1114],{},[95,1106,935],{}," doesn't just add numbers — between a ",[95,1109,361],{}," and anything else, it ",[25,1112,1113],{},"joins them into one longer piece of text"," instead:",[104,1116,1118],{"className":106,"code":1117,"language":108,"meta":48,"style":48},"int score = 24;\nSystem.out.println(\"Score: \" + score); \u002F\u002F Score: 24\n",[95,1119,1120,1125],{"__ignoreMap":48},[112,1121,1122],{"class":114,"line":115},[112,1123,1124],{},"int score = 24;\n",[112,1126,1127],{"class":114,"line":49},[112,1128,1129],{},"System.out.println(\"Score: \" + score); \u002F\u002F Score: 24\n",[15,1131,1132,1133,1135],{},"Every worked example so far has been doing this already. The catch: ",[95,1134,935],{}," still runs left to right, so where the text shows up in the expression changes the result:",[104,1137,1139],{"className":106,"code":1138,"language":108,"meta":48,"style":48},"System.out.println(\"a\" + 1 + 2); \u002F\u002F a12 — \"a\"+1 makes \"a1\" (text), then +2 makes \"a12\" (text)\nSystem.out.println(1 + 2 + \"a\"); \u002F\u002F 3a  — 1+2 makes 3 (math) first, then +\"a\" makes \"3a\" (text)\n",[95,1140,1141,1146],{"__ignoreMap":48},[112,1142,1143],{"class":114,"line":115},[112,1144,1145],{},"System.out.println(\"a\" + 1 + 2); \u002F\u002F a12 — \"a\"+1 makes \"a1\" (text), then +2 makes \"a12\" (text)\n",[112,1147,1148],{"class":114,"line":49},[112,1149,1150],{},"System.out.println(1 + 2 + \"a\"); \u002F\u002F 3a  — 1+2 makes 3 (math) first, then +\"a\" makes \"3a\" (text)\n",[15,1152,1153,1154,1156,1157,1159],{},"Once a ",[95,1155,935],{}," touches a ",[95,1158,361],{},", everything after it becomes text-joining, left to right — there's no going back to math mode later in the same line.",[15,1161,1162,1163,1165,1166,1169,1170,1173,1174,1177,1178,1181,1182,1185],{},"Text inside ",[95,1164,931],{}," can also contain ",[25,1167,1168],{},"escape sequences"," — a backslash followed by a letter, meaning something other than a literal character: ",[95,1171,1172],{},"\\n"," (new line), ",[95,1175,1176],{},"\\t"," (tab), ",[95,1179,1180],{},"\\\""," (a literal quote mark inside the text), and ",[95,1183,1184],{},"\\\\"," (a literal backslash).",[104,1187,1189],{"className":106,"code":1188,"language":108,"meta":48,"style":48},"System.out.println(\"Line one\\nLine two\"); \u002F\u002F prints on two separate lines\nSystem.out.println(\"She said \\\"go\\\"\");    \u002F\u002F She said \"go\"\n",[95,1190,1191,1196],{"__ignoreMap":48},[112,1192,1193],{"class":114,"line":115},[112,1194,1195],{},"System.out.println(\"Line one\\nLine two\"); \u002F\u002F prints on two separate lines\n",[112,1197,1198],{"class":114,"line":49},[112,1199,1200],{},"System.out.println(\"She said \\\"go\\\"\");    \u002F\u002F She said \"go\"\n",[69,1202,1204],{"id":1203},"math-expressions","Math Expressions",[15,1206,1207,1210,1211],{},[95,1208,1209],{},"+ - * \u002F"," work the same way you'd expect, with one big exception: ",[25,1212,1213],{},"dividing two whole numbers throws away the decimal part.",[104,1215,1217],{"className":106,"code":1216,"language":108,"meta":48,"style":48},"System.out.println(7 \u002F 2); \u002F\u002F prints 3, not 3.5\n",[95,1218,1219],{"__ignoreMap":48},[112,1220,1221],{"class":114,"line":115},[112,1222,1216],{},[15,1224,1225,1226,1229,1230,738],{},"This is called ",[25,1227,1228],{},"truncating division",", and it's the single most common source of \"wrong answer, no error message\" bugs you'll run into. If you want the decimal part, at least one of the two numbers needs to be a ",[95,1231,631],{},[104,1233,1235],{"className":106,"code":1234,"language":108,"meta":48,"style":48},"System.out.println(7.0 \u002F 2); \u002F\u002F prints 3.5\n",[95,1236,1237],{"__ignoreMap":48},[112,1238,1239],{"class":114,"line":115},[112,1240,1234],{},[69,1242,1244],{"id":1243},"order-of-operations","Order of Operations",[15,1246,1247,1248,537,1251,1253,1254,537,1256,1259],{},"Same rules as math class: ",[95,1249,1250],{},"*",[95,1252,176],{}," happen before ",[95,1255,935],{},[95,1257,1258],{},"-",". Parentheses override that.",[104,1261,1263],{"className":106,"code":1262,"language":108,"meta":48,"style":48},"System.out.println(2 + 3 * 2);   \u002F\u002F 8\nSystem.out.println((2 + 3) * 2); \u002F\u002F 10\n",[95,1264,1265,1270],{"__ignoreMap":48},[112,1266,1267],{"class":114,"line":115},[112,1268,1269],{},"System.out.println(2 + 3 * 2);   \u002F\u002F 8\n",[112,1271,1272],{"class":114,"line":49},[112,1273,1274],{},"System.out.println((2 + 3) * 2); \u002F\u002F 10\n",[69,1276,1278,1279,1282],{"id":1277},"the-remainder-operator","The Remainder Operator (",[95,1280,1281],{},"%",")",[15,1284,1285,1287,1288,1291,1292,1295],{},[95,1286,1281],{}," gives you what's left over after dividing. ",[95,1289,1290],{},"5 % 2"," is ",[95,1293,1294],{},"1",", because 2 fits into 5 twice, with 1 left over.",[104,1297,1299],{"className":106,"code":1298,"language":108,"meta":48,"style":48},"int totalSeconds = 150;\nSystem.out.println(totalSeconds \u002F 60); \u002F\u002F 2 — whole minutes\nSystem.out.println(totalSeconds % 60); \u002F\u002F 30 — leftover seconds\n\u002F\u002F 150 seconds = 2 minutes, 30 seconds\n",[95,1300,1301,1306,1311,1316],{"__ignoreMap":48},[112,1302,1303],{"class":114,"line":115},[112,1304,1305],{},"int totalSeconds = 150;\n",[112,1307,1308],{"class":114,"line":49},[112,1309,1310],{},"System.out.println(totalSeconds \u002F 60); \u002F\u002F 2 — whole minutes\n",[112,1312,1313],{"class":114,"line":126},[112,1314,1315],{},"System.out.println(totalSeconds % 60); \u002F\u002F 30 — leftover seconds\n",[112,1317,1318],{"class":114,"line":132},[112,1319,1320],{},"\u002F\u002F 150 seconds = 2 minutes, 30 seconds\n",[15,1322,1323,1325,1326,537,1328,1330,1331,1291,1334,1337,1338,1291,1341,1344],{},[95,1324,1281],{}," binds as tightly as ",[95,1327,1250],{},[95,1329,176],{}," (so it follows the same order-of-operations rule above). It also behaves a little differently with negative numbers than you might expect: ",[95,1332,1333],{},"-7 \u002F 2",[95,1335,1336],{},"-3"," (still truncated toward zero, not rounded down), and ",[95,1339,1340],{},"-7 % 2",[95,1342,1343],{},"-1"," (the remainder keeps the sign of the number being divided).",[69,1346,462],{"id":461},[19,1348,1349,1357],{},[22,1350,1351,1354,1355,79],{},[25,1352,1353],{},"Dividing two whole numbers and expecting a decimal."," It truncates instead — check whether at least one side is a ",[95,1356,631],{},[22,1358,1359,1362,1363,1366,1367,1370,1371,260,1374,1377],{},[25,1360,1361],{},"Dividing by zero."," Whole-number division by ",[95,1364,1365],{},"0"," crashes the program. Decimal division by ",[95,1368,1369],{},"0.0"," doesn't crash, but gives a nonsense result (",[95,1372,1373],{},"Infinity",[95,1375,1376],{},"NaN",") — a sign something's wrong upstream.",[69,1379,501],{"id":500},[19,1381,1382,1391,1394,1407],{},[22,1383,1384,1387,1388,1390],{},[95,1385,1386],{},"print"," stays on the line; ",[95,1389,395],{}," moves to a new one.",[22,1392,1393],{},"Dividing two whole numbers truncates the decimal part instead of rounding.",[22,1395,1396,1397,176,1399,1401,1402,176,1404,1406],{},"Use ",[95,1398,1250],{},[95,1400,176],{}," before ",[95,1403,935],{},[95,1405,1258],{},", unless parentheses say otherwise.",[22,1408,1409,1411],{},[95,1410,1281],{}," gives the remainder after division — useful for splitting a total into two units (like seconds into minutes and seconds).",[15,1413,544,1414,548,1416,1419],{},[95,1415,547],{},[95,1417,1418],{},"unit-1-using-objects-and-methods\u002F1.03-expressions-and-output.md"," (CSA 1.3)",[554,1421,556],{},{"title":48,"searchDepth":49,"depth":49,"links":1423},[1424,1425,1427,1428,1429,1431,1432],{"id":1058,"depth":49,"text":1059},{"id":1099,"depth":49,"text":1426},"Joining Text and Values With +",{"id":1203,"depth":49,"text":1204},{"id":1243,"depth":49,"text":1244},{"id":1277,"depth":49,"text":1430},"The Remainder Operator (%)",{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":1434,"status":570},"2.2 — Expressions and Output (CSA 1.3)","\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2-expressions-and-output",{"title":1050,"description":48},"shockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.2-expressions-and-output","0NcrLM4C6i2k-p2KTH21QCGq9E0VPLfBo0YNNJTn2E4",{"id":1440,"title":1441,"body":1442,"description":48,"extension":51,"meta":1663,"navigation":55,"path":1665,"seo":1666,"stem":1667,"__hash__":1668},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.3-assignment-and-input.md","Assignment & Input",{"type":8,"value":1443,"toc":1655},[1444,1447,1451,1456,1465,1477,1502,1506,1509,1529,1538,1542,1545,1560,1567,1571,1574,1594,1596,1620,1622,1645,1653],[11,1445,1441],{"id":1446},"assignment-input",[69,1448,1450],{"id":1449},"assignment-one-more-time","Assignment, One More Time",[15,1452,1453,1455],{},[95,1454,737],{}," always has one variable on the left, and a value (or a math expression) on the right. Read it as \"gets assigned,\" not \"equals.\"",[104,1457,1459],{"className":106,"code":1458,"language":108,"meta":48,"style":48},"int score = 10 * 2 + 5; \u002F\u002F score is assigned the value 25\n",[95,1460,1461],{"__ignoreMap":48},[112,1462,1463],{"class":114,"line":115},[112,1464,1458],{},[15,1466,1467,1468,537,1470,1472,1473,1476],{},"Copying one variable into another only copies the value at that moment — it doesn't link them together. (This is true for primitive types like ",[95,1469,603],{},[95,1471,631],{},", which is everything we've used so far; once you start working with objects, starting in Ch.7, copying a variable copies a ",[494,1474,1475],{},"reference"," instead, which behaves differently.)",[104,1478,1480],{"className":106,"code":1479,"language":108,"meta":48,"style":48},"int x = 3;\nint y = 2;\nx = y;   \u002F\u002F x is now assigned a copy of y's value: 2\ny = 5;   \u002F\u002F y changes — x is still 2, unaffected\n",[95,1481,1482,1487,1492,1497],{"__ignoreMap":48},[112,1483,1484],{"class":114,"line":115},[112,1485,1486],{},"int x = 3;\n",[112,1488,1489],{"class":114,"line":49},[112,1490,1491],{},"int y = 2;\n",[112,1493,1494],{"class":114,"line":126},[112,1495,1496],{},"x = y;   \u002F\u002F x is now assigned a copy of y's value: 2\n",[112,1498,1499],{"class":114,"line":132},[112,1500,1501],{},"y = 5;   \u002F\u002F y changes — x is still 2, unaffected\n",[69,1503,1505],{"id":1504},"every-variable-needs-a-value-first","Every Variable Needs a Value First",[15,1507,1508],{},"You can't use a variable in an expression before it's been assigned something, and the value has to match the type:",[104,1510,1512],{"className":106,"code":1511,"language":108,"meta":48,"style":48},"int x = 1;\ndouble y = 2.2;\nx = 2 * y;   \u002F\u002F won't compile — 2 * y is a double, and x is an int\n",[95,1513,1514,1519,1524],{"__ignoreMap":48},[112,1515,1516],{"class":114,"line":115},[112,1517,1518],{},"int x = 1;\n",[112,1520,1521],{"class":114,"line":49},[112,1522,1523],{},"double y = 2.2;\n",[112,1525,1526],{"class":114,"line":126},[112,1527,1528],{},"x = 2 * y;   \u002F\u002F won't compile — 2 * y is a double, and x is an int\n",[15,1530,1531,1532,1534,1535,1537],{},"The fix here isn't to force it — it's to make ",[95,1533,852],{}," a ",[95,1536,631],{}," in the first place, since that's what it's actually meant to hold.",[69,1539,1541],{"id":1540},"updating-a-value-using-itself","Updating a Value Using Itself",[15,1543,1544],{},"A common pattern: change a variable based on its own current value.",[104,1546,1548],{"className":106,"code":1547,"language":108,"meta":48,"style":48},"int step = 0;\nstep = step + 1; \u002F\u002F uses the OLD value of step, then stores the new result back into it\n",[95,1549,1550,1555],{"__ignoreMap":48},[112,1551,1552],{"class":114,"line":115},[112,1553,1554],{},"int step = 0;\n",[112,1556,1557],{"class":114,"line":49},[112,1558,1559],{},"step = step + 1; \u002F\u002F uses the OLD value of step, then stores the new result back into it\n",[15,1561,1562,1563,1566],{},"(Lesson 2.5 covers a shorthand for this: ",[95,1564,1565],{},"step++",".)",[69,1568,1570],{"id":1569},"where-input-comes-from","Where \"Input\" Comes From",[15,1572,1573],{},"Some value comes from outside your code, gets stored in a variable, and your code reacts to it. On a robot, that's a joystick or a sensor, not typed text — but it's the same idea: the variable holds whatever value showed up, and the rest of the code doesn't need to change no matter what that value is.",[104,1575,1577],{"className":106,"code":1576,"language":108,"meta":48,"style":48},"double maxSpeed = 0.85;\ndouble throttle = 0.6; \u002F\u002F stands in for \"whatever value the controller sends\"\ndouble output = throttle * maxSpeed;\n",[95,1578,1579,1584,1589],{"__ignoreMap":48},[112,1580,1581],{"class":114,"line":115},[112,1582,1583],{},"double maxSpeed = 0.85;\n",[112,1585,1586],{"class":114,"line":49},[112,1587,1588],{},"double throttle = 0.6; \u002F\u002F stands in for \"whatever value the controller sends\"\n",[112,1590,1591],{"class":114,"line":126},[112,1592,1593],{},"double output = throttle * maxSpeed;\n",[69,1595,462],{"id":461},[19,1597,1598,1604],{},[22,1599,1600,1603],{},[25,1601,1602],{},"Using a variable before it has a value."," Java won't let this compile — it's a safety net, not an inconvenience.",[22,1605,1606,1613,1614,1616,1617,79],{},[25,1607,1608,1609,1612],{},"Assuming ",[95,1610,1611],{},"y = x"," keeps them linked."," It copies the value once. Changing ",[95,1615,852],{}," later does nothing to ",[95,1618,1619],{},"y",[69,1621,501],{"id":500},[19,1623,1624,1630,1633,1636,1642],{},[22,1625,1626,1627,1629],{},"Read ",[95,1628,737],{}," as \"gets assigned,\" not \"equals.\"",[22,1631,1632],{},"Copying a variable's value into another does not link them — each is independent afterward.",[22,1634,1635],{},"A variable must have a value, of a matching type, before it's used in an expression.",[22,1637,1638,1641],{},[95,1639,1640],{},"step = step + 1"," uses the old value first, then overwrites the variable.",[22,1643,1644],{},"\"Input\" is any value that comes from outside your code — a joystick reading, a sensor, or (on a laptop, not covered in this course) typed text.",[15,1646,544,1647,548,1649,1652],{},[95,1648,547],{},[95,1650,1651],{},"unit-1-using-objects-and-methods\u002F1.04-assignment-and-input.md"," (CSA 1.4)",[554,1654,556],{},{"title":48,"searchDepth":49,"depth":49,"links":1656},[1657,1658,1659,1660,1661,1662],{"id":1449,"depth":49,"text":1450},{"id":1504,"depth":49,"text":1505},{"id":1540,"depth":49,"text":1541},{"id":1569,"depth":49,"text":1570},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":1664,"status":570},"2.3 — Assignment and Input (CSA 1.4)","\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F3-assignment-and-input",{"title":1441,"description":48},"shockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.3-assignment-and-input","78cq_NhHluYno3jPG6Htium12cHrCQEVwT0qfVhm87I",{"id":1670,"title":1671,"body":1672,"description":48,"extension":51,"meta":2072,"navigation":55,"path":2074,"seo":2075,"stem":2076,"__hash__":2077},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.4-casting-and-ranges-of-values.md","Casting & Ranges of Values",{"type":8,"value":1673,"toc":2063},[1674,1677,1681,1684,1716,1720,1729,1744,1758,1765,1774,1805,1809,1816,1845,1849,1855,1864,1878,1881,1885,1898,1913,1927,1956,1970,1972,2005,2007,2053,2061],[11,1675,1671],{"id":1676},"casting-ranges-of-values",[69,1678,1680],{"id":1679},"widening-vs-narrowing","Widening vs. Narrowing",[15,1682,1683],{},"Java moves values between numeric types two different ways:",[19,1685,1686,1702],{},[22,1687,1688,1691,1692,1694,1695,1697,1698,1701],{},[25,1689,1690],{},"Widening"," — a smaller type flows into a bigger one automatically, no cast needed: ",[95,1693,603],{}," into ",[95,1696,631],{}," is always safe (no information is lost), so ",[95,1699,1700],{},"double d = 5;"," just compiles.",[22,1703,1704,1707,1708,1694,1710,1712,1713,1715],{},[25,1705,1706],{},"Narrowing"," — a bigger type into a smaller one loses information, so Java requires an explicit cast to make sure you meant it: ",[95,1709,631],{},[95,1711,603],{}," needs ",[95,1714,968],{},". This is exactly the rule behind the \"possible lossy conversion\" compile errors from 2.1 and 2.3.",[69,1717,1719],{"id":1718},"converting-between-types-casting","Converting Between Types (Casting)",[15,1721,1722,1723,260,1725,1728],{},"Put ",[95,1724,968],{},[95,1726,1727],{},"(double)"," right before a value to convert it to that type on the spot:",[104,1730,1732],{"className":106,"code":1731,"language":108,"meta":48,"style":48},"(double) 1 \u002F 3   \u002F\u002F 0.333... — the 1 becomes a double first, then divides\n(int) 3.6        \u002F\u002F 3 — cuts off everything after the decimal point\n",[95,1733,1734,1739],{"__ignoreMap":48},[112,1735,1736],{"class":114,"line":115},[112,1737,1738],{},"(double) 1 \u002F 3   \u002F\u002F 0.333... — the 1 becomes a double first, then divides\n",[112,1740,1741],{"class":114,"line":49},[112,1742,1743],{},"(int) 3.6        \u002F\u002F 3 — cuts off everything after the decimal point\n",[15,1745,1746,1748,1749,1291,1752,959,1755,79],{},[95,1747,968],{}," always cuts off the decimal — it never rounds. ",[95,1750,1751],{},"(int) 3.9",[95,1753,1754],{},"3",[95,1756,1757],{},"4",[15,1759,1760,1761,1764],{},"If you actually want to round, add ",[95,1762,1763],{},"0.5"," first, then cast:",[104,1766,1768],{"className":106,"code":1767,"language":108,"meta":48,"style":48},"int rounded = (int)(5.7 + 0.5); \u002F\u002F 6 — this is rounding, not truncating\n",[95,1769,1770],{"__ignoreMap":48},[112,1771,1772],{"class":114,"line":115},[112,1773,1767],{},[15,1775,1776,1777,1779,1780,1783,1784,1291,1787,959,1790,1793,1794,1797,1798,476,1801,1804],{},"This add-",[95,1778,1763],{}," trick only rounds correctly for ",[25,1781,1782],{},"non-negative"," numbers. For a negative value it rounds the wrong way: ",[95,1785,1786],{},"(int)(-5.7 + 0.5)",[95,1788,1789],{},"-5",[95,1791,1792],{},"-6"," — and FRC values (joystick input, encoder deltas) are often negative. Java's own ",[95,1795,1796],{},"Math.round(...)"," (Ch.4) handles the sign correctly and is the better tool for real code; this trick is worth knowing because you'll see it, and because it explains ",[494,1799,1800],{},"why",[95,1802,1803],{},"Math.round"," exists.",[69,1806,1808],{"id":1807},"the-fix-for-truncating-division","The Fix for Truncating Division",[15,1810,1811,1812,1815],{},"Lesson 2.2 showed that dividing two whole numbers cuts off the decimal. Casting one of them fixes it — but only if the cast happens ",[494,1813,1814],{},"before"," the division:",[104,1817,1819],{"className":106,"code":1818,"language":108,"meta":48,"style":48},"int total = 17;\nint games = 5;\n\ndouble average = (double) total \u002F games;   \u002F\u002F correct: 3.4\ndouble wrong    = (double) (total \u002F games); \u002F\u002F wrong: int division first, then cast: 3.0\n",[95,1820,1821,1826,1831,1835,1840],{"__ignoreMap":48},[112,1822,1823],{"class":114,"line":115},[112,1824,1825],{},"int total = 17;\n",[112,1827,1828],{"class":114,"line":49},[112,1829,1830],{},"int games = 5;\n",[112,1832,1833],{"class":114,"line":126},[112,1834,907],{"emptyLinePlaceholder":55},[112,1836,1837],{"class":114,"line":132},[112,1838,1839],{},"double average = (double) total \u002F games;   \u002F\u002F correct: 3.4\n",[112,1841,1842],{"class":114,"line":138},[112,1843,1844],{},"double wrong    = (double) (total \u002F games); \u002F\u002F wrong: int division first, then cast: 3.0\n",[69,1846,1848],{"id":1847},"whole-numbers-have-a-limit","Whole Numbers Have a Limit",[15,1850,1851,1852,1854],{},"An ",[95,1853,603],{}," can only hold values in a fixed range (roughly ±2.1 billion). Go past that limit, and the number silently wraps around to a wrong value — no error, no warning.",[104,1856,1858],{"className":106,"code":1857,"language":108,"meta":48,"style":48},"System.out.println(Integer.MAX_VALUE + 1); \u002F\u002F wraps to the smallest possible int\n",[95,1859,1860],{"__ignoreMap":48},[112,1861,1862],{"class":114,"line":115},[112,1863,1857],{},[15,1865,1866,1867,1870,1871,1873,1874,1877],{},"(",[95,1868,1869],{},"Integer"," here is a built-in helper class that travels alongside the ",[95,1872,603],{}," primitive, and ",[95,1875,1876],{},"MAX_VALUE"," is a constant it defines — both get a proper introduction in 9.2.)",[15,1879,1880],{},"This is unlikely to come up in a match, but it's a real risk for a counter that keeps growing and is never reset.",[69,1882,1884],{"id":1883},"decimals-have-a-precision-limit-too","Decimals Have a Precision Limit Too",[15,1886,405,1887,1889,1890,1893,1894,1897],{},[95,1888,631],{}," can only store so many significant digits (about 15-16). Beyond that, the extra digits get quietly rounded off. The everyday cause isn't running out of digits, though — most decimals simply can't be stored ",[494,1891,1892],{},"exactly"," in binary at all, the same way ",[95,1895,1896],{},"1\u002F3"," can't be written exactly in decimal:",[104,1899,1901],{"className":106,"code":1900,"language":108,"meta":48,"style":48},"System.out.println(0.1 + 0.2);        \u002F\u002F 0.30000000000000004, not 0.3\nSystem.out.println(0.1 + 0.2 == 0.3); \u002F\u002F false\n",[95,1902,1903,1908],{"__ignoreMap":48},[112,1904,1905],{"class":114,"line":115},[112,1906,1907],{},"System.out.println(0.1 + 0.2);        \u002F\u002F 0.30000000000000004, not 0.3\n",[112,1909,1910],{"class":114,"line":49},[112,1911,1912],{},"System.out.println(0.1 + 0.2 == 0.3); \u002F\u002F false\n",[15,1914,1915,1916,1918,1919,1922,1923,1926],{},"This is why comparing two ",[95,1917,631],{},"s with ",[95,1920,1921],{},"=="," is risky — two values that \"should\" be mathematically equal can differ by a tiny rounding amount you never typed in yourself. The fix, needed constantly for things like checking whether a robot arm reached its target angle, is a ",[25,1924,1925],{},"tolerance comparison",": instead of asking \"are these exactly equal,\" ask \"are these close enough\":",[104,1928,1930],{"className":106,"code":1929,"language":108,"meta":48,"style":48},"double target = 45.0;\ndouble current = 44.98;\ndouble tolerance = 0.05;\n\nboolean closeEnough = Math.abs(current - target) \u003C tolerance; \u002F\u002F true\n",[95,1931,1932,1937,1942,1947,1951],{"__ignoreMap":48},[112,1933,1934],{"class":114,"line":115},[112,1935,1936],{},"double target = 45.0;\n",[112,1938,1939],{"class":114,"line":49},[112,1940,1941],{},"double current = 44.98;\n",[112,1943,1944],{"class":114,"line":126},[112,1945,1946],{},"double tolerance = 0.05;\n",[112,1948,1949],{"class":114,"line":132},[112,1950,907],{"emptyLinePlaceholder":55},[112,1952,1953],{"class":114,"line":138},[112,1954,1955],{},"boolean closeEnough = Math.abs(current - target) \u003C tolerance; \u002F\u002F true\n",[15,1957,1958,1961,1962,1965,1966,1969],{},[95,1959,1960],{},"Math.abs(...)"," (Ch.4) strips the sign, so it doesn't matter whether ",[95,1963,1964],{},"current"," is a bit above or a bit below ",[95,1967,1968],{},"target"," — only how far apart they are.",[69,1971,462],{"id":461},[19,1973,1974,1980,1991],{},[22,1975,1976,1979],{},[25,1977,1978],{},"Casting after dividing instead of before."," The division already happened as whole numbers by the time the cast runs — putting the cast in the wrong spot doesn't fix anything.",[22,1981,1982,476,1985,1987,1988,1990],{},[25,1983,1984],{},"Assuming a cast rounds.",[95,1986,968],{}," cuts off the decimal. Rounding needs the add-",[95,1989,1763],{},"-then-cast trick — and even that trick only works for non-negative numbers.",[22,1992,1993,2000,2001,2004],{},[25,1994,1995,1996,1918,1998,79],{},"Comparing ",[95,1997,631],{},[95,1999,1921],{}," Two values that \"should\" be equal often aren't, bit-for-bit — use a tolerance comparison (",[95,2002,2003],{},"Math.abs(a - b) \u003C tolerance",") instead.",[69,2006,501],{"id":500},[19,2008,2009,2022,2032,2038,2043],{},[22,2010,2011,2012,1694,2014,2016,2017,1694,2019,2021],{},"Widening (small type into big, e.g. ",[95,2013,603],{},[95,2015,631],{},") happens automatically; narrowing (big into small, e.g. ",[95,2018,631],{},[95,2020,603],{},") needs an explicit cast.",[22,2023,2024,537,2026,2028,2029,2031],{},[95,2025,968],{},[95,2027,1727],{}," convert a value's type on the spot; ",[95,2030,968],{}," always cuts off decimals, never rounds.",[22,2033,2034,2035,2037],{},"To fix truncating division, cast one of the numbers ",[494,2036,1814],{}," dividing — position matters.",[22,2039,2040,2042],{},[95,2041,603],{}," values have a fixed range; going past it silently wraps to a wrong value.",[22,2044,2045,2047,2048,2050,2051,79],{},[95,2046,631],{}," values have a precision limit and can't store most decimals exactly — compare with a tolerance (",[95,2049,2003],{},") instead of ",[95,2052,1921],{},[15,2054,544,2055,548,2057,2060],{},[95,2056,547],{},[95,2058,2059],{},"unit-1-using-objects-and-methods\u002F1.05-casting-and-ranges-of-values.md"," (CSA 1.5)",[554,2062,556],{},{"title":48,"searchDepth":49,"depth":49,"links":2064},[2065,2066,2067,2068,2069,2070,2071],{"id":1679,"depth":49,"text":1680},{"id":1718,"depth":49,"text":1719},{"id":1807,"depth":49,"text":1808},{"id":1847,"depth":49,"text":1848},{"id":1883,"depth":49,"text":1884},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":2073,"status":570},"2.4 — Casting and Ranges of Values (CSA 1.5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F4-casting-and-ranges-of-values",{"title":1671,"description":48},"shockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.4-casting-and-ranges-of-values","cMmyTC3QPP6hwnB6e2RFx3rQQ0F4PYxGAWhRzg91M6g",{"id":2079,"title":2080,"body":2081,"description":48,"extension":51,"meta":2398,"navigation":55,"path":2400,"seo":2401,"stem":2402,"__hash__":2403},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.5-compound-assignment-operators.md","Compound Assignment Operators",{"type":8,"value":2082,"toc":2390},[2083,2086,2090,2103,2118,2122,2131,2146,2170,2174,2181,2219,2229,2233,2236,2292,2304,2306,2354,2356,2380,2388],[11,2084,2080],{"id":2085},"compound-assignment-operators",[69,2087,2089],{"id":2088},"a-shortcut-for-update-using-the-old-value","A Shortcut for \"Update Using the Old Value\"",[15,2091,2092,2095,2096,2099,2100,79],{},[95,2093,2094],{},"x = x + 1;"," comes up so often that Java has a shortcut: ",[95,2097,2098],{},"x += 1;",". Same idea works for every operator: ",[95,2101,2102],{},"+= -= *= \u002F= %=",[104,2104,2106],{"className":106,"code":2105,"language":108,"meta":48,"style":48},"score += 10;   \u002F\u002F same as: score = score + 10;\npower *= 0.5;  \u002F\u002F same as: power = power * 0.5;\n",[95,2107,2108,2113],{"__ignoreMap":48},[112,2109,2110],{"class":114,"line":115},[112,2111,2112],{},"score += 10;   \u002F\u002F same as: score = score + 10;\n",[112,2114,2115],{"class":114,"line":49},[112,2116,2117],{},"power *= 0.5;  \u002F\u002F same as: power = power * 0.5;\n",[69,2119,2121],{"id":2120},"increment-and-decrement","Increment and Decrement",[15,2123,2124,2125,537,2128,79],{},"Adding or subtracting exactly 1 is common enough to get its own shortcut: ",[95,2126,2127],{},"++",[95,2129,2130],{},"--",[104,2132,2134],{"className":106,"code":2133,"language":108,"meta":48,"style":48},"step++;   \u002F\u002F same as step += 1, same as step = step + 1\ntimer--;\n",[95,2135,2136,2141],{"__ignoreMap":48},[112,2137,2138],{"class":114,"line":115},[112,2139,2140],{},"step++;   \u002F\u002F same as step += 1, same as step = step + 1\n",[112,2142,2143],{"class":114,"line":49},[112,2144,2145],{},"timer--;\n",[15,2147,2148,2150,2151,2154,2155,2150,2158,2161,2162,2165,2166,2169],{},[95,2149,1565],{}," (",[25,2152,2153],{},"postfix",") and ",[95,2156,2157],{},"++step",[25,2159,2160],{},"prefix",") both add 1 to ",[95,2163,2164],{},"step"," — the difference only shows up when the increment is used ",[494,2167,2168],{},"inside"," a larger expression on the same line: postfix uses the old value first, then increments; prefix increments first, then uses the new value. Used on its own line, like every example here, they behave identically.",[69,2171,2173],{"id":2172},"a-real-example-ramping-up-power","A Real Example: Ramping Up Power",[15,2175,2176,2177,2180],{},"Instead of jumping straight to full power, increase it gradually, a little bit each time. (The ",[95,2178,2179],{},"if"," below is a sneak peek — Ch.5 covers it properly; for now, just read it as \"only run the next line when this is true.\")",[104,2182,2184],{"className":106,"code":2183,"language":108,"meta":48,"style":48},"double power = 0.0;\ndouble rampRate = 0.02; \u002F\u002F add 2% each time this runs\n\npower += rampRate;\nif (power > targetPower) {\n    power = targetPower; \u002F\u002F stop it from going past the target\n}\n",[95,2185,2186,2191,2196,2200,2205,2210,2215],{"__ignoreMap":48},[112,2187,2188],{"class":114,"line":115},[112,2189,2190],{},"double power = 0.0;\n",[112,2192,2193],{"class":114,"line":49},[112,2194,2195],{},"double rampRate = 0.02; \u002F\u002F add 2% each time this runs\n",[112,2197,2198],{"class":114,"line":126},[112,2199,907],{"emptyLinePlaceholder":55},[112,2201,2202],{"class":114,"line":132},[112,2203,2204],{},"power += rampRate;\n",[112,2206,2207],{"class":114,"line":138},[112,2208,2209],{},"if (power > targetPower) {\n",[112,2211,2212],{"class":114,"line":144},[112,2213,2214],{},"    power = targetPower; \u002F\u002F stop it from going past the target\n",[112,2216,2217],{"class":114,"line":150},[112,2218,153],{},[15,2220,2221,2222,2224,2225,2228],{},"That ",[95,2223,2179],{}," check matters — without it, ",[95,2226,2227],{},"power"," would just keep climbing past where you wanted it to stop.",[69,2230,2232],{"id":2231},"tracing-code-by-hand","Tracing Code by Hand",[15,2234,2235],{},"Tracing means walking through code line by line, by hand, updating each variable as you go — a genuinely useful way to find bugs when just reading the code isn't enough.",[104,2237,2239],{"className":106,"code":2238,"language":108,"meta":48,"style":48},"int step = 0;\nint delta = 5;\nint total = 1;\n\nstep++;              \u002F\u002F step: 1\ndelta -= 3;          \u002F\u002F delta: 2\ntotal = step + delta; \u002F\u002F total: 1 + 2 = 3\nstep = total * 2;    \u002F\u002F step: 3 * 2 = 6\ndelta %= 2;          \u002F\u002F delta: 2 % 2 = 0\ntotal--;             \u002F\u002F total: 2\n",[95,2240,2241,2245,2250,2255,2259,2264,2269,2274,2280,2286],{"__ignoreMap":48},[112,2242,2243],{"class":114,"line":115},[112,2244,1554],{},[112,2246,2247],{"class":114,"line":49},[112,2248,2249],{},"int delta = 5;\n",[112,2251,2252],{"class":114,"line":126},[112,2253,2254],{},"int total = 1;\n",[112,2256,2257],{"class":114,"line":132},[112,2258,907],{"emptyLinePlaceholder":55},[112,2260,2261],{"class":114,"line":138},[112,2262,2263],{},"step++;              \u002F\u002F step: 1\n",[112,2265,2266],{"class":114,"line":144},[112,2267,2268],{},"delta -= 3;          \u002F\u002F delta: 2\n",[112,2270,2271],{"class":114,"line":150},[112,2272,2273],{},"total = step + delta; \u002F\u002F total: 1 + 2 = 3\n",[112,2275,2277],{"class":114,"line":2276},8,[112,2278,2279],{},"step = total * 2;    \u002F\u002F step: 3 * 2 = 6\n",[112,2281,2283],{"class":114,"line":2282},9,[112,2284,2285],{},"delta %= 2;          \u002F\u002F delta: 2 % 2 = 0\n",[112,2287,2289],{"class":114,"line":2288},10,[112,2290,2291],{},"total--;             \u002F\u002F total: 2\n",[15,2293,2294,2295,322,2298,322,2301,79],{},"Final values: ",[95,2296,2297],{},"step = 6",[95,2299,2300],{},"delta = 0",[95,2302,2303],{},"total = 2",[69,2305,462],{"id":461},[19,2307,2308,2317,2323],{},[22,2309,2310,476,2313,2316],{},[25,2311,2312],{},"Forgetting the clamp when ramping.",[95,2314,2315],{},"power += rampRate"," with no limit check will just keep climbing past your target.",[22,2318,2319,2322],{},[25,2320,2321],{},"Skipping ahead while tracing."," Go one line at a time, in order — skipping ahead is how you miss the actual bug.",[22,2324,2325,476,2328,537,2330,2332,2333,2336,2337,2339,2340,2343,2344,2346,2347,2350,2351,2353],{},[25,2326,2327],{},"Compound assignment hides a cast.",[95,2329,2094],{},[95,2331,2098],{}," are usually described as identical, but they're not quite: ",[95,2334,2335],{},"int x = 5; x = x * 0.5;"," won't compile (the right side is a ",[95,2338,631],{},"), while ",[95,2341,2342],{},"x *= 0.5;"," compiles fine and silently truncates ",[95,2345,852],{}," down to ",[95,2348,2349],{},"2"," — the compound form has an invisible ",[95,2352,968],{}," cast built in.",[69,2355,501],{"id":500},[19,2357,2358,2363,2370,2377],{},[22,2359,2360,2362],{},[95,2361,2102],{}," update a variable using its current value, then store the result back.",[22,2364,2365,537,2367,2369],{},[95,2366,2127],{},[95,2368,2130],{}," are shortcuts for adding or subtracting exactly 1.",[22,2371,2372,2373,2376],{},"Ramping a motor's power up gradually is a real use of ",[95,2374,2375],{},"+=",", checked against a limit each time.",[22,2378,2379],{},"Tracing code by hand — one line, one value at a time — is a real debugging skill.",[15,2381,544,2382,548,2384,2387],{},[95,2383,547],{},[95,2385,2386],{},"unit-1-using-objects-and-methods\u002F1.06-compound-assignment-operators.md"," (CSA 1.6)",[554,2389,556],{},{"title":48,"searchDepth":49,"depth":49,"links":2391},[2392,2393,2394,2395,2396,2397],{"id":2088,"depth":49,"text":2089},{"id":2120,"depth":49,"text":2121},{"id":2172,"depth":49,"text":2173},{"id":2231,"depth":49,"text":2232},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":2399,"status":570},"2.5 — Compound Assignment Operators (CSA 1.6)","\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F5-compound-assignment-operators",{"title":2080,"description":48},"shockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.5-compound-assignment-operators","4jEzavsXTRIeaokO541U_J0fYUmHrFV9o8NAa3kuhes",{"id":2405,"title":2406,"body":2407,"description":48,"extension":51,"meta":2612,"navigation":55,"path":2614,"seo":2615,"stem":2616,"__hash__":2617},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3.1-apis-and-libraries.md","APIs and Libraries",{"type":8,"value":2408,"toc":2605},[2409,2412,2416,2422,2429,2433,2447,2450,2464,2493,2520,2536,2540,2549,2551,2576,2578,2595,2603],[11,2410,2406],{"id":2411},"apis-and-libraries",[69,2413,2415],{"id":2414},"libraries-and-apis","Libraries and APIs",[15,2417,405,2418,2421],{},[25,2419,2420],{},"library"," is a collection of code someone else already wrote, that you can reuse instead of writing it yourself. WPILib — the library every FRC robot depends on — is exactly this: motor control, sensors, the whole command-based framework, all written once and reused by thousands of teams.",[15,2423,2424,2425,2428],{},"The ",[25,2426,2427],{},"API"," (Application Programming Interface) is the instructions for how to actually use a library: what classes it gives you, what each one can do, and what you need to pass in. You don't need to know how a library's code works internally — you just need its API. WPILib publishes its API as web pages you can look things up in; Lesson 3.2 shows how to read one.",[69,2430,2432],{"id":2431},"classes-attributes-and-behaviors","Classes, Attributes, and Behaviors",[15,2434,405,2435,2437,2438,260,2440,2442,2443,2446],{},[25,2436,97],{}," is the building block a library gives you — it defines a new kind of value, the same way ",[95,2439,603],{},[95,2441,631],{}," do, except you (or a library author) define what it means. An ",[25,2444,2445],{},"object"," is one specific thing built from a class.",[15,2448,2449],{},"Every class bundles two things together:",[19,2451,2452,2458],{},[22,2453,2454,2457],{},[25,2455,2456],{},"Attributes"," — the data it holds. Stored in variables.",[22,2459,2460,2463],{},[25,2461,2462],{},"Behaviors"," — what it can do. Defined as methods.",[104,2465,2467],{"className":106,"code":2466,"language":108,"meta":48,"style":48},"\u002F\u002F statusLight is an object, built from WPILib's DigitalOutput class\nDigitalOutput statusLight = new DigitalOutput(0);\n\n\u002F\u002F a behavior — call a method with the dot operator\nstatusLight.set(true);\n",[95,2468,2469,2474,2479,2483,2488],{"__ignoreMap":48},[112,2470,2471],{"class":114,"line":115},[112,2472,2473],{},"\u002F\u002F statusLight is an object, built from WPILib's DigitalOutput class\n",[112,2475,2476],{"class":114,"line":49},[112,2477,2478],{},"DigitalOutput statusLight = new DigitalOutput(0);\n",[112,2480,2481],{"class":114,"line":126},[112,2482,907],{"emptyLinePlaceholder":55},[112,2484,2485],{"class":114,"line":132},[112,2486,2487],{},"\u002F\u002F a behavior — call a method with the dot operator\n",[112,2489,2490],{"class":114,"line":138},[112,2491,2492],{},"statusLight.set(true);\n",[15,2494,2495,2498,2499,2501,2502,2505,2506,2508,2509,2512,2513,2516,2517,2519],{},[95,2496,2497],{},"DigitalOutput"," is a real WPILib class: it switches one of the robot controller's digital output pins on or off — here pin ",[95,2500,1365],{},", wired to a status light. ",[95,2503,2504],{},"new"," builds the object (Lesson 4.5 covers exactly how); for now, read that line as \"make one ",[95,2507,2497],{}," for pin 0 and call it ",[95,2510,2511],{},"statusLight",".\" A real file also needs an ",[95,2514,2515],{},"import"," line before it can use ",[95,2518,2497],{}," — that's Lesson 3.3.",[15,2521,2424,2522,2524,2525,2528,2529,2532,2533,2535],{},[95,2523,79],{}," (dot operator) is how you reach an object's behaviors and attributes. ",[95,2526,2527],{},"statusLight.set(true)"," means: find the ",[95,2530,2531],{},"set"," method defined in the ",[95,2534,2497],{}," class, and run it on this specific object — turning its pin on.",[69,2537,2539],{"id":2538},"why-this-matters","Why This Matters",[15,2541,2542,2543,2545,2546,2548],{},"You don't need to know how ",[95,2544,2497],{}," is implemented internally — the calls into the robot controller's hardware, the voltage on the pin, none of it — to use ",[95,2547,2527],{}," correctly. That's the entire point of a library: someone else solved the hard problem once, documented how to use their solution, and you build on top of it instead of starting from scratch.",[69,2550,462],{"id":461},[19,2552,2553,2567],{},[22,2554,2555,476,2558,2560,2561,2563,2564,2566],{},[25,2556,2557],{},"Confusing a class with an object.",[95,2559,2497],{}," is the class (the blueprint); ",[95,2562,2511],{}," is one specific object built from it. A robot might have several ",[95,2565,2497],{}," objects — one per pin.",[22,2568,2569,476,2572,2575],{},[25,2570,2571],{},"Forgetting the dot operator.",[95,2573,2574],{},"statusLight set(true)"," isn't valid — the dot is what connects an object to its behavior.",[69,2577,501],{"id":500},[19,2579,2580,2583,2586,2589],{},[22,2581,2582],{},"A library is reusable code written by someone else; its API documents how to use it.",[22,2584,2585],{},"A class defines a new kind of value, bundling attributes (data) and behaviors (methods) together.",[22,2587,2588],{},"An object is one specific instance built from a class.",[22,2590,2591,2592,2594],{},"The dot operator (",[95,2593,79],{},") accesses an object's attributes and behaviors.",[15,2596,544,2597,548,2599,2602],{},[95,2598,547],{},[95,2600,2601],{},"unit-1-using-objects-and-methods\u002F1.07-apis-and-libraries.md"," (CSA 1.7)",[554,2604,556],{},{"title":48,"searchDepth":49,"depth":49,"links":2606},[2607,2608,2609,2610,2611],{"id":2414,"depth":49,"text":2415},{"id":2431,"depth":49,"text":2432},{"id":2538,"depth":49,"text":2539},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":2613,"status":570},"3.1 — APIs and Libraries (CSA 1.7)","\u002Fshockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F1-apis-and-libraries",{"title":2406,"description":48},"shockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3.1-apis-and-libraries","z1CS2DJh_84Azr7cfy_lXth7zaZwxfjh1ZZfLd0QEv0",{"id":2619,"title":2620,"body":2621,"description":48,"extension":51,"meta":3036,"navigation":55,"path":3038,"seo":3039,"stem":3040,"__hash__":3041},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3.2-documentation-with-comments-and-preconditions.md","Documentation with Comments and Preconditions",{"type":8,"value":2622,"toc":3027},[2623,2626,2630,2655,2658,2681,2685,2695,2698,2743,2753,2774,2778,2781,2823,2841,2852,2856,2870,2934,2943,2947,2950,2952,2978,2980,3017,3025],[11,2624,2620],{"id":2625},"documentation-with-comments-and-preconditions",[69,2627,2629],{"id":2628},"three-kinds-of-comments","Three Kinds of Comments",[104,2631,2633],{"className":106,"code":2632,"language":108,"meta":48,"style":48},"\u002F\u002F single-line comment\n\u002F* multi-line\n   comment *\u002F\n\u002F** a documentation comment — describes a class or method for other programmers *\u002F\n",[95,2634,2635,2640,2645,2650],{"__ignoreMap":48},[112,2636,2637],{"class":114,"line":115},[112,2638,2639],{},"\u002F\u002F single-line comment\n",[112,2641,2642],{"class":114,"line":49},[112,2643,2644],{},"\u002F* multi-line\n",[112,2646,2647],{"class":114,"line":126},[112,2648,2649],{},"   comment *\u002F\n",[112,2651,2652],{"class":114,"line":132},[112,2653,2654],{},"\u002F** a documentation comment — describes a class or method for other programmers *\u002F\n",[15,2656,2657],{},"The compiler ignores all three completely — they exist for whoever reads the code next, including future-you.",[15,2659,2660,2663,2664,2667,2668,2670,2671,2674,2675,2677,2678,2680],{},[25,2661,2662],{},"Java 25 note:"," Java 23 added a fourth style, ",[95,2665,2666],{},"\u002F\u002F\u002F"," Markdown documentation comments, where every line of the comment starts with ",[95,2669,2666],{},". This course uses ",[95,2672,2673],{},"\u002F** *\u002F",", which works on every Java version — on Java 17, a ",[95,2676,2666],{}," line is just an ordinary ",[95,2679,438],{}," comment.",[69,2682,2684],{"id":2683},"preconditions-and-postconditions","Preconditions and Postconditions",[15,2686,405,2687,2690,2691,2694],{},[25,2688,2689],{},"precondition"," is what has to be true before a method is called for it to work correctly. A ",[25,2692,2693],{},"postcondition"," is what's guaranteed true after it runs.",[15,2696,2697],{},"The method below takes a parameter, which Lesson 4.1 covers properly — for now, just look at the comment above it:",[104,2699,2701],{"className":106,"code":2700,"language":108,"meta":48,"style":48},"\u002F**\n * Spins the shooter up toward a target speed.\n * Precondition: targetRPM is between 0 and the motor's max RPM.\n * Postcondition: the motor ramps toward targetRPM.\n *\n * @param targetRPM the speed to spin up to\n *\u002F\npublic void spinUpTo(double targetRPM) { ... }\n",[95,2702,2703,2708,2713,2718,2723,2728,2733,2738],{"__ignoreMap":48},[112,2704,2705],{"class":114,"line":115},[112,2706,2707],{},"\u002F**\n",[112,2709,2710],{"class":114,"line":49},[112,2711,2712],{}," * Spins the shooter up toward a target speed.\n",[112,2714,2715],{"class":114,"line":126},[112,2716,2717],{}," * Precondition: targetRPM is between 0 and the motor's max RPM.\n",[112,2719,2720],{"class":114,"line":132},[112,2721,2722],{}," * Postcondition: the motor ramps toward targetRPM.\n",[112,2724,2725],{"class":114,"line":138},[112,2726,2727],{}," *\n",[112,2729,2730],{"class":114,"line":144},[112,2731,2732],{}," * @param targetRPM the speed to spin up to\n",[112,2734,2735],{"class":114,"line":150},[112,2736,2737],{}," *\u002F\n",[112,2739,2740],{"class":114,"line":2276},[112,2741,2742],{},"public void spinUpTo(double targetRPM) { ... }\n",[15,2744,2745,2746,845,2749,2752],{},"A documentation comment starts with a plain description — here, what the method does plus its precondition and postcondition — and ends with its ",[25,2747,2748],{},"tags",[95,2750,2751],{},"@param"," describes one parameter. Keep the tags last: everything after a tag is treated as part of that tag's description.",[15,2754,2755,2756,2759,2760,2763,2764,2767,2768,2770,2771,2773],{},"Java doesn't enforce preconditions automatically — nothing stops you from calling ",[95,2757,2758],{},"spinUpTo(-500)",". A precondition is a documented expectation, not a guarantee the method checks it. A real library shows the same effect: ",[95,2761,2762],{},"Math.sqrt(-4)"," (Java's ",[95,2765,2766],{},"Math"," class is Lesson 4.3) doesn't crash — its documentation says a negative input gives ",[95,2769,1376],{}," (\"not a number\"). If your code needed a real distance, ",[95,2772,1376],{}," is a silent wrong answer, not an error.",[69,2775,2777],{"id":2776},"more-documentation-tags","More Documentation Tags",[15,2779,2780],{},"Two more tags show up constantly in library documentation:",[104,2782,2784],{"className":106,"code":2783,"language":108,"meta":48,"style":48},"\u002F**\n * Converts a battery voltage into an approximate charge percentage.\n *\n * @param volts the measured battery voltage\n * @return the charge, from 0 to 100\n * @throws IllegalArgumentException if volts is negative\n *\u002F\npublic static double batteryPercent(double volts) { ... }\n",[95,2785,2786,2790,2795,2799,2804,2809,2814,2818],{"__ignoreMap":48},[112,2787,2788],{"class":114,"line":115},[112,2789,2707],{},[112,2791,2792],{"class":114,"line":49},[112,2793,2794],{}," * Converts a battery voltage into an approximate charge percentage.\n",[112,2796,2797],{"class":114,"line":126},[112,2798,2727],{},[112,2800,2801],{"class":114,"line":132},[112,2802,2803],{}," * @param volts the measured battery voltage\n",[112,2805,2806],{"class":114,"line":138},[112,2807,2808],{}," * @return the charge, from 0 to 100\n",[112,2810,2811],{"class":114,"line":144},[112,2812,2813],{}," * @throws IllegalArgumentException if volts is negative\n",[112,2815,2816],{"class":114,"line":150},[112,2817,2737],{},[112,2819,2820],{"class":114,"line":2276},[112,2821,2822],{},"public static double batteryPercent(double volts) { ... }\n",[19,2824,2825,2831],{},[22,2826,2827,2830],{},[95,2828,2829],{},"@return"," describes the value the method hands back (return values are Lesson 4.2).",[22,2832,2833,2836,2837,2840],{},[95,2834,2835],{},"@throws"," names an error (an ",[494,2838,2839],{},"exception",") the method can throw, and when it happens (exceptions are Ch.12).",[15,2842,2843,2844,2847,2848,2851],{},"Your IDE reads these comments too: hover over a call to ",[95,2845,2846],{},"batteryPercent"," and it shows the description and tags. The ",[95,2849,2850],{},"javadoc"," tool turns the same comments into web pages — which is exactly how a library's API pages are made.",[69,2853,2855],{"id":2854},"reading-an-api-page","Reading an API Page",[15,2857,2858,2859,2861,2862,2865,2866,2869],{},"WPILib's API pages are generated from its own ",[95,2860,2673],{}," comments. The 2027 pages are at ",[95,2863,2864],{},"github.wpilib.org\u002Fallwpilib\u002Fdocs\u002Fbeta\u002Fjava\u002F"," — search there for a class by name. The page for WPILib's ",[95,2867,2868],{},"Timer"," class shows, top to bottom:",[19,2871,2872,2887,2893,2905,2923],{},[22,2873,2874,195,2877,2880,2881,2883,2884,2886],{},[25,2875,2876],{},"Package and class",[95,2878,2879],{},"org.wpilib.system",", class ",[95,2882,2868],{},". The package tells you what to ",[95,2885,2515],{}," (Lesson 3.3).",[22,2888,2889,2892],{},[25,2890,2891],{},"Class description"," — \"A timer class.\"",[22,2894,2895,195,2898,2901,2902,2904],{},[25,2896,2897],{},"Constructor Summary",[95,2899,2900],{},"Timer()",": how to build one with ",[95,2903,2504],{},", and what it needs (no arguments).",[22,2906,2907,2910,2911,2914,2915,2918,2919,2922],{},[25,2908,2909],{},"Method Summary"," — one row per method: its return type, its name and parameters, and a one-line description. ",[95,2912,2913],{},"double get()"," — \"Get the current time from the timer.\" ",[95,2916,2917],{},"void start()"," — \"Start the timer running.\" ",[95,2920,2921],{},"boolean hasElapsed(double seconds)"," — \"Check if the period specified has passed.\"",[22,2924,2925,2928,2929,537,2931,2933],{},[25,2926,2927],{},"Method Details"," — the full comment for each method, including its ",[95,2930,2751],{},[95,2932,2829],{}," text.",[15,2935,2936,2937,2939,2940,2942],{},"The row ",[95,2938,2913],{}," tells you everything you need to call it: no arguments, and it hands back a ",[95,2941,631],{}," — the timer's elapsed time in seconds.",[69,2944,2946],{"id":2945},"why-bother-documenting-this","Why Bother Documenting This",[15,2948,2949],{},"Once you write a method, other people (including future-you, and your whole team) will call it without reading its implementation. Documenting preconditions and postconditions is how they know what's safe to pass in and what to expect back — without documentation, the only way to find out is to read the method's full source or guess.",[69,2951,462],{"id":461},[19,2953,2954,2963,2969],{},[22,2955,2956,2959,2960,2962],{},[25,2957,2958],{},"Assuming a precondition is enforced."," Documenting a precondition doesn't make Java check it — passing a bad value can still silently produce a wrong result (like ",[95,2961,1376],{},") instead of an error.",[22,2964,2965,2968],{},[25,2966,2967],{},"Skipping documentation on methods other people will call."," The cost of a two-line comment is much smaller than the cost of a teammate guessing wrong about what a method expects.",[22,2970,2971,2974,2975,2977],{},[25,2972,2973],{},"Putting description text after the tags."," Anything written after ",[95,2976,2751],{}," becomes part of that parameter's description — write the description first, then the tags.",[69,2979,501],{"id":500},[19,2981,2982,2994,2997,3000,3014],{},[22,2983,2984,322,2986,325,2988,2990,2991,2993],{},[95,2985,438],{},[95,2987,540],{},[95,2989,2673],{}," are the three comment styles; the compiler ignores all of them. (Java 23+ also allows ",[95,2992,2666],{}," documentation comments.)",[22,2995,2996],{},"A precondition is what must be true before a method is called; a postcondition is what's guaranteed true after it returns.",[22,2998,2999],{},"Preconditions are documented expectations, not automatically enforced — violating one can produce a wrong result without an error.",[22,3001,405,3002,3004,3005,3007,3008,3010,3011,3013],{},[95,3003,2673],{}," comment starts with its description, then its tags: ",[95,3006,2751],{}," for each parameter, ",[95,3009,2829],{}," for the returned value, ",[95,3012,2835],{}," for errors.",[22,3015,3016],{},"An API page lists a class's package, constructors, and methods (return type, name, parameters, description) — all generated from comments like these.",[15,3018,544,3019,548,3021,3024],{},[95,3020,547],{},[95,3022,3023],{},"unit-1-using-objects-and-methods\u002F1.08-documentation-with-comments-and-preconditions.md"," (CSA 1.8)",[554,3026,556],{},{"title":48,"searchDepth":49,"depth":49,"links":3028},[3029,3030,3031,3032,3033,3034,3035],{"id":2628,"depth":49,"text":2629},{"id":2683,"depth":49,"text":2684},{"id":2776,"depth":49,"text":2777},{"id":2854,"depth":49,"text":2855},{"id":2945,"depth":49,"text":2946},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":3037,"status":570},"3.2 — Documentation with Comments and Preconditions (CSA 1.8)","\u002Fshockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F2-documentation-with-comments-and-preconditions",{"title":2620,"description":48},"shockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3.2-documentation-with-comments-and-preconditions","suuSX1denMImlKHQ0jzzvOPc2AVPIxmnCBNXLeDZJiI",{"id":3043,"title":3044,"body":3045,"description":48,"extension":51,"meta":3317,"navigation":55,"path":3319,"seo":3320,"stem":3321,"__hash__":3322},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3.3-packages-and-imports.md","Packages & Imports",{"type":8,"value":3046,"toc":3309},[3047,3050,3054,3082,3086,3092,3125,3144,3148,3192,3196,3221,3233,3246,3248,3265,3267,3300,3307],[11,3048,3044],{"id":3049},"packages-imports",[69,3051,3053],{"id":3052},"packages-are-folders-for-classes","Packages Are Folders for Classes",[15,3055,405,3056,3059,3060,3063,3064,3067,3068,537,3071,3073,3074,3077,3078,3081],{},[25,3057,3058],{},"package"," groups related classes together — like a folder. ",[95,3061,3062],{},"org.wpilib.command3"," is a real WPILib package holding the command-based framework's classes (Ch.25), and ",[95,3065,3066],{},"org.wpilib.hardware.discrete"," holds ",[95,3069,3070],{},"DigitalInput",[95,3072,2497],{},". Package names match folders on disk: a class in the package ",[95,3075,3076],{},"frc.robot.subsystems"," lives in a ",[95,3079,3080],{},"frc\u002Frobot\u002Fsubsystems\u002F"," folder.",[69,3083,3085],{"id":3084},"importing-a-class","Importing a Class",[15,3087,3088,3089,3091],{},"To use a class from another package, ",[95,3090,2515],{}," it at the top of your file:",[104,3093,3095],{"className":106,"code":3094,"language":108,"meta":48,"style":48},"package frc.robot.subsystems;\n\nimport org.wpilib.hardware.discrete.DigitalInput;\nimport org.wpilib.hardware.rotation.Encoder;\n\npublic class Arm { ... }\n",[95,3096,3097,3102,3106,3111,3116,3120],{"__ignoreMap":48},[112,3098,3099],{"class":114,"line":115},[112,3100,3101],{},"package frc.robot.subsystems;\n",[112,3103,3104],{"class":114,"line":49},[112,3105,907],{"emptyLinePlaceholder":55},[112,3107,3108],{"class":114,"line":126},[112,3109,3110],{},"import org.wpilib.hardware.discrete.DigitalInput;\n",[112,3112,3113],{"class":114,"line":132},[112,3114,3115],{},"import org.wpilib.hardware.rotation.Encoder;\n",[112,3117,3118],{"class":114,"line":138},[112,3119,907],{"emptyLinePlaceholder":55},[112,3121,3122],{"class":114,"line":144},[112,3123,3124],{},"public class Arm { ... }\n",[15,3126,2424,3127,3129,3130,3133,3134,3136,3137,3140,3141,3143],{},[95,3128,3058],{}," line at the top says where ",[494,3131,3132],{},"this"," file lives; each ",[95,3135,2515],{}," brings in one class from somewhere else so you can use it by its short name (",[95,3138,3139],{},"Encoder",") instead of its full path. The order is always the same: ",[95,3142,3058],{}," first, then the imports, then the class.",[69,3145,3147],{"id":3146},"other-ways-to-reach-a-class","Other Ways to Reach a Class",[19,3149,3150,3160,3169,3186],{},[22,3151,3152,3155,3156,3159],{},[25,3153,3154],{},"Fully-qualified name"," — skip the import and write the whole path where you use the class: ",[95,3157,3158],{},"org.wpilib.system.Timer clock = new org.wpilib.system.Timer();",". Legal, just long.",[22,3161,3162,195,3165,3168],{},[25,3163,3164],{},"Wildcard import",[95,3166,3167],{},"import org.wpilib.hardware.discrete.*;"," imports every class in that one package (not the packages inside it).",[22,3170,3171,195,3174,3177,3178,3181,3182,3185],{},[25,3172,3173],{},"Static import",[95,3175,3176],{},"import static java.lang.Math.sqrt;"," lets you call one static method without its class name: ",[95,3179,3180],{},"sqrt(9.0)"," instead of ",[95,3183,3184],{},"Math.sqrt(9.0)"," (static methods are Lesson 4.2).",[22,3187,3188,3191],{},[25,3189,3190],{},"Same package, no import"," — a class in the same package as your file can be used by its short name with no import at all.",[69,3193,3195],{"id":3194},"one-package-needs-no-import","One Package Needs No Import",[15,3197,3198,3201,3202,322,3204,322,3206,3208,3209,3211,3212,537,3215,3217,3218,3220],{},[95,3199,3200],{},"java.lang"," is special — its classes (",[95,3203,361],{},[95,3205,358],{},[95,3207,2766],{},", and a handful of others) are always available, in every Java file, with no ",[95,3210,2515],{}," needed. That's why you've been able to use ",[95,3213,3214],{},"System.out.println",[95,3216,361],{}," this whole time without importing anything — and why ",[95,3219,2766],{}," (Lesson 4.3) needs no import either.",[15,3222,3223,3225,3226,3229,3230,3232],{},[25,3224,2662],{}," Java 25 adds ",[95,3227,3228],{},"import module java.base;",", which imports every public class in Java's core library at once, and a compact source file (one that's just ",[95,3231,216],{}," with no class line around it) gets that import automatically. On Java 17 neither exists — import classes one at a time as shown above.",[15,3234,3235,3238,3239,3242,3243,3245],{},[25,3236,3237],{},"Running a file that has a package line:"," keep it in the folder its package names. On Java 22 and later, ",[95,3240,3241],{},"java SelfTest.java"," refuses to run a file whose ",[95,3244,3058],{}," line doesn't match the folder it's in.",[69,3247,462],{"id":461},[19,3249,3250,3259],{},[22,3251,3252,3255,3256,3258],{},[25,3253,3254],{},"Forgetting an import."," If a class isn't in ",[95,3257,3200],{}," and isn't in your own package, using it without importing it is a compile error.",[22,3260,3261,3264],{},[25,3262,3263],{},"Importing something you don't use."," Not a functional bug, but most IDEs will flag it — it's just clutter.",[69,3266,501],{"id":500},[19,3268,3269,3272,3277,3288],{},[22,3270,3271],{},"A package groups related classes together, the way a folder groups related files — and its name matches the folder path on disk.",[22,3273,3274,3276],{},[95,3275,2515],{}," brings a class from another package into your file so you can use its short name.",[22,3278,3279,3280,3283,3284,3287],{},"You can also write a fully-qualified name, import a whole package with ",[95,3281,3282],{},".*",", or ",[95,3285,3286],{},"import static"," a single static member; classes in your own package need no import.",[22,3289,3290,3292,3293,322,3295,325,3297,3299],{},[95,3291,3200],{}," (which includes ",[95,3294,361],{},[95,3296,358],{},[95,3298,2766],{},") never needs an import — it's always available.",[15,3301,544,3302,548,3304,3306],{},[95,3303,547],{},[95,3305,2601],{}," (CSA 1.7 §1.7.2)",[554,3308,556],{},{"title":48,"searchDepth":49,"depth":49,"links":3310},[3311,3312,3313,3314,3315,3316],{"id":3052,"depth":49,"text":3053},{"id":3084,"depth":49,"text":3085},{"id":3146,"depth":49,"text":3147},{"id":3194,"depth":49,"text":3195},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":3318,"status":570},"3.3 — Packages & Imports (CSA 1.7 §1.7.2)","\u002Fshockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3-packages-and-imports",{"title":3044,"description":48},"shockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3.3-packages-and-imports","scdAcD5CawIWOs1B1b0e0FNXGXGh_JlcQgGX2xJVVKc",{"id":3324,"title":3325,"body":3326,"description":48,"extension":51,"meta":3524,"navigation":55,"path":3526,"seo":3527,"stem":3528,"__hash__":3529},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.1-methods-signatures-and-parameters.md","Methods, Signatures & Parameters",{"type":8,"value":3327,"toc":3516},[3328,3331,3335,3347,3351,3362,3371,3381,3390,3407,3411,3418,3422,3437,3457,3459,3490,3492,3506,3514],[11,3329,3325],{"id":3330},"methods-signatures-parameters",[69,3332,3334],{"id":3333},"what-a-method-is","What a Method Is",[15,3336,405,3337,3340,3341,3343,3344,3346],{},[25,3338,3339],{},"method"," is a named block of code that runs when you call it. ",[95,3342,388],{}," is a method call — you've been calling methods since Lesson 1.2 without needing to know how ",[95,3345,395],{}," is implemented internally. That's the whole benefit: you use a method by its name and what it does, not by reading its insides.",[69,3348,3350],{"id":3349},"signature-parameters-arguments","Signature, Parameters, Arguments",[15,3352,3353,3354,3357,3358,3361],{},"A method's ",[25,3355,3356],{},"signature"," is its name plus its parameter types — what you need to know to call it correctly. The return type is ",[494,3359,3360],{},"not"," part of the signature, so two methods in one class can't differ only in what they return.",[104,3363,3365],{"className":106,"code":3364,"language":108,"meta":48,"style":48},"public void rampTo(double targetSpeed) { ... }\n",[95,3366,3367],{"__ignoreMap":48},[112,3368,3369],{"class":114,"line":115},[112,3370,3364],{},[15,3372,3373,3376,3377,3380],{},[95,3374,3375],{},"targetSpeed"," here is a ",[25,3378,3379],{},"parameter"," — a variable declared in the method's header, usable inside the method's body. When you actually call the method:",[104,3382,3384],{"className":106,"code":3383,"language":108,"meta":48,"style":48},"drivetrain.rampTo(0.8);\n",[95,3385,3386],{"__ignoreMap":48},[112,3387,3388],{"class":114,"line":115},[112,3389,3383],{},[15,3391,3392,3395,3396,3399,3400,3403,3404,79],{},[95,3393,3394],{},"0.8"," is the ",[25,3397,3398],{},"argument"," — the real value being passed in. \"Parameter\" and \"argument\" describe the same slot from two different sides: the parameter is the variable ",[494,3401,3402],{},"in the method","; the argument is the value ",[494,3405,3406],{},"at the call site",[69,3408,3410],{"id":3409},"call-by-value","Call by Value",[15,3412,3413,3414,3417],{},"Java copies the argument's value into the parameter — ",[25,3415,3416],{},"call by value",". If the method changes its own parameter internally, the original value the caller passed in is unaffected; only a copy went in. (When the argument is an object, what gets copied is the reference to it — Lesson 7.3 shows what that means.)",[69,3419,3421],{"id":3420},"overloading","Overloading",[15,3423,3424,3425,845,3427,3430,3431,3433,3434,3436],{},"Two methods can share the same name if their parameter lists differ in number or type — this is ",[25,3426,3420],{},[95,3428,3429],{},"System.out.println()"," is a real example: there's a version for no arguments, one for a ",[95,3432,361],{},", one for an ",[95,3435,603],{},", and more — Java picks the right one based on what you pass in.",[104,3438,3440],{"className":106,"code":3439,"language":108,"meta":48,"style":48},"void println()          \u002F\u002F no parameters\nvoid println(String x)  \u002F\u002F takes a String\nvoid println(int x)     \u002F\u002F takes an int\n",[95,3441,3442,3447,3452],{"__ignoreMap":48},[112,3443,3444],{"class":114,"line":115},[112,3445,3446],{},"void println()          \u002F\u002F no parameters\n",[112,3448,3449],{"class":114,"line":49},[112,3450,3451],{},"void println(String x)  \u002F\u002F takes a String\n",[112,3453,3454],{"class":114,"line":126},[112,3455,3456],{},"void println(int x)     \u002F\u002F takes an int\n",[69,3458,462],{"id":461},[19,3460,3461,3467,3473],{},[22,3462,3463,3466],{},[25,3464,3465],{},"Mixing up \"parameter\" and \"argument.\""," They're often used loosely as if interchangeable, but precisely: parameter = the variable in the method header, argument = the value at the call site.",[22,3468,3469,3472],{},[25,3470,3471],{},"Assuming a method can change the caller's original value."," Call by value means the method only ever gets a copy — reassigning a parameter inside the method never affects the variable the caller passed in.",[22,3474,3475,3478,3479,3482,3483,3486,3487,3489],{},[25,3476,3477],{},"Wrong argument count, type, or order."," The compiler checks a call's arguments against the method's signature — a wrong count or a wrong type won't compile, and neither will swapping two arguments of ",[494,3480,3481],{},"different"," types. Swapping two arguments of the ",[494,3484,3485],{},"same"," type (two ",[95,3488,631],{},"s, say) does compile, and silently passes the wrong values (Lesson 4.5).",[69,3491,501],{"id":500},[19,3493,3494,3497,3500,3503],{},[22,3495,3496],{},"A method's signature is its name plus its parameter types.",[22,3498,3499],{},"A parameter is a variable in the method's own header; an argument is the actual value passed in at the call site.",[22,3501,3502],{},"Java uses call by value — a method receives a copy of each argument, not the original.",[22,3504,3505],{},"Overloading means multiple methods share a name but differ in their parameter lists; Java picks the matching one based on the call.",[15,3507,544,3508,548,3510,3513],{},[95,3509,547],{},[95,3511,3512],{},"unit-1-using-objects-and-methods\u002F1.09-method-signatures.md"," (CSA 1.9)",[554,3515,556],{},{"title":48,"searchDepth":49,"depth":49,"links":3517},[3518,3519,3520,3521,3522,3523],{"id":3333,"depth":49,"text":3334},{"id":3349,"depth":49,"text":3350},{"id":3409,"depth":49,"text":3410},{"id":3420,"depth":49,"text":3421},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":3525,"status":570},"4.1 — Methods, Signatures and Parameters (CSA 1.9)","\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F1-methods-signatures-and-parameters",{"title":3325,"description":48},"shockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.1-methods-signatures-and-parameters","wxzkQuq-wAoMe_cBQl_iVvlOz9_kp0TxYr8DbaWWsKU",{"id":3531,"title":3532,"body":3533,"description":48,"extension":51,"meta":3754,"navigation":55,"path":3756,"seo":3757,"stem":3758,"__hash__":3759},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.2-calling-class-methods.md","Calling Class Methods",{"type":8,"value":3534,"toc":3747},[3535,3538,3542,3560,3569,3572,3587,3591,3600,3628,3637,3652,3656,3673,3693,3695,3715,3717,3737,3745],[11,3536,3532],{"id":3537},"calling-class-methods",[69,3539,3541],{"id":3540},"class-methods-static-methods","Class Methods (Static Methods)",[15,3543,3544,3545,3547,3548,260,3551,845,3554,3556,3557,3559],{},"A method marked ",[95,3546,179],{}," belongs to the class itself, not to any object — called a ",[25,3549,3550],{},"class method",[25,3552,3553],{},"static method",[95,3555,101],{}," is static too: in this course it's always ",[95,3558,167],{},". Call a static method using the class name and the dot operator:",[104,3561,3563],{"className":106,"code":3562,"language":108,"meta":48,"style":48},"double distance = Math.abs(target - current);\n",[95,3564,3565],{"__ignoreMap":48},[112,3566,3567],{"class":114,"line":115},[112,3568,3562],{},[15,3570,3571],{},"Inside the same class that defines the method, you can drop the class name and just call it directly.",[15,3573,3574,3576,3577,3580,3581,3583,3584,3586],{},[25,3575,2662],{}," Java 25 also accepts a shorter, non-static ",[95,3578,3579],{},"void main()"," as a program's entry point. On Java 17, ",[95,3582,101],{}," must be ",[95,3585,167],{}," — which works on every version, so it's what this course uses.",[69,3588,3590],{"id":3589},"void-vs-non-void-methods","Void vs. Non-Void Methods",[15,3592,405,3593,3595,3596,3599],{},[95,3594,183],{}," method doesn't return anything — you call it purely for its effect (like printing, or setting a motor's speed). A ",[25,3597,3598],{},"non-void"," method computes and returns a value, which the caller should actually use:",[104,3601,3603],{"className":106,"code":3602,"language":108,"meta":48,"style":48},"public static int square(int number)\n{\n    int result = number * number;\n    return result;\n}\n",[95,3604,3605,3610,3614,3619,3624],{"__ignoreMap":48},[112,3606,3607],{"class":114,"line":115},[112,3608,3609],{},"public static int square(int number)\n",[112,3611,3612],{"class":114,"line":49},[112,3613,123],{},[112,3615,3616],{"class":114,"line":126},[112,3617,3618],{},"    int result = number * number;\n",[112,3620,3621],{"class":114,"line":132},[112,3622,3623],{},"    return result;\n",[112,3625,3626],{"class":114,"line":138},[112,3627,153],{},[15,3629,3630,3633,3634,3636],{},[95,3631,3632],{},"return"," sends the value back to whoever called the method, and ends the method immediately — nothing after ",[95,3635,3632],{}," runs.",[104,3638,3640],{"className":106,"code":3639,"language":108,"meta":48,"style":48},"int y = square(5);        \u002F\u002F stored in a variable\nSystem.out.println(square(4)); \u002F\u002F used directly in an expression\n",[95,3641,3642,3647],{"__ignoreMap":48},[112,3643,3644],{"class":114,"line":115},[112,3645,3646],{},"int y = square(5);        \u002F\u002F stored in a variable\n",[112,3648,3649],{"class":114,"line":49},[112,3650,3651],{},"System.out.println(square(4)); \u002F\u002F used directly in an expression\n",[69,3653,3655],{"id":3654},"common-errors","Common Errors",[19,3657,3658,3661,3670],{},[22,3659,3660],{},"Forgetting to do something with a non-void method's return value — it should be stored or used; Java lets you ignore it, but then the call's result is wasted.",[22,3662,3663,3664,3666,3667,3669],{},"A type mismatch between what a method returns and what you try to store it in (assigning a ",[95,3665,631],{}," return into an ",[95,3668,603],{}," variable won't compile).",[22,3671,3672],{},"Wrong argument count or type at the call site (or two arguments swapped — see Lesson 4.1).",[104,3674,3676],{"className":106,"code":3675,"language":108,"meta":48,"style":48},"int total = calculateChecksum(data); \u002F\u002F fine — assuming calculateChecksum returns an int\n\u002F\u002F compiles, but the returned value is silently thrown away:\ncalculateChecksum(data);\n",[95,3677,3678,3683,3688],{"__ignoreMap":48},[112,3679,3680],{"class":114,"line":115},[112,3681,3682],{},"int total = calculateChecksum(data); \u002F\u002F fine — assuming calculateChecksum returns an int\n",[112,3684,3685],{"class":114,"line":49},[112,3686,3687],{},"\u002F\u002F compiles, but the returned value is silently thrown away:\n",[112,3689,3690],{"class":114,"line":126},[112,3691,3692],{},"calculateChecksum(data);\n",[69,3694,462],{"id":461},[19,3696,3697,3703],{},[22,3698,3699,3702],{},[25,3700,3701],{},"Calling a non-void method and doing nothing with the result."," It still compiles — Java doesn't force you to use a return value, which makes this an easy mistake to miss.",[22,3704,3705,3708,3709,3711,3712,3714],{},[25,3706,3707],{},"Assigning a return value to the wrong type."," A ",[95,3710,631],{},"-returning method's result can't go straight into an ",[95,3713,603],{}," variable without an explicit cast (Ch.2.4) — and casting one truncates the decimal, which may not be what you wanted.",[69,3716,501],{"id":500},[19,3718,3719,3724,3729,3734],{},[22,3720,405,3721,3723],{},[95,3722,179],{}," method is a class method, called via the class name (or bare, from inside the same class).",[22,3725,405,3726,3728],{},[95,3727,183],{}," method returns nothing; a non-void method computes a value that should be stored or used.",[22,3730,3731,3733],{},[95,3732,3632],{}," sends a value back to the caller and ends the method immediately.",[22,3735,3736],{},"A non-void method's return value being ignored is a real, easy-to-miss bug — it still compiles.",[15,3738,544,3739,548,3741,3744],{},[95,3740,547],{},[95,3742,3743],{},"unit-1-using-objects-and-methods\u002F1.10-calling-class-methods.md"," (CSA 1.10)",[554,3746,556],{},{"title":48,"searchDepth":49,"depth":49,"links":3748},[3749,3750,3751,3752,3753],{"id":3540,"depth":49,"text":3541},{"id":3589,"depth":49,"text":3590},{"id":3654,"depth":49,"text":3655},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":3755,"status":570},"4.2 — Calling Class Methods (CSA 1.10)","\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F2-calling-class-methods",{"title":3532,"description":48},"shockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.2-calling-class-methods","-4-ljsmhxfKD8CYPcLAMIAQsMO3MhcWSzYMmpnRrYcQ",{"id":3761,"title":3762,"body":3763,"description":48,"extension":51,"meta":4305,"navigation":55,"path":4307,"seo":4308,"stem":4309,"__hash__":4310},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.3-using-the-math-class.md","Using the Math Class",{"type":8,"value":3764,"toc":4298},[3765,3768,3772,3780,3805,3814,3818,4040,4051,4066,4078,4082,4095,4110,4116,4145,4168,4170,4209,4211,4288,4296],[11,3766,3762],{"id":3767},"using-the-math-class",[69,3769,3771],{"id":3770},"maths-static-methods","Math's Static Methods",[15,3773,3774,3776,3777,3779],{},[95,3775,2766],{}," is a built-in class of static methods — no object, no ",[95,3778,2504],{},", just call it directly by its class name:",[104,3781,3783],{"className":106,"code":3782,"language":108,"meta":48,"style":48},"Math.abs(-4);     \u002F\u002F 4 — absolute value\nMath.pow(2, 3);   \u002F\u002F 8.0 — 2 to the power of 3\nMath.sqrt(9);     \u002F\u002F 3.0\nMath.random();    \u002F\u002F a double >= 0.0 and \u003C 1.0\n",[95,3784,3785,3790,3795,3800],{"__ignoreMap":48},[112,3786,3787],{"class":114,"line":115},[112,3788,3789],{},"Math.abs(-4);     \u002F\u002F 4 — absolute value\n",[112,3791,3792],{"class":114,"line":49},[112,3793,3794],{},"Math.pow(2, 3);   \u002F\u002F 8.0 — 2 to the power of 3\n",[112,3796,3797],{"class":114,"line":126},[112,3798,3799],{},"Math.sqrt(9);     \u002F\u002F 3.0\n",[112,3801,3802],{"class":114,"line":132},[112,3803,3804],{},"Math.random();    \u002F\u002F a double >= 0.0 and \u003C 1.0\n",[15,3806,3807,3808,3810,3811,3813],{},"These all return a value, so — same rule as the last lesson — you should actually use what they return. (",[95,3809,2766],{}," lives in ",[95,3812,3200],{},", so it never needs an import — Lesson 3.3.)",[69,3815,3817],{"id":3816},"more-math-methods-robot-code-uses","More Math Methods Robot Code Uses",[3819,3820,3821,3837],"table",{},[3822,3823,3824],"thead",{},[3825,3826,3827,3831,3834],"tr",{},[3828,3829,3830],"th",{},"Method",[3828,3832,3833],{},"What it gives you",[3828,3835,3836],{},"Example",[3838,3839,3840,3864,3883,3908,3935,3950,3967,3988,4013],"tbody",{},[3825,3841,3842,3852,3855],{},[3843,3844,3845,3848,3849],"td",{},[95,3846,3847],{},"Math.max(a, b)"," \u002F ",[95,3850,3851],{},"Math.min(a, b)",[3843,3853,3854],{},"the larger \u002F smaller of two values",[3843,3856,3857,3860,3861],{},[95,3858,3859],{},"Math.max(3, 7)"," → ",[95,3862,3863],{},"7",[3825,3865,3866,3871,3876],{},[3843,3867,3868],{},[95,3869,3870],{},"Math.round(x)",[3843,3872,3873,3875],{},[95,3874,852],{}," rounded to the nearest whole number",[3843,3877,3878,3860,3881],{},[95,3879,3880],{},"Math.round(2.6)",[95,3882,1754],{},[3825,3884,3885,3893,3900],{},[3843,3886,3887,3848,3890],{},[95,3888,3889],{},"Math.floor(x)",[95,3891,3892],{},"Math.ceil(x)",[3843,3894,3895,3897,3898],{},[95,3896,852],{}," rounded down \u002F up, as a ",[95,3899,631],{},[3843,3901,3902,3860,3905],{},[95,3903,3904],{},"Math.floor(2.6)",[95,3906,3907],{},"2.0",[3825,3909,3910,3915,3928],{},[3843,3911,3912],{},[95,3913,3914],{},"Math.signum(x)",[3843,3916,3917,3918,548,3920,322,3923,3283,3925],{},"the sign of ",[95,3919,852],{},[95,3921,3922],{},"-1.0",[95,3924,1369],{},[95,3926,3927],{},"1.0",[3843,3929,3930,3860,3933],{},[95,3931,3932],{},"Math.signum(-0.4)",[95,3934,3922],{},[3825,3936,3937,3942,3945],{},[3843,3938,3939],{},[95,3940,3941],{},"Math.PI",[3843,3943,3944],{},"the constant π — a value, not a method, so no parentheses",[3843,3946,3947],{},[95,3948,3949],{},"3.141592653589793",[3825,3951,3952,3957,3960],{},[3843,3953,3954],{},[95,3955,3956],{},"Math.toRadians(degrees)",[3843,3958,3959],{},"an angle in degrees converted to radians",[3843,3961,3962,3860,3965],{},[95,3963,3964],{},"Math.toRadians(180)",[95,3966,3949],{},[3825,3968,3969,3974,3980],{},[3843,3970,3971],{},[95,3972,3973],{},"Math.hypot(x, y)",[3843,3975,3976,3979],{},[95,3977,3978],{},"√(x² + y²)"," — the straight-line distance",[3843,3981,3982,3860,3985],{},[95,3983,3984],{},"Math.hypot(3, 4)",[95,3986,3987],{},"5.0",[3825,3989,3990,3995,4005],{},[3843,3991,3992],{},[95,3993,3994],{},"Math.atan2(y, x)",[3843,3996,3997,3998,4001,4002,4004],{},"the angle, in radians, pointing at ",[95,3999,4000],{},"(x, y)"," — note ",[95,4003,1619],{}," comes first",[3843,4006,4007,3860,4010],{},[95,4008,4009],{},"Math.atan2(1, 1)",[95,4011,4012],{},"0.7853981633974483",[3825,4014,4015,4020,4033],{},[3843,4016,4017],{},[95,4018,4019],{},"Math.clamp(value, min, max)",[3843,4021,4022,4025,4026,4029,4030],{},[95,4023,4024],{},"value",", kept inside the range ",[95,4027,4028],{},"min"," to ",[95,4031,4032],{},"max",[3843,4034,4035,3860,4038],{},[95,4036,4037],{},"Math.clamp(1.4, -1.0, 1.0)",[95,4039,3927],{},[15,4041,4042,4045,4046,4029,4048,4050],{},[95,4043,4044],{},"Math.clamp"," is the one you'll use most for motors — it keeps a computed throttle from ever leaving the legal ",[95,4047,3922],{},[95,4049,3927],{}," range:",[104,4052,4054],{"className":106,"code":4053,"language":108,"meta":48,"style":48},"\u002F\u002F never lower than -1.0 or higher than 1.0\ndouble throttle = Math.clamp(joystickValue * 1.5, -1.0, 1.0);\n",[95,4055,4056,4061],{"__ignoreMap":48},[112,4057,4058],{"class":114,"line":115},[112,4059,4060],{},"\u002F\u002F never lower than -1.0 or higher than 1.0\n",[112,4062,4063],{"class":114,"line":49},[112,4064,4065],{},"double throttle = Math.clamp(joystickValue * 1.5, -1.0, 1.0);\n",[15,4067,4068,476,4071,4073,4074,4077],{},[25,4069,4070],{},"Java 17 note:",[95,4072,4044],{}," was added in Java 21. On Java 17, write ",[95,4075,4076],{},"Math.max(-1.0, Math.min(1.0, value))"," instead — it gives the same result.",[69,4079,4081],{"id":4080},"random-numbers-in-a-range","Random Numbers in a Range",[15,4083,4084,4087,4088,4090,4091,4094],{},[95,4085,4086],{},"Math.random()"," alone gives a ",[95,4089,631],{}," in ",[95,4092,4093],{},"[0.0, 1.0)"," — including 0.0, never reaching 1.0. That's rarely useful on its own; you stretch and shift it to get the range you actually want:",[104,4096,4098],{"className":106,"code":4097,"language":108,"meta":48,"style":48},"int rnd = (int)(Math.random() * 10);      \u002F\u002F an int from 0-9 (10 possible values)\nint rnd2 = (int)(Math.random() * 10) + 1; \u002F\u002F an int from 1-10 (shifted up by 1)\n",[95,4099,4100,4105],{"__ignoreMap":48},[112,4101,4102],{"class":114,"line":115},[112,4103,4104],{},"int rnd = (int)(Math.random() * 10);      \u002F\u002F an int from 0-9 (10 possible values)\n",[112,4106,4107],{"class":114,"line":49},[112,4108,4109],{},"int rnd2 = (int)(Math.random() * 10) + 1; \u002F\u002F an int from 1-10 (shifted up by 1)\n",[15,4111,4112,4113,4115],{},"The general recipe: multiply by how many values you want, cast to ",[95,4114,603],{}," to drop the decimal, then add the minimum to shift the whole range up.",[104,4117,4119],{"className":106,"code":4118,"language":108,"meta":48,"style":48},"\u002F\u002F A random autonomous delay between 1 and 4 seconds\ndouble delay = Math.random() * 3.0 + 1.0; \u002F\u002F [1.0, 4.0)\n\n\u002F\u002F A random starting position index, 0 through 2 (3 choices)\nint startPos = (int)(Math.random() * 3);\n",[95,4120,4121,4126,4131,4135,4140],{"__ignoreMap":48},[112,4122,4123],{"class":114,"line":115},[112,4124,4125],{},"\u002F\u002F A random autonomous delay between 1 and 4 seconds\n",[112,4127,4128],{"class":114,"line":49},[112,4129,4130],{},"double delay = Math.random() * 3.0 + 1.0; \u002F\u002F [1.0, 4.0)\n",[112,4132,4133],{"class":114,"line":126},[112,4134,907],{"emptyLinePlaceholder":55},[112,4136,4137],{"class":114,"line":132},[112,4138,4139],{},"\u002F\u002F A random starting position index, 0 through 2 (3 choices)\n",[112,4141,4142],{"class":114,"line":138},[112,4143,4144],{},"int startPos = (int)(Math.random() * 3);\n",[15,4146,4147,4148,4151,4152,4155,4156,4158,4159,4162,4163,4165,4166,79],{},"The parentheses matter: ",[95,4149,4150],{},"(int)(Math.random() * 10)"," casts the whole scaled expression; ",[95,4153,4154],{},"(int)Math.random() * 10"," casts ",[95,4157,4086],{}," alone ",[494,4160,4161],{},"first"," — which truncates it to ",[95,4164,1365],{}," every time, then multiplies by 10, always giving ",[95,4167,1365],{},[69,4169,462],{"id":461},[19,4171,4172,4187,4200],{},[22,4173,4174,476,4177,4179,4180,4182,4183,4186],{},[25,4175,4176],{},"Forgetting the parentheses around the scaled expression.",[95,4178,4154],{}," always evaluates to ",[95,4181,1365],{}," — the cast has to wrap the whole ",[95,4184,4185],{},"Math.random() * range"," expression.",[22,4188,4189,4192,4193,959,4196,4199],{},[25,4190,4191],{},"Off-by-one on the range size."," For an inclusive range like 1-10, the range size is ",[95,4194,4195],{},"10",[95,4197,4198],{},"9"," — count how many distinct values you actually want.",[22,4201,4202,476,4205,4208],{},[25,4203,4204],{},"Ignoring the return value.",[95,4206,4207],{},"Math.abs(x);"," on its own line compiles but does nothing useful — the result has to be stored or used.",[69,4210,501],{"id":500},[19,4212,4213,4222,4232,4243,4252],{},[22,4214,4215,4217,4218,4221],{},[95,4216,2766],{}," methods are static — call them as ",[95,4219,4220],{},"Math.methodName(...)",", no object needed.",[22,4223,4224,4226,4227,4090,4229,4231],{},[95,4225,4086],{}," returns a ",[95,4228,631],{},[95,4230,4093],{}," — 0.0 possible, 1.0 never reached.",[22,4233,4234,4235,4238,4239,4242],{},"To get a random int in a range: ",[95,4236,4237],{},"(int)(Math.random() * range) + min",", where ",[95,4240,4241],{},"range"," is the count of possible values.",[22,4244,4245,4246,4248,4249,4251],{},"The parentheses around ",[95,4247,4185],{}," are required — casting only ",[95,4250,4086],{}," breaks the formula.",[22,4253,4254,4256,4257,176,4259,322,4261,322,4264,176,4267,322,4270,322,4273,322,4275,322,4278,322,4281,4284,4285,79],{},[95,4255,2766],{}," also gives you ",[95,4258,4032],{},[95,4260,4028],{},[95,4262,4263],{},"round",[95,4265,4266],{},"floor",[95,4268,4269],{},"ceil",[95,4271,4272],{},"signum",[95,4274,377],{},[95,4276,4277],{},"toRadians",[95,4279,4280],{},"hypot",[95,4282,4283],{},"atan2",", and — on Java 21+ — ",[95,4286,4287],{},"clamp",[15,4289,544,4290,548,4292,4295],{},[95,4291,547],{},[95,4293,4294],{},"unit-1-using-objects-and-methods\u002F1.11-using-the-math-class.md"," (CSA 1.11)",[554,4297,556],{},{"title":48,"searchDepth":49,"depth":49,"links":4299},[4300,4301,4302,4303,4304],{"id":3770,"depth":49,"text":3771},{"id":3816,"depth":49,"text":3817},{"id":4080,"depth":49,"text":4081},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":4306,"status":570},"4.3 — Using the Math Class (CSA 1.11)","\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F3-using-the-math-class",{"title":3762,"description":48},"shockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.3-using-the-math-class","Rm80RVo1yQLflPewVHBaz9gxJ7xXuStKarrc6nJ_yZI",{"id":4312,"title":4313,"body":4314,"description":48,"extension":51,"meta":4542,"navigation":55,"path":4544,"seo":4545,"stem":4546,"__hash__":4547},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.4-objects-instances-of-classes.md","Objects — Instances of Classes",{"type":8,"value":4315,"toc":4535},[4316,4319,4323,4342,4347,4362,4385,4389,4392,4411,4430,4434,4448,4451,4471,4474,4476,4501,4503,4525,4533],[11,4317,4313],{"id":4318},"objects-instances-of-classes",[69,4320,4322],{"id":4321},"class-as-blueprint-object-as-instance","Class as Blueprint, Object as Instance",[15,4324,405,4325,4327,4328,4330,4331,4334,4335,537,4338,4341],{},[25,4326,97],{}," is a blueprint; an ",[25,4329,2445],{}," is one specific thing built from it — the way a cookie cutter (class) stamps out cookies (objects), all the same shape but each its own cookie. ",[95,4332,4333],{},"DriveMotor"," is a class; ",[95,4336,4337],{},"leftMotor",[95,4339,4340],{},"rightMotor"," are two separate objects built from it.",[15,4343,4344,4346],{},[95,4345,4333],{}," stands for your team's own motor class — assume it already exists in your robot project (you'll write classes like it yourself in Ch.7). Its constructor takes the PWM channel the motor is plugged into.",[104,4348,4350],{"className":106,"code":4349,"language":108,"meta":48,"style":48},"DriveMotor leftMotor;\nDriveMotor rightMotor;\n",[95,4351,4352,4357],{"__ignoreMap":48},[112,4353,4354],{"class":114,"line":115},[112,4355,4356],{},"DriveMotor leftMotor;\n",[112,4358,4359],{"class":114,"line":49},[112,4360,4361],{},"DriveMotor rightMotor;\n",[15,4363,4364,4365,4368,4369,260,4371,4373,4374,4377,4378,4381,4382,4384],{},"A class also defines a new ",[494,4366,4367],{},"type",", the same way ",[95,4370,603],{},[95,4372,631],{}," do — ",[95,4375,4376],{},"DriveMotor leftMotor;"," declares a variable exactly like ",[95,4379,4380],{},"int score;"," does, just holding a ",[95,4383,4333],{}," instead of a whole number.",[69,4386,4388],{"id":4387},"attributes-and-behaviors-revisited","Attributes and Behaviors, Revisited",[15,4390,4391],{},"Every object has:",[19,4393,4394,4399],{},[22,4395,4396,4398],{},[25,4397,2456],{}," — the data it holds (its PWM channel, its current throttle).",[22,4400,4401,4403,4404,322,4407,4410],{},[25,4402,2462],{}," — what it can do, defined as methods (",[95,4405,4406],{},"setThrottle()",[95,4408,4409],{},"getThrottle()",").",[15,4412,4413,4414,4417,4418,4421,4422,537,4424,4426,4427,4429],{},"The class defines ",[494,4415,4416],{},"what"," attributes and behaviors exist; each individual object has its ",[494,4419,4420],{},"own"," values for them. ",[95,4423,4337],{},[95,4425,4340],{}," are both ",[95,4428,4333],{}," objects, but each has its own PWM channel and its own current throttle.",[69,4431,4433],{"id":4432},"reference-variables","Reference Variables",[15,4435,4436,4437,4439,4440,4442,4443,322,4445,4447],{},"A variable like ",[95,4438,4337],{}," doesn't hold the motor object directly — it holds a ",[25,4441,1475],{}," to it, like a tracking number pointing at where the real object lives in memory. This is different from a primitive variable (",[95,4444,603],{},[95,4446,631],{},"), which holds its value directly with nothing in between.",[15,4449,4450],{},"You can create as many objects from one class as you need:",[104,4452,4454],{"className":106,"code":4453,"language":108,"meta":48,"style":48},"DriveMotor leftMotor = new DriveMotor(1);\nDriveMotor rightMotor = new DriveMotor(2);\nDriveMotor intakeMotor = new DriveMotor(3);\n",[95,4455,4456,4461,4466],{"__ignoreMap":48},[112,4457,4458],{"class":114,"line":115},[112,4459,4460],{},"DriveMotor leftMotor = new DriveMotor(1);\n",[112,4462,4463],{"class":114,"line":49},[112,4464,4465],{},"DriveMotor rightMotor = new DriveMotor(2);\n",[112,4467,4468],{"class":114,"line":126},[112,4469,4470],{},"DriveMotor intakeMotor = new DriveMotor(3);\n",[15,4472,4473],{},"Three separate objects, one class.",[69,4475,462],{"id":461},[19,4477,4478,4489],{},[22,4479,4480,476,4483,4485,4486,4488],{},[25,4481,4482],{},"Confusing the class name with an object's name.",[95,4484,4333],{}," is always the class (capitalized, PascalCase); ",[95,4487,4337],{}," is a specific object (camelCase). Mixing these up is a common early error.",[22,4490,4491,476,4494,537,4496,4426,4498,4500],{},[25,4492,4493],{},"Assuming two objects of the same class share state.",[95,4495,4337],{},[95,4497,4340],{},[95,4499,4333],{}," objects, but changing one's throttle has zero effect on the other — each object's attributes are entirely its own.",[69,4502,501],{"id":500},[19,4504,4505,4508,4516,4519,4522],{},[22,4506,4507],{},"A class is a blueprint; an object is one specific instance built from it.",[22,4509,4510,4511,260,4513,4515],{},"A class defines a new type, just like ",[95,4512,603],{},[95,4514,631],{}," — a class variable declares a variable of that type.",[22,4517,4518],{},"Attributes are an object's data; behaviors are what it can do, defined as methods.",[22,4520,4521],{},"A reference variable holds a pointer to an object, not the object's data directly.",[22,4523,4524],{},"Many objects can be created from the same class, each with its own independent attribute values.",[15,4526,544,4527,548,4529,4532],{},[95,4528,547],{},[95,4530,4531],{},"unit-1-using-objects-and-methods\u002F1.12-objects-instances-of-classes.md"," (CSA 1.12)",[554,4534,556],{},{"title":48,"searchDepth":49,"depth":49,"links":4536},[4537,4538,4539,4540,4541],{"id":4321,"depth":49,"text":4322},{"id":4387,"depth":49,"text":4388},{"id":4432,"depth":49,"text":4433},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":4543,"status":570},"4.4 — Objects – Instances of Classes (CSA 1.12)","\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4-objects-instances-of-classes",{"title":4313,"description":48},"shockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.4-objects-instances-of-classes","J34pYpdV6vdZ9TirVwkbrr00bFsry1-WcVD8LORWjwQ",{"id":4549,"title":4550,"body":4551,"description":48,"extension":51,"meta":4819,"navigation":55,"path":4821,"seo":4822,"stem":4823,"__hash__":4824},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.5-creating-and-initializing-objects-constructors.md","Creating & Initializing Objects: Constructors",{"type":8,"value":4552,"toc":4809},[4553,4556,4562,4571,4580,4585,4589,4599,4624,4636,4639,4646,4652,4667,4680,4684,4687,4711,4713,4768,4770,4799,4807],[11,4554,4550],{"id":4555},"creating-initializing-objects-constructors",[69,4557,4559,4560],{"id":4558},"building-an-object-with-new","Building an Object with ",[95,4561,2504],{},[15,4563,405,4564,4567,4568,4570],{},[25,4565,4566],{},"constructor"," initializes a new object's attributes when it's created. To build one, use ",[95,4569,2504],{}," followed by the class name — that's actually a call to the constructor:",[104,4572,4574],{"className":106,"code":4573,"language":108,"meta":48,"style":48},"DriveMotor leftMotor = new DriveMotor(5); \u002F\u002F 5 is the PWM channel it's plugged into\n",[95,4575,4576],{"__ignoreMap":48},[112,4577,4578],{"class":114,"line":115},[112,4579,4573],{},[15,4581,1866,4582,4584],{},[95,4583,4333],{}," is the team's own motor class from Lesson 4.4 — assume it exists.)",[69,4586,4588],{"id":4587},"constructors-can-be-overloaded","Constructors Can Be Overloaded",[15,4590,4591,4592,4594,4595,4598],{},"A class can offer more than one constructor — different ways to set up an object, distinguished by their parameter lists. This is the same ",[25,4593,3420],{}," concept from methods (Lesson 4.1), applied to constructors. WPILib's ",[95,4596,4597],{},"Pose2d"," class (a robot's position and heading on the field) has several:",[104,4600,4602],{"className":106,"code":4601,"language":108,"meta":48,"style":48},"\u002F\u002F no-argument constructor: defaults to (0, 0, facing 0°)\nPose2d start1 = new Pose2d();\n\u002F\u002F x, y, and heading, explicitly\nPose2d start2 = new Pose2d(1.0, 2.0, new Rotation2d());\n",[95,4603,4604,4609,4614,4619],{"__ignoreMap":48},[112,4605,4606],{"class":114,"line":115},[112,4607,4608],{},"\u002F\u002F no-argument constructor: defaults to (0, 0, facing 0°)\n",[112,4610,4611],{"class":114,"line":49},[112,4612,4613],{},"Pose2d start1 = new Pose2d();\n",[112,4615,4616],{"class":114,"line":126},[112,4617,4618],{},"\u002F\u002F x, y, and heading, explicitly\n",[112,4620,4621],{"class":114,"line":132},[112,4622,4623],{},"Pose2d start2 = new Pose2d(1.0, 2.0, new Rotation2d());\n",[15,4625,4626,537,4628,4631,4632,4635],{},[95,4627,4597],{},[95,4629,4630],{},"Rotation2d"," are real WPILib classes, from the package ",[95,4633,4634],{},"org.wpilib.math.geometry","; a pose's x and y are measured in meters.",[15,4637,4638],{},"Argument order matters — mixing up which number means what (is it x-then-y, or y-then-x?) produces a real, silent bug: the code compiles fine, but the object ends up with the wrong values.",[69,4640,4642,4643],{"id":4641},"object-references-and-null","Object References and ",[95,4644,4645],{},"null",[15,4647,4648,4649,4651],{},"A reference variable can be declared without pointing at any object yet — that's ",[95,4650,4645],{},", meaning \"doesn't refer to anything.\"",[104,4653,4655],{"className":106,"code":4654,"language":108,"meta":48,"style":48},"DriveMotor intakeMotor = null; \u002F\u002F no object yet\nintakeMotor = new DriveMotor(7); \u002F\u002F now it does\n",[95,4656,4657,4662],{"__ignoreMap":48},[112,4658,4659],{"class":114,"line":115},[112,4660,4661],{},"DriveMotor intakeMotor = null; \u002F\u002F no object yet\n",[112,4663,4664],{"class":114,"line":49},[112,4665,4666],{},"intakeMotor = new DriveMotor(7); \u002F\u002F now it does\n",[15,4668,4669,4670,4672,4673,4675,4676,4679],{},"Calling a method on a ",[95,4671,4645],{}," reference — one that still holds ",[95,4674,4645],{}," because no object was ever assigned to it — throws a ",[95,4677,4678],{},"NullPointerException"," at runtime (more on this in the next lesson).",[69,4681,4683],{"id":4682},"constructor-signatures","Constructor Signatures",[15,4685,4686],{},"Just like methods, a constructor has a signature: its name (always the same as the class) plus its parameter types. Look up a library class's constructors in its documentation (its API page's Constructor Summary — Lesson 3.2) to see what arguments it expects and in what order.",[104,4688,4690],{"className":106,"code":4689,"language":108,"meta":48,"style":48},"public class Pose2d {\n    public Pose2d() { \u002F* not shown *\u002F }\n    public Pose2d(double x, double y, Rotation2d rotation) { \u002F* not shown *\u002F }\n}\n",[95,4691,4692,4697,4702,4707],{"__ignoreMap":48},[112,4693,4694],{"class":114,"line":115},[112,4695,4696],{},"public class Pose2d {\n",[112,4698,4699],{"class":114,"line":49},[112,4700,4701],{},"    public Pose2d() { \u002F* not shown *\u002F }\n",[112,4703,4704],{"class":114,"line":126},[112,4705,4706],{},"    public Pose2d(double x, double y, Rotation2d rotation) { \u002F* not shown *\u002F }\n",[112,4708,4709],{"class":114,"line":132},[112,4710,153],{},[69,4712,462],{"id":461},[19,4714,4715,4728,4742],{},[22,4716,4717,476,4722,4725,4726,79],{},[25,4718,4719,4720,79],{},"Forgetting ",[95,4721,2504],{},[95,4723,4724],{},"DriveMotor leftMotor = DriveMotor(5);"," doesn't compile — creating an object always requires ",[95,4727,2504],{},[22,4729,4730,4733,4734,4737,4738,4741],{},[25,4731,4732],{},"Mixing up argument order."," A constructor taking ",[95,4735,4736],{},"(x, y, rotation)"," called as ",[95,4739,4740],{},"(rotation, x, y)"," either won't compile (wrong types) or, worse, compiles with the wrong values silently swapped.",[22,4743,4744,476,4749,4752,4753,4756,4757,4759,4760,4763,4764,4767],{},[25,4745,4669,4746,4748],{},[95,4747,4645],{}," reference.",[95,4750,4751],{},"DriveMotor m = null;"," followed by ",[95,4754,4755],{},"m.setThrottle(0.5);"," compiles, but crashes with a ",[95,4758,4678],{}," at runtime. (A local variable given no value at all — just ",[95,4761,4762],{},"DriveMotor m;"," — is different: Java won't compile code that reads ",[95,4765,4766],{},"m"," before it's assigned, reporting \"variable m might not have been initialized.\")",[69,4769,501],{"id":500},[19,4771,4772,4778,4781,4789,4796],{},[22,4773,4774,4777],{},[95,4775,4776],{},"new ClassName(arguments)"," calls a constructor to build and initialize an object.",[22,4779,4780],{},"A class can have multiple overloaded constructors, differing in their parameter lists.",[22,4782,4783,4784,4786,4787,79],{},"A reference variable can be ",[95,4785,4645],{}," — pointing at no object at all — until it's assigned a real one with ",[95,4788,2504],{},[22,4790,4669,4791,4793,4794,79],{},[95,4792,4645],{}," reference throws a ",[95,4795,4678],{},[22,4797,4798],{},"Constructor argument order must match the constructor's signature exactly.",[15,4800,544,4801,548,4803,4806],{},[95,4802,547],{},[95,4804,4805],{},"unit-1-using-objects-and-methods\u002F1.13-creating-and-initializing-objects-constructors.md"," (CSA 1.13)",[554,4808,556],{},{"title":48,"searchDepth":49,"depth":49,"links":4810},[4811,4813,4814,4816,4817,4818],{"id":4558,"depth":49,"text":4812},"Building an Object with new",{"id":4587,"depth":49,"text":4588},{"id":4641,"depth":49,"text":4815},"Object References and null",{"id":4682,"depth":49,"text":4683},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":4820,"status":570},"4.5 — Creating and Initializing Objects: Constructors (CSA 1.13)","\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F5-creating-and-initializing-objects-constructors",{"title":4550,"description":48},"shockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.5-creating-and-initializing-objects-constructors","rVf19cPJ49e-ihpDZ8NFYB3Q7ttcmJAJbCGZpesP-A8",{"id":4826,"title":4827,"body":4828,"description":48,"extension":51,"meta":5053,"navigation":55,"path":5055,"seo":5056,"stem":5057,"__hash__":5058},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.6-calling-instance-methods.md","Calling Instance Methods",{"type":8,"value":4829,"toc":5045},[4830,4833,4837,4848,4863,4879,4882,4897,4912,4916,4919,4934,4943,4947,4961,4976,4978,5018,5020,5035,5043],[11,4831,4827],{"id":4832},"calling-instance-methods",[69,4834,4836],{"id":4835},"instance-methods-vs-static-methods","Instance Methods vs. Static Methods",[15,4838,4839,4840,4843,4844,4847],{},"Lesson 4.2 covered static (class) methods, called via the class name. An ",[25,4841,4842],{},"instance method"," is the opposite: it's always called on a specific object, and it reads or changes ",[494,4845,4846],{},"that object's"," attributes.",[104,4849,4851],{"className":106,"code":4850,"language":108,"meta":48,"style":48},"\u002F\u002F instance method — acts on leftMotor specifically, not DriveMotor in general\nleftMotor.setThrottle(0.5);\n",[95,4852,4853,4858],{"__ignoreMap":48},[112,4854,4855],{"class":114,"line":115},[112,4856,4857],{},"\u002F\u002F instance method — acts on leftMotor specifically, not DriveMotor in general\n",[112,4859,4860],{"class":114,"line":49},[112,4861,4862],{},"leftMotor.setThrottle(0.5);\n",[15,4864,4865,4868,4869,4872,4873,4875,4876,4878],{},[95,4866,4867],{},"Math.sqrt(9)"," doesn't care which object called it (there is no object) — it's pure computation. ",[95,4870,4871],{},"leftMotor.setThrottle(0.5)"," only makes sense applied to one specific motor. (",[95,4874,4337],{}," is a ",[95,4877,4333],{},", the team's own motor class from Lesson 4.4.)",[69,4880,4678],{"id":4881},"nullpointerexception",[15,4883,4884,4885,4887,4888,4890,4891,4893,4894,4896],{},"Calling a method on a reference that holds ",[95,4886,4645],{}," — set to ",[95,4889,4645],{}," and never assigned a real object with ",[95,4892,2504],{}," — throws a ",[95,4895,4678],{}," at runtime. This is one of the most common real bugs in object-oriented code:",[104,4898,4900],{"className":106,"code":4899,"language":108,"meta":48,"style":48},"DriveMotor intakeMotor = null;\nintakeMotor.setThrottle(0.5); \u002F\u002F crashes: intakeMotor doesn't refer to a real object\n",[95,4901,4902,4907],{"__ignoreMap":48},[112,4903,4904],{"class":114,"line":115},[112,4905,4906],{},"DriveMotor intakeMotor = null;\n",[112,4908,4909],{"class":114,"line":49},[112,4910,4911],{},"intakeMotor.setThrottle(0.5); \u002F\u002F crashes: intakeMotor doesn't refer to a real object\n",[69,4913,4915],{"id":4914},"methods-with-arguments","Methods With Arguments",[15,4917,4918],{},"Just like the constructors from the last lesson, instance methods can take arguments:",[104,4920,4922],{"className":106,"code":4921,"language":108,"meta":48,"style":48},"leftMotor.setThrottle(0.5);    \u002F\u002F 0.5 is the argument: half throttle forward\nelevator.moveToPosition(24.0); \u002F\u002F 24.0 is the argument, saved into the method's parameter\n",[95,4923,4924,4929],{"__ignoreMap":48},[112,4925,4926],{"class":114,"line":115},[112,4927,4928],{},"leftMotor.setThrottle(0.5);    \u002F\u002F 0.5 is the argument: half throttle forward\n",[112,4930,4931],{"class":114,"line":49},[112,4932,4933],{},"elevator.moveToPosition(24.0); \u002F\u002F 24.0 is the argument, saved into the method's parameter\n",[15,4935,1866,4936,4939,4940,1566],{},[95,4937,4938],{},"elevator"," is an object of another of the team's own classes, ",[95,4941,4942],{},"Elevator",[69,4944,4946],{"id":4945},"getters-accessors","Getters (Accessors)",[15,4948,4949,4950,4953,4954,4957,4958,4960],{},"A method that just reports one of an object's attributes — no side effects, just returns a value — is a ",[25,4951,4952],{},"getter"," (formally, an accessor). By convention its name starts with ",[95,4955,4956],{},"get",", and its return value should actually be used. ",[95,4959,4409],{}," reports the last throttle this motor was told to run at:",[104,4962,4964],{"className":106,"code":4963,"language":108,"meta":48,"style":48},"double throttle = leftMotor.getThrottle(); \u002F\u002F a getter — use the returned value\nSystem.out.println(\"Current throttle: \" + leftMotor.getThrottle());\n",[95,4965,4966,4971],{"__ignoreMap":48},[112,4967,4968],{"class":114,"line":115},[112,4969,4970],{},"double throttle = leftMotor.getThrottle(); \u002F\u002F a getter — use the returned value\n",[112,4972,4973],{"class":114,"line":49},[112,4974,4975],{},"System.out.println(\"Current throttle: \" + leftMotor.getThrottle());\n",[69,4977,462],{"id":461},[19,4979,4980,4996,5009],{},[22,4981,4982,476,4985,4988,4989,4992,4993,4995],{},[25,4983,4984],{},"Calling an instance method without an object.",[95,4986,4987],{},"DriveMotor.setThrottle(0.5)"," doesn't compile — Java reports \"non-static method setThrottle(double) cannot be referenced from a static context,\" because ",[95,4990,4991],{},"setThrottle"," needs a specific motor to act on. Only ",[95,4994,4871],{}," works.",[22,4997,4998,5002,5003,5005,5006,5008],{},[25,4999,4669,5000,4748],{},[95,5001,4645],{}," The single most common source of ",[95,5004,4678],{}," — make sure every object is actually constructed with ",[95,5007,2504],{}," before calling anything on it.",[22,5010,5011,476,5014,5017],{},[25,5012,5013],{},"Ignoring a getter's return value.",[95,5015,5016],{},"leftMotor.getThrottle();"," alone does nothing useful — a getter exists specifically to report a value you then use.",[69,5019,501],{"id":500},[19,5021,5022,5025,5032],{},[22,5023,5024],{},"An instance method is called on a specific object and can read\u002Fchange that object's own attributes; a static method belongs to the class itself.",[22,5026,4669,5027,4793,5029,5031],{},[95,5028,4645],{},[95,5030,4678],{}," — one of the most common real bugs.",[22,5033,5034],{},"A getter (accessor) reports one of an object's attributes; its return value should be used, not ignored.",[15,5036,544,5037,548,5039,5042],{},[95,5038,547],{},[95,5040,5041],{},"unit-1-using-objects-and-methods\u002F1.14-calling-instance-methods.md"," (CSA 1.14)",[554,5044,556],{},{"title":48,"searchDepth":49,"depth":49,"links":5046},[5047,5048,5049,5050,5051,5052],{"id":4835,"depth":49,"text":4836},{"id":4881,"depth":49,"text":4678},{"id":4914,"depth":49,"text":4915},{"id":4945,"depth":49,"text":4946},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":5054,"status":570},"4.6 — Calling Instance Methods (CSA 1.14)","\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F6-calling-instance-methods",{"title":4827,"description":48},"shockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.6-calling-instance-methods","N6yitUM9ABivsdtdYA0uWRq6a0DaYHeC4p6ABgFEzjI",{"id":5060,"title":5061,"body":5062,"description":48,"extension":51,"meta":5366,"navigation":55,"path":5369,"seo":5370,"stem":5371,"__hash__":5372},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.1-5.2-if-statements-and-for-loops.md","Control Structures: if Statements & For Loops",{"type":8,"value":5063,"toc":5358},[5064,5067,5071,5076,5099,5106,5145,5148,5158,5180,5184,5190,5226,5249,5265,5283,5285,5319,5321,5347,5356],[11,5065,5061],{"id":5066},"control-structures-if-statements-for-loops",[69,5068,5070],{"id":5069},"if-statements-one-way-and-two-way-selection","if Statements: One-Way and Two-Way Selection",[15,5072,1851,5073,5075],{},[95,5074,2179],{}," statement runs its body only when a boolean condition is true:",[104,5077,5079],{"className":106,"code":5078,"language":108,"meta":48,"style":48},"if (joystick.getRawButton(1))\n{\n    intake.spin(0.5);\n}\n",[95,5080,5081,5086,5090,5095],{"__ignoreMap":48},[112,5082,5083],{"class":114,"line":115},[112,5084,5085],{},"if (joystick.getRawButton(1))\n",[112,5087,5088],{"class":114,"line":49},[112,5089,123],{},[112,5091,5092],{"class":114,"line":126},[112,5093,5094],{},"    intake.spin(0.5);\n",[112,5096,5097],{"class":114,"line":132},[112,5098,153],{},[15,5100,5101,5102,5105],{},"Add an ",[95,5103,5104],{},"else"," for a second branch that runs when the condition is false:",[104,5107,5109],{"className":106,"code":5108,"language":108,"meta":48,"style":48},"if (joystick.getRawButton(1))\n{\n    intake.spin(0.5);\n}\nelse\n{\n    intake.stop();\n}\n",[95,5110,5111,5115,5119,5123,5127,5132,5136,5141],{"__ignoreMap":48},[112,5112,5113],{"class":114,"line":115},[112,5114,5085],{},[112,5116,5117],{"class":114,"line":49},[112,5118,123],{},[112,5120,5121],{"class":114,"line":126},[112,5122,5094],{},[112,5124,5125],{"class":114,"line":132},[112,5126,153],{},[112,5128,5129],{"class":114,"line":138},[112,5130,5131],{},"else\n",[112,5133,5134],{"class":114,"line":144},[112,5135,123],{},[112,5137,5138],{"class":114,"line":150},[112,5139,5140],{},"    intake.stop();\n",[112,5142,5143],{"class":114,"line":2276},[112,5144,153],{},[15,5146,5147],{},"Always use curly braces, even for a single statement — Java doesn't require them, but skipping them is exactly how the classic \"which statement is actually inside the if\" bug happens.",[69,5149,5151,5152,5154,5155,5157],{"id":5150},"the-classic-vs-mistake","The Classic ",[95,5153,737],{}," vs. ",[95,5156,1921],{}," Mistake",[15,5159,5160,5161,5163,5164,5166,5167,5170,5171,4029,5173,5176,5177,5179],{},"One ",[95,5162,737],{}," assigns a value; two ",[95,5165,1921],{}," test whether a value equals something. Writing ",[95,5168,5169],{},"if (isCold = true)"," inside a condition compiles (it's a legal assignment expression) but silently does the wrong thing — it assigns ",[95,5172,661],{},[95,5174,5175],{},"isCold"," and the condition is always true, regardless of what ",[95,5178,5175],{}," was before.",[69,5181,5183],{"id":5182},"for-loops-three-parts-one-line","For Loops: Three Parts, One Line",[15,5185,405,5186,5189],{},[95,5187,5188],{},"for"," loop bundles the three steps of a loop — initialize, test, update — into one header:",[104,5191,5193],{"className":106,"code":5192,"language":108,"meta":48,"style":48},"for (int i = 0; i \u003C sensors.length; i++)\n{\n    if (sensors[i].isFaulty())\n    {\n        report(sensors[i]);\n    }\n}\n",[95,5194,5195,5200,5204,5209,5213,5218,5222],{"__ignoreMap":48},[112,5196,5197],{"class":114,"line":115},[112,5198,5199],{},"for (int i = 0; i \u003C sensors.length; i++)\n",[112,5201,5202],{"class":114,"line":49},[112,5203,123],{},[112,5205,5206],{"class":114,"line":126},[112,5207,5208],{},"    if (sensors[i].isFaulty())\n",[112,5210,5211],{"class":114,"line":132},[112,5212,135],{},[112,5214,5215],{"class":114,"line":138},[112,5216,5217],{},"        report(sensors[i]);\n",[112,5219,5220],{"class":114,"line":144},[112,5221,147],{},[112,5223,5224],{"class":114,"line":150},[112,5225,153],{},[15,5227,5228],{},[494,5229,5230,5233,5234,5237,5238,5241,5242,5245,5246,5248],{},[95,5231,5232],{},"sensors"," here is an array — a numbered list of values: ",[95,5235,5236],{},"sensors.length"," is how many there are, and ",[95,5239,5240],{},"sensors[i]"," is the one at position ",[95,5243,5244],{},"i",", counting from ",[95,5247,1365],{},". Arrays get their own full lesson in Ch.9; for now, focus on the loop's shape.",[15,5250,5251,5252,5254,5255,5258,5259,5254,5261,5264],{},"The three parts are always separated by semicolons, in this order: initialize the loop variable, test it, update it. Starting at ",[95,5253,1365],{}," pairs naturally with ",[95,5256,5257],{},"\u003C","; starting at ",[95,5260,1294],{},[95,5262,5263],{},"\u003C="," — pick whichever matches how many times you actually want to run.",[15,5266,5267,5268,845,5271,5274,5275,5278,5279,5282],{},"The update doesn't have to be ",[95,5269,5270],{},"i++",[95,5272,5273],{},"for (int i = 10; i > 0; i--)"," counts down from 10 to 1, and ",[95,5276,5277],{},"for (int i = 0; i \u003C= 10; i += 2)"," steps by two: 0, 2, 4, … 10. A loop variable declared in the header, like ",[95,5280,5281],{},"int i",", exists only inside that loop.",[69,5284,462],{"id":461},[19,5286,5287,5296,5306],{},[22,5288,5289,5292,5293,5295],{},[25,5290,5291],{},"Missing curly braces."," Without them, only the very next line is actually part of the ",[95,5294,2179],{},"\u002Floop body — everything after it runs unconditionally, every time.",[22,5297,5298,5305],{},[25,5299,5300,3181,5302,5304],{},[95,5301,737],{},[95,5303,1921],{}," in a condition."," A real, silent bug — the code compiles and the condition is always true.",[22,5307,5308,476,5311,5314,5315,5318],{},[25,5309,5310],{},"Off-by-one in a for loop's bound.",[95,5312,5313],{},"i \u003C sensors.length"," visits every valid index; ",[95,5316,5317],{},"i \u003C= sensors.length"," runs one iteration too many and reads past the end.",[69,5320,501],{"id":500},[19,5322,5323,5331,5334,5342],{},[22,5324,1851,5325,5327,5328,5330],{},[95,5326,2179],{}," runs its body only when its condition is true; an ",[95,5329,5104],{}," gives it a second branch for when it's false.",[22,5332,5333],{},"Always use curly braces around a conditional or loop body.",[22,5335,5336,5338,5339,5341],{},[95,5337,1921],{}," tests equality; ",[95,5340,737],{}," assigns. Confusing them compiles but silently breaks the logic.",[22,5343,405,5344,5346],{},[95,5345,5188],{}," loop's header has three parts — initialize, test, update — always in that order, separated by semicolons.",[15,5348,5349,476,5352,5355],{},[25,5350,5351],{},"Deck context:",[95,5353,5354],{},"mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-1.js",", slide 5 (\"CONTROL STRUCTURES\")",[554,5357,556],{},{"title":48,"searchDepth":49,"depth":49,"links":5359},[5360,5361,5363,5364,5365],{"id":5069,"depth":49,"text":5070},{"id":5150,"depth":49,"text":5362},"The Classic = vs. == Mistake",{"id":5182,"depth":49,"text":5183},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":5367,"status":5368},"5.1 (if Statements, CSA 2.3) + 5.2 (For Loops, CSA 2.8) — combined","new — authored lesson (fuller depth than the teaser slide). This single lesson covers both items together, matching the existing deck slide's combined granularity.","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F1-5.2-if-statements-and-for-loops",{"title":5061,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.1-5.2-if-statements-and-for-loops","c0wvDyVf_4HLg9US7Mce0gY1xXHFLRdCXj16jH4P3fU",{"id":5374,"title":5375,"body":5376,"description":48,"extension":51,"meta":5525,"navigation":55,"path":5527,"seo":5528,"stem":5529,"__hash__":5530},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.10-nested-iteration.md","Nested Iteration",{"type":8,"value":5377,"toc":5519},[5378,5381,5385,5392,5428,5442,5444,5447,5449,5488,5490,5509,5517],[11,5379,5375],{"id":5380},"nested-iteration",[69,5382,5384],{"id":5383},"a-loop-inside-a-loop","A Loop Inside a Loop",[15,5386,5387,5388,5391],{},"Nesting one loop inside another means the inner loop runs to completion for ",[494,5389,5390],{},"every single pass"," of the outer one:",[104,5393,5395],{"className":106,"code":5394,"language":108,"meta":48,"style":48},"for (int row = 0; row \u003C 8; row++)\n{\n    for (int col = 0; col \u003C 8; col++)\n    {\n        visionGrid[row][col] = sampleCell(row, col);\n    }\n}\n",[95,5396,5397,5402,5406,5411,5415,5420,5424],{"__ignoreMap":48},[112,5398,5399],{"class":114,"line":115},[112,5400,5401],{},"for (int row = 0; row \u003C 8; row++)\n",[112,5403,5404],{"class":114,"line":49},[112,5405,123],{},[112,5407,5408],{"class":114,"line":126},[112,5409,5410],{},"    for (int col = 0; col \u003C 8; col++)\n",[112,5412,5413],{"class":114,"line":132},[112,5414,135],{},[112,5416,5417],{"class":114,"line":138},[112,5418,5419],{},"        visionGrid[row][col] = sampleCell(row, col);\n",[112,5421,5422],{"class":114,"line":144},[112,5423,147],{},[112,5425,5426],{"class":114,"line":150},[112,5427,153],{},[15,5429,5430,5431,5434,5435,5438,5439,5441],{},"For each value of ",[95,5432,5433],{},"row",", the inner loop runs all the way through every ",[95,5436,5437],{},"col"," value before the outer loop advances to the next ",[95,5440,5433],{},". The inner loop restarts from scratch each time.",[69,5443,2539],{"id":2538},[15,5445,5446],{},"Nested loops are the natural shape for anything grid-like: scanning a 2D vision frame, checking every pair of sensors against each other, or generating a table of test cases. (2D arrays, which pair naturally with nested loops, get their own full chapter — Ch.10.)",[69,5448,462],{"id":461},[19,5450,5451,5479],{},[22,5452,5453,476,5456,5459,5460,5462,5463,5465,5466,5469,5470,176,5472,322,5474,176,5476,4410],{},[25,5454,5455],{},"Reusing the same loop variable name for both loops.",[95,5457,5458],{},"for (int i ...)"," nested inside another ",[95,5461,5458],{}," won't compile — the outer ",[95,5464,5244],{}," is still in scope inside the inner loop, so the compiler reports ",[95,5467,5468],{},"variable i is already defined",". Use distinct names (",[95,5471,5433],{},[95,5473,5437],{},[95,5475,5244],{},[95,5477,5478],{},"j",[22,5480,5481,5484,5485,5487],{},[25,5482,5483],{},"Assuming the inner loop's variable persists across outer iterations."," It doesn't — a loop variable declared in the ",[95,5486,5188],{}," header is freshly initialized every time that loop starts, including every restart of an inner loop.",[69,5489,501],{"id":500},[19,5491,5492,5495,5498],{},[22,5493,5494],{},"A loop nested inside another runs completely, every single time the outer loop takes one step.",[22,5496,5497],{},"Nested loops are the standard shape for anything grid-shaped — rows and columns, pairs of items, tables of test cases.",[22,5499,5500,5501,176,5503,959,5505,176,5507,4410],{},"Use distinct loop variable names for nested loops (",[95,5502,5433],{},[95,5504,5437],{},[95,5506,5244],{},[95,5508,5244],{},[15,5510,544,5511,548,5513,5516],{},[95,5512,547],{},[95,5514,5515],{},"unit-2-selection-and-iteration\u002F2.11-nested-iteration.md"," (CSA 2.11)",[554,5518,556],{},{"title":48,"searchDepth":49,"depth":49,"links":5520},[5521,5522,5523,5524],{"id":5383,"depth":49,"text":5384},{"id":2538,"depth":49,"text":2539},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":5526,"status":570},"5.10 — Nested Iteration (CSA 2.11)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F10-nested-iteration",{"title":5375,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.10-nested-iteration","fEKulmvEeV3ALSZzGDbqlJktfbinM4YbiKXMb4HgrjU",{"id":5532,"title":5533,"body":5534,"description":48,"extension":51,"meta":5677,"navigation":55,"path":5679,"seo":5680,"stem":5681,"__hash__":5682},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.11-informal-runtime-analysis-of-loops.md","Informal Runtime Analysis of Loops",{"type":8,"value":5535,"toc":5670},[5536,5539,5543,5546,5555,5568,5572,5575,5603,5605,5608,5610,5644,5646,5660,5668],[11,5537,5533],{"id":5538},"informal-runtime-analysis-of-loops",[69,5540,5542],{"id":5541},"counting-iterations-without-running-the-code","Counting Iterations Without Running the Code",[15,5544,5545],{},"You can predict exactly how many times a loop runs just by reading its header:",[104,5547,5549],{"className":106,"code":5548,"language":108,"meta":48,"style":48},"for (int i = 3; i \u003C 7; i++) { ... } \u002F\u002F runs 6 - 3 + 1 = 4 times\n",[95,5550,5551],{"__ignoreMap":48},[112,5552,5553],{"class":114,"line":115},[112,5554,5548],{},[15,5556,5557,5558,5561,5562,5564,5565,5567],{},"The formula: ",[95,5559,5560],{},"largest value the loop variable reaches − smallest value + 1",". For a ",[95,5563,5257],{}," bound, the largest value is one less than the limit; for ",[95,5566,5263],{},", it's the limit itself.",[69,5569,5571],{"id":5570},"nested-loops-multiply","Nested Loops Multiply",[15,5573,5574],{},"A nested loop's total iteration count is outer iterations × inner iterations:",[104,5576,5578],{"className":106,"code":5577,"language":108,"meta":48,"style":48},"\u002F\u002F 5 outer passes × 10 inner passes = 50 total iterations\nfor (int row = 0; row \u003C 5; row++)\n{\n    for (int col = 0; col \u003C 10; col++) { ... }\n}\n",[95,5579,5580,5585,5590,5594,5599],{"__ignoreMap":48},[112,5581,5582],{"class":114,"line":115},[112,5583,5584],{},"\u002F\u002F 5 outer passes × 10 inner passes = 50 total iterations\n",[112,5586,5587],{"class":114,"line":49},[112,5588,5589],{},"for (int row = 0; row \u003C 5; row++)\n",[112,5591,5592],{"class":114,"line":126},[112,5593,123],{},[112,5595,5596],{"class":114,"line":132},[112,5597,5598],{},"    for (int col = 0; col \u003C 10; col++) { ... }\n",[112,5600,5601],{"class":114,"line":138},[112,5602,153],{},[69,5604,2539],{"id":2538},[15,5606,5607],{},"Being able to predict a loop's iteration count without running it is a real debugging tool — if a loop is running way more (or fewer) times than expected, tracing through this formula by hand usually finds the off-by-one or the wrong bound immediately, faster than adding print statements and re-running.",[69,5609,462],{"id":461},[19,5611,5612,5638],{},[22,5613,5614,476,5620,5623,5624,5626,5627,5630,5631,5634,5635,5637],{},[25,5615,5616,5617,5619],{},"Forgetting to subtract 1 for a ",[95,5618,5257],{}," bound.",[95,5621,5622],{},"i \u003C 7"," starting at ",[95,5625,1754],{}," reaches ",[95,5628,5629],{},"3, 4, 5, 6"," — four values, not ",[95,5632,5633],{},"7 − 3 + 1 = 5"," (that would treat ",[95,5636,3863],{}," itself as reached).",[22,5639,5640,5643],{},[25,5641,5642],{},"Multiplying the wrong two numbers for a nested loop."," It's outer-count × inner-count-per-outer-pass, not outer-count + inner-count.",[69,5645,501],{"id":500},[19,5647,5648,5654,5657],{},[22,5649,5650,5651,79],{},"A loop's iteration count is ",[95,5652,5653],{},"largest reachable value − smallest value + 1",[22,5655,5656],{},"Nested loops multiply: total iterations = outer count × inner count.",[22,5658,5659],{},"Counting iterations by hand is a fast way to catch an off-by-one bug before it turns into a mysterious runtime problem.",[15,5661,544,5662,548,5664,5667],{},[95,5663,547],{},[95,5665,5666],{},"unit-2-selection-and-iteration\u002F2.12-informal-runtime-analysis-of-loops.md"," (CSA 2.12)",[554,5669,556],{},{"title":48,"searchDepth":49,"depth":49,"links":5671},[5672,5673,5674,5675,5676],{"id":5541,"depth":49,"text":5542},{"id":5570,"depth":49,"text":5571},{"id":2538,"depth":49,"text":2539},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":5678,"status":570},"5.11 — Informal Runtime Analysis of Loops (CSA 2.12)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F11-informal-runtime-analysis-of-loops",{"title":5533,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.11-informal-runtime-analysis-of-loops","66iCTNBFLEET2q9XfCrZlnUmB_XNETCkSAklpjiJshM",{"id":5684,"title":5685,"body":5686,"description":6561,"extension":51,"meta":6562,"navigation":55,"path":6565,"seo":6566,"stem":6567,"__hash__":6568},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.12-switch-statements-and-expressions.md","switch Statements and Expressions",{"type":8,"value":5687,"toc":6549},[5688,5691,5702,5706,5797,5827,5860,5864,5879,5933,5952,5956,5962,6020,6030,6034,6102,6114,6118,6131,6185,6197,6201,6214,6271,6294,6298,6307,6363,6383,6387,6406,6408,6480,6482,6542,6547],[11,5689,5685],{"id":5690},"switch-statements-and-expressions",[15,5692,5693,5694,5697,5698,5701],{},"When one value decides between many fixed choices, an ",[95,5695,5696],{},"else if"," chain (Lesson 5.5) ends up comparing the same variable over and over. A ",[95,5699,5700],{},"switch"," says it directly: look at one value, then jump to the case that matches it.",[69,5703,5705],{"id":5704},"the-classic-switch-statement","The Classic switch Statement",[104,5707,5709],{"className":106,"code":5708,"language":108,"meta":48,"style":48},"int autoMode = 2;\n\nswitch (autoMode)\n{\n    case 1:\n        System.out.println(\"Drive forward\");\n        break;\n    case 2:\n        System.out.println(\"Score one piece\");\n        break;\n    case 3:\n        System.out.println(\"Score two pieces\");\n        break;\n    default:\n        System.out.println(\"Do nothing\");\n        break;\n}\n",[95,5710,5711,5716,5720,5725,5729,5734,5739,5744,5749,5754,5758,5764,5770,5775,5781,5787,5792],{"__ignoreMap":48},[112,5712,5713],{"class":114,"line":115},[112,5714,5715],{},"int autoMode = 2;\n",[112,5717,5718],{"class":114,"line":49},[112,5719,907],{"emptyLinePlaceholder":55},[112,5721,5722],{"class":114,"line":126},[112,5723,5724],{},"switch (autoMode)\n",[112,5726,5727],{"class":114,"line":132},[112,5728,123],{},[112,5730,5731],{"class":114,"line":138},[112,5732,5733],{},"    case 1:\n",[112,5735,5736],{"class":114,"line":144},[112,5737,5738],{},"        System.out.println(\"Drive forward\");\n",[112,5740,5741],{"class":114,"line":150},[112,5742,5743],{},"        break;\n",[112,5745,5746],{"class":114,"line":2276},[112,5747,5748],{},"    case 2:\n",[112,5750,5751],{"class":114,"line":2282},[112,5752,5753],{},"        System.out.println(\"Score one piece\");\n",[112,5755,5756],{"class":114,"line":2288},[112,5757,5743],{},[112,5759,5761],{"class":114,"line":5760},11,[112,5762,5763],{},"    case 3:\n",[112,5765,5767],{"class":114,"line":5766},12,[112,5768,5769],{},"        System.out.println(\"Score two pieces\");\n",[112,5771,5773],{"class":114,"line":5772},13,[112,5774,5743],{},[112,5776,5778],{"class":114,"line":5777},14,[112,5779,5780],{},"    default:\n",[112,5782,5784],{"class":114,"line":5783},15,[112,5785,5786],{},"        System.out.println(\"Do nothing\");\n",[112,5788,5790],{"class":114,"line":5789},16,[112,5791,5743],{},[112,5793,5795],{"class":114,"line":5794},17,[112,5796,153],{},[15,5798,5799,5800,5803,5804,5807,5808,5810,5811,5813,5814,5817,5818,5820,5821,5823,5824,5826],{},"Java evaluates the value in parentheses once, jumps to the ",[95,5801,5802],{},"case"," whose label matches it, and runs the statements from there. ",[95,5805,5806],{},"break"," ends the whole ",[95,5809,5700],{}," — the same ",[95,5812,5806],{}," that leaves a loop early in Lesson 5.8. ",[95,5815,5816],{},"default"," runs when no label matches, like the trailing ",[95,5819,5104],{}," of an ",[95,5822,5696],{}," chain; it's optional in a ",[95,5825,5700],{}," statement, but leaving it off makes \"do nothing\" a real outcome.",[15,5828,5829,5830,260,5832,5835,5836,5839,5840,176,5842,5844,5845,5847,5848,5847,5850,5852,5853,5847,5855,5857,5858,79],{},"Case labels must be fixed values, like ",[95,5831,2349],{},[95,5833,5834],{},"\"RED\""," — never a condition such as ",[95,5837,5838],{},"autoMode > 2",". For ranges, use an ",[95,5841,2179],{},[95,5843,5104],{}," chain. You can switch on an ",[95,5846,603],{},", a ",[95,5849,686],{},[95,5851,361],{}," or an enum (Ch.11) — but not on a ",[95,5854,616],{},[95,5856,631],{}," or a ",[95,5859,657],{},[69,5861,5863],{"id":5862},"fall-through-what-happens-without-break","Fall-Through: What Happens Without break",[15,5865,5866,5867,5869,5870,5873,5874,5876,5877,738],{},"Leave out a ",[95,5868,5806],{},", and execution doesn't stop at the next label — it ",[494,5871,5872],{},"falls through"," and keeps running the following case's statements, ignoring that case's label, until it reaches a ",[95,5875,5806],{}," or the end of the ",[95,5878,5700],{},[104,5880,5882],{"className":106,"code":5881,"language":108,"meta":48,"style":48},"switch (autoMode)\n{\n    case 1:\n        System.out.println(\"Drive forward\");\n        \u002F\u002F no break: falls through into case 2\n    case 2:\n        System.out.println(\"Score one piece\");\n        break;\n    default:\n        System.out.println(\"Do nothing\");\n        break;\n}\n",[95,5883,5884,5888,5892,5896,5900,5905,5909,5913,5917,5921,5925,5929],{"__ignoreMap":48},[112,5885,5886],{"class":114,"line":115},[112,5887,5724],{},[112,5889,5890],{"class":114,"line":49},[112,5891,123],{},[112,5893,5894],{"class":114,"line":126},[112,5895,5733],{},[112,5897,5898],{"class":114,"line":132},[112,5899,5738],{},[112,5901,5902],{"class":114,"line":138},[112,5903,5904],{},"        \u002F\u002F no break: falls through into case 2\n",[112,5906,5907],{"class":114,"line":144},[112,5908,5748],{},[112,5910,5911],{"class":114,"line":150},[112,5912,5753],{},[112,5914,5915],{"class":114,"line":2276},[112,5916,5743],{},[112,5918,5919],{"class":114,"line":2282},[112,5920,5780],{},[112,5922,5923],{"class":114,"line":2288},[112,5924,5786],{},[112,5926,5927],{"class":114,"line":5760},[112,5928,5743],{},[112,5930,5931],{"class":114,"line":5766},[112,5932,153],{},[15,5934,5935,5936,5939,5940,5942,5943,537,5946,5949,5950,79],{},"With ",[95,5937,5938],{},"autoMode"," set to ",[95,5941,1294],{},", this prints both ",[95,5944,5945],{},"Drive forward",[95,5947,5948],{},"Score one piece",". Fall-through is occasionally what you want, but far more often it's a forgotten ",[95,5951,5806],{},[69,5953,5955],{"id":5954},"several-labels-one-action","Several Labels, One Action",[15,5957,5958,5959,5961],{},"When several values should do the same thing, list them in one ",[95,5960,5802],{},", separated by commas:",[104,5963,5965],{"className":106,"code":5964,"language":108,"meta":48,"style":48},"switch (buttonNumber)\n{\n    case 1, 2:\n        System.out.println(\"Intake\");\n        break;\n    case 3:\n        System.out.println(\"Shoot\");\n        break;\n    default:\n        System.out.println(\"Unmapped button\");\n        break;\n}\n",[95,5966,5967,5972,5976,5981,5986,5990,5994,5999,6003,6007,6012,6016],{"__ignoreMap":48},[112,5968,5969],{"class":114,"line":115},[112,5970,5971],{},"switch (buttonNumber)\n",[112,5973,5974],{"class":114,"line":49},[112,5975,123],{},[112,5977,5978],{"class":114,"line":126},[112,5979,5980],{},"    case 1, 2:\n",[112,5982,5983],{"class":114,"line":132},[112,5984,5985],{},"        System.out.println(\"Intake\");\n",[112,5987,5988],{"class":114,"line":138},[112,5989,5743],{},[112,5991,5992],{"class":114,"line":144},[112,5993,5763],{},[112,5995,5996],{"class":114,"line":150},[112,5997,5998],{},"        System.out.println(\"Shoot\");\n",[112,6000,6001],{"class":114,"line":2276},[112,6002,5743],{},[112,6004,6005],{"class":114,"line":2282},[112,6006,5780],{},[112,6008,6009],{"class":114,"line":2288},[112,6010,6011],{},"        System.out.println(\"Unmapped button\");\n",[112,6013,6014],{"class":114,"line":5760},[112,6015,5743],{},[112,6017,6018],{"class":114,"line":5766},[112,6019,153],{},[15,6021,6022,6023,537,6026,6029],{},"Older code gets the same effect with fall-through, stacking ",[95,6024,6025],{},"case 1:",[95,6027,6028],{},"case 2:"," on separate lines with nothing between them. The comma form says it more clearly.",[69,6031,6033],{"id":6032},"switching-on-a-string","Switching on a String",[104,6035,6037],{"className":106,"code":6036,"language":108,"meta":48,"style":48},"String alliance = \"RED\";\n\nswitch (alliance)\n{\n    case \"RED\":\n        System.out.println(\"Start on the left\");\n        break;\n    case \"BLUE\":\n        System.out.println(\"Start on the right\");\n        break;\n    default:\n        System.out.println(\"Unknown alliance\");\n        break;\n}\n",[95,6038,6039,6044,6048,6053,6057,6062,6067,6071,6076,6081,6085,6089,6094,6098],{"__ignoreMap":48},[112,6040,6041],{"class":114,"line":115},[112,6042,6043],{},"String alliance = \"RED\";\n",[112,6045,6046],{"class":114,"line":49},[112,6047,907],{"emptyLinePlaceholder":55},[112,6049,6050],{"class":114,"line":126},[112,6051,6052],{},"switch (alliance)\n",[112,6054,6055],{"class":114,"line":132},[112,6056,123],{},[112,6058,6059],{"class":114,"line":138},[112,6060,6061],{},"    case \"RED\":\n",[112,6063,6064],{"class":114,"line":144},[112,6065,6066],{},"        System.out.println(\"Start on the left\");\n",[112,6068,6069],{"class":114,"line":150},[112,6070,5743],{},[112,6072,6073],{"class":114,"line":2276},[112,6074,6075],{},"    case \"BLUE\":\n",[112,6077,6078],{"class":114,"line":2282},[112,6079,6080],{},"        System.out.println(\"Start on the right\");\n",[112,6082,6083],{"class":114,"line":2288},[112,6084,5743],{},[112,6086,6087],{"class":114,"line":5760},[112,6088,5780],{},[112,6090,6091],{"class":114,"line":5766},[112,6092,6093],{},"        System.out.println(\"Unknown alliance\");\n",[112,6095,6096],{"class":114,"line":5772},[112,6097,5743],{},[112,6099,6100],{"class":114,"line":5777},[112,6101,153],{},[15,6103,405,6104,6106,6107,6110,6111,6113],{},[95,6105,361],{}," case matches only the exact same text, capital letters included — ",[95,6108,6109],{},"\"red\""," would land in ",[95,6112,5816],{},". (Ch.6 explains how Java compares Strings.)",[69,6115,6117],{"id":6116},"the-arrow-form-no-fall-through","The Arrow Form: No Fall-Through",[15,6119,6120,6121,3181,6124,6127,6128,6130],{},"Writing ",[95,6122,6123],{},"case ... ->",[95,6125,6126],{},"case ...:"," gives each case its own separate body. It never falls through, so there's no ",[95,6129,5806],{}," to forget:",[104,6132,6134],{"className":106,"code":6133,"language":108,"meta":48,"style":48},"switch (autoMode)\n{\n    case 1 -> System.out.println(\"Drive forward\");\n    case 2 ->\n    {\n        System.out.println(\"Score one piece\");\n        System.out.println(\"Then back up\");\n    }\n    case 3, 4 -> System.out.println(\"Score two pieces\");\n    default -> System.out.println(\"Do nothing\");\n}\n",[95,6135,6136,6140,6144,6149,6154,6158,6162,6167,6171,6176,6181],{"__ignoreMap":48},[112,6137,6138],{"class":114,"line":115},[112,6139,5724],{},[112,6141,6142],{"class":114,"line":49},[112,6143,123],{},[112,6145,6146],{"class":114,"line":126},[112,6147,6148],{},"    case 1 -> System.out.println(\"Drive forward\");\n",[112,6150,6151],{"class":114,"line":132},[112,6152,6153],{},"    case 2 ->\n",[112,6155,6156],{"class":114,"line":138},[112,6157,135],{},[112,6159,6160],{"class":114,"line":144},[112,6161,5753],{},[112,6163,6164],{"class":114,"line":150},[112,6165,6166],{},"        System.out.println(\"Then back up\");\n",[112,6168,6169],{"class":114,"line":2276},[112,6170,147],{},[112,6172,6173],{"class":114,"line":2282},[112,6174,6175],{},"    case 3, 4 -> System.out.println(\"Score two pieces\");\n",[112,6177,6178],{"class":114,"line":2288},[112,6179,6180],{},"    default -> System.out.println(\"Do nothing\");\n",[112,6182,6183],{"class":114,"line":5760},[112,6184,153],{},[15,6186,6187,6188,6190,6191,537,6193,6196],{},"A case with one statement puts it right after the arrow; a case with several wraps them in braces. One ",[95,6189,5700],{}," must use one form throughout — you can't mix ",[95,6192,738],{},[95,6194,6195],{},"->"," cases. For new code, the arrow form is usually the better choice.",[69,6198,6200],{"id":6199},"switch-expressions-producing-a-value","switch Expressions: Producing a Value",[15,6202,405,6203,6205,6206,6209,6210,6213],{},[95,6204,5700],{}," can also ",[494,6207,6208],{},"produce a value",", the way ",[95,6211,6212],{},"?:"," does in Lesson 5.5, but for any number of choices:",[104,6215,6217],{"className":106,"code":6216,"language":108,"meta":48,"style":48},"int autoMode = 3;\n\nString plan = switch (autoMode)\n{\n    case 1 -> \"Drive forward\";\n    case 2 -> \"Score one piece\";\n    case 3, 4 -> \"Score two pieces\";\n    default -> \"Do nothing\";\n};\n\nSystem.out.println(plan); \u002F\u002F Score two pieces\n",[95,6218,6219,6224,6228,6233,6237,6242,6247,6252,6257,6262,6266],{"__ignoreMap":48},[112,6220,6221],{"class":114,"line":115},[112,6222,6223],{},"int autoMode = 3;\n",[112,6225,6226],{"class":114,"line":49},[112,6227,907],{"emptyLinePlaceholder":55},[112,6229,6230],{"class":114,"line":126},[112,6231,6232],{},"String plan = switch (autoMode)\n",[112,6234,6235],{"class":114,"line":132},[112,6236,123],{},[112,6238,6239],{"class":114,"line":138},[112,6240,6241],{},"    case 1 -> \"Drive forward\";\n",[112,6243,6244],{"class":114,"line":144},[112,6245,6246],{},"    case 2 -> \"Score one piece\";\n",[112,6248,6249],{"class":114,"line":150},[112,6250,6251],{},"    case 3, 4 -> \"Score two pieces\";\n",[112,6253,6254],{"class":114,"line":2276},[112,6255,6256],{},"    default -> \"Do nothing\";\n",[112,6258,6259],{"class":114,"line":2282},[112,6260,6261],{},"};\n",[112,6263,6264],{"class":114,"line":2288},[112,6265,907],{"emptyLinePlaceholder":55},[112,6267,6268],{"class":114,"line":5760},[112,6269,6270],{},"System.out.println(plan); \u002F\u002F Score two pieces\n",[15,6272,6273,6274,6276,6277,6279,6280,6282,6283,6286,6287,5857,6289,6291,6292,79],{},"Each case's value becomes the value of the whole ",[95,6275,5700],{},". Two rules come with that. The semicolon after the closing brace is required, because the ",[95,6278,5700],{}," is part of an assignment statement. And a ",[95,6281,5700],{}," expression must be ",[494,6284,6285],{},"exhaustive",": every possible value has to produce a result, so a switch expression on an ",[95,6288,603],{},[95,6290,361],{}," needs a ",[95,6293,5816],{},[69,6295,6297],{"id":6296},"yield-when-a-case-needs-more-than-one-line","yield: When a Case Needs More Than One Line",[15,6299,6300,6301,6303,6304,738],{},"If a case in a ",[95,6302,5700],{}," expression needs to do some work before producing its value, give it a block and hand the value back with ",[95,6305,6306],{},"yield",[104,6308,6310],{"className":106,"code":6309,"language":108,"meta":48,"style":48},"double speed = switch (gear)\n{\n    case 1 -> 0.3;\n    case 2 -> 0.6;\n    case 3 ->\n    {\n        System.out.println(\"Top gear: watch the corners\");\n        yield 1.0;\n    }\n    default -> 0.0;\n};\n",[95,6311,6312,6317,6321,6326,6331,6336,6340,6345,6350,6354,6359],{"__ignoreMap":48},[112,6313,6314],{"class":114,"line":115},[112,6315,6316],{},"double speed = switch (gear)\n",[112,6318,6319],{"class":114,"line":49},[112,6320,123],{},[112,6322,6323],{"class":114,"line":126},[112,6324,6325],{},"    case 1 -> 0.3;\n",[112,6327,6328],{"class":114,"line":132},[112,6329,6330],{},"    case 2 -> 0.6;\n",[112,6332,6333],{"class":114,"line":138},[112,6334,6335],{},"    case 3 ->\n",[112,6337,6338],{"class":114,"line":144},[112,6339,135],{},[112,6341,6342],{"class":114,"line":150},[112,6343,6344],{},"        System.out.println(\"Top gear: watch the corners\");\n",[112,6346,6347],{"class":114,"line":2276},[112,6348,6349],{},"        yield 1.0;\n",[112,6351,6352],{"class":114,"line":2282},[112,6353,147],{},[112,6355,6356],{"class":114,"line":2288},[112,6357,6358],{},"    default -> 0.0;\n",[112,6360,6361],{"class":114,"line":5760},[112,6362,6261],{},[15,6364,6365,6367,6368,6370,6371,6373,6374,6376,6377,6379,6380,4410],{},[95,6366,6306],{}," means \"this is the switch's value\" — ",[95,6369,3632],{}," would try to leave the whole method instead. ",[95,6372,6306],{}," also replaces ",[95,6375,5806],{}," if you ever write a ",[95,6378,5700],{}," expression in the colon form (",[95,6381,6382],{},"case 1: yield 0.3;",[69,6384,6386],{"id":6385},"switch-and-enums-ch11","switch and Enums (Ch.11)",[15,6388,6389,6391,6392,6395,6396,6399,6400,6402,6403,6405],{},[95,6390,5700],{}," is at its best with enums, the named sets of choices that Ch.11 introduces — that chapter picks up right where this lesson leaves off. One Java version note to carry there: on Java 21 and later, including Java 25 (this course's target), an enum case label can be written either bare (",[95,6393,6394],{},"case INTAKE ->",") or qualified with the enum's name (",[95,6397,6398],{},"case ArmPosition.INTAKE ->","). On Java 17, only the bare name compiles. Everything else in this lesson — arrow cases, comma-separated labels, ",[95,6401,5700],{}," expressions and ",[95,6404,6306],{}," — has been standard since Java 14, so it works the same on Java 17 and Java 25.",[69,6407,462],{"id":461},[19,6409,6410,6418,6432,6448,6461],{},[22,6411,6412,6417],{},[25,6413,4719,6414,6416],{},[95,6415,5806],{}," in the colon form."," Execution falls through and runs the next case's statements too. The arrow form can't fall through, which is a good reason to prefer it.",[22,6419,6420,476,6423,6426,6427,176,6429,6431],{},[25,6421,6422],{},"Writing a condition as a case label.",[95,6424,6425],{},"case autoMode > 2:"," won't compile — labels are fixed values. Use an ",[95,6428,2179],{},[95,6430,5104],{}," chain for ranges.",[22,6433,6434,6447],{},[25,6435,6436,6437,6439,6440,6442,6443,260,6445,79],{},"Leaving out ",[95,6438,5816],{}," in a ",[95,6441,5700],{}," expression on an ",[95,6444,603],{},[95,6446,361],{}," It won't compile, because some values would have no result.",[22,6449,6450,476,6455,6291,6458,6460],{},[25,6451,6452,6453,4186],{},"Forgetting the semicolon after a ",[95,6454,5700],{},[95,6456,6457],{},"String plan = switch (autoMode) { ... }",[95,6459,238],{}," after the closing brace, like any other assignment.",[22,6462,6463,6471,6472,6474,6475,6477,6478,79],{},[25,6464,6465,6466,6468,6469,79],{},"Switching on a ",[95,6467,361],{}," that might be ",[95,6470,4645],{}," The ",[95,6473,5700],{}," throws a ",[95,6476,4678],{}," before checking any case, even ",[95,6479,5816],{},[69,6481,501],{"id":500},[19,6483,6484,6496,6505,6516,6528,6535],{},[22,6485,405,6486,6488,6489,322,6491,322,6493,6495],{},[95,6487,5700],{}," matches one value against fixed case labels; it works on ",[95,6490,603],{},[95,6492,686],{},[95,6494,361],{}," and enum values.",[22,6497,6498,6499,6501,6502,6504],{},"In the colon form, each case needs a ",[95,6500,5806],{},"; without one, execution falls through into the next case. ",[95,6503,5816],{}," catches every value no label matched.",[22,6506,6507,6508,6511,6512,6515],{},"The arrow form (",[95,6509,6510],{},"case 1 ->",") never falls through, and ",[95,6513,6514],{},"case 1, 2"," lists several labels for one action.",[22,6517,405,6518,6520,6521,537,6523,6525,6526,79],{},[95,6519,5700],{}," expression produces a value and must cover every possible input, so ",[95,6522,603],{},[95,6524,361],{}," switch expressions need a ",[95,6527,5816],{},[22,6529,6530,6532,6533,4186],{},[95,6531,6306],{}," hands back the value from a multi-line block inside a ",[95,6534,5700],{},[22,6536,6537,6538,6541],{},"On Java 21+ an enum case label may be qualified (",[95,6539,6540],{},"case ArmPosition.INTAKE","); Java 17 accepts only the bare constant name.",[15,6543,6544,6545,79],{},"Derived from: nothing upstream — written for this course (content-audit decision D4); AP CSA doesn't cover ",[95,6546,5700],{},[554,6548,556],{},{"title":48,"searchDepth":49,"depth":49,"links":6550},[6551,6552,6553,6554,6555,6556,6557,6558,6559,6560],{"id":5704,"depth":49,"text":5705},{"id":5862,"depth":49,"text":5863},{"id":5954,"depth":49,"text":5955},{"id":6032,"depth":49,"text":6033},{"id":6116,"depth":49,"text":6117},{"id":6199,"depth":49,"text":6200},{"id":6296,"depth":49,"text":6297},{"id":6385,"depth":49,"text":6386},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},"When one value decides between many fixed choices, an else if chain (Lesson 5.5) ends up comparing the same variable over and over. A switch says it directly: look at one value, then jump to the case that matches it.",{"outlineRef":6563,"status":6564},"5.12 — switch Statements and Expressions (not in AP CSA; added by the 2026-09-25 content audit)","new — authored lesson (no teaser slide; the canonical switch reference that Ch.11, 13, 21 and 25 point back to)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F12-switch-statements-and-expressions",{"title":5685,"description":6561},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.12-switch-statements-and-expressions","hJIO0PeQE4pcfB-d3MWfkq5_tWAbjNZriYjKx4G9_bs",{"id":6570,"title":6571,"body":6572,"description":48,"extension":51,"meta":6677,"navigation":55,"path":6679,"seo":6680,"stem":6681,"__hash__":6682},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.3-algorithms-with-selection-and-repetition.md","Algorithms with Selection and Repetition",{"type":8,"value":6573,"toc":6671},[6574,6577,6581,6584,6608,6611,6615,6621,6624,6632,6635,6637,6653,6655,6663],[11,6575,6571],{"id":6576},"algorithms-with-selection-and-repetition",[69,6578,6580],{"id":6579},"the-three-building-blocks","The Three Building Blocks",[15,6582,6583],{},"Every algorithm, no matter how complex, is built from just three ingredients:",[19,6585,6586,6592,6602],{},[22,6587,6588,6591],{},[25,6589,6590],{},"Sequence"," — steps run in order, one after another.",[22,6593,6594,6597,6598,176,6600,4410],{},[25,6595,6596],{},"Selection"," — branch based on a true\u002Ffalse decision (",[95,6599,2179],{},[95,6601,5104],{},[22,6603,6604,6607],{},[25,6605,6606],{},"Repetition"," — repeat a block until some condition is met (loops).",[15,6609,6610],{},"That's genuinely it. Every autonomous routine, every teleop control loop, every piece of robot code you'll ever write is some combination of these three.",[69,6612,6614],{"id":6613},"planning-before-coding","Planning Before Coding",[15,6616,6617,6618,6620],{},"For anything beyond a couple of lines, it helps to plan the steps before writing real Java — in plain English, a diagram, or ",[25,6619,85],{}," (informal step-by-step notes that aren't real code, but capture the sequence\u002Fselection\u002Frepetition structure). This is the same idea from Lesson 1.2, applied to a bigger problem.",[15,6622,6623],{},"Pseudocode for a simple autonomous routine:",[104,6625,6630],{"className":6626,"code":6628,"language":6629},[6627],"language-text","Drive forward until the distance sensor reads \u003C 12 inches\nIf a game piece is detected, run the intake\nOtherwise, back up and try a different path\n","text",[95,6631,6628],{"__ignoreMap":48},[15,6633,6634],{},"Only after the steps are clear does it make sense to translate each line into real Java.",[69,6636,462],{"id":461},[19,6638,6639,6645],{},[22,6640,6641,6644],{},[25,6642,6643],{},"Skipping the planning step for a multi-branch routine."," Jumping straight to code for anything with several conditions or a loop is exactly how logic errors sneak in — a wrong branch order, a missed case.",[22,6646,6647,6652],{},[25,6648,6649,6650,79],{},"Assuming \"selection\" only means ",[95,6651,2179],{}," Any true\u002Ffalse branching decision counts, including the conditions inside loops.",[69,6654,501],{"id":500},[19,6656,6657,6660],{},[22,6658,6659],{},"Every algorithm is built from sequence, selection, and repetition — nothing else is needed.",[22,6661,6662],{},"Pseudocode (informal step-by-step notes) is a real planning tool, not busywork — use it before writing real code for anything with multiple branches or a loop.",[15,6664,544,6665,548,6667,6670],{},[95,6666,547],{},[95,6668,6669],{},"unit-2-selection-and-iteration\u002F2.01-algorithms-with-selection-and-repetition.md"," (CSA 2.1)",{"title":48,"searchDepth":49,"depth":49,"links":6672},[6673,6674,6675,6676],{"id":6579,"depth":49,"text":6580},{"id":6613,"depth":49,"text":6614},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":6678,"status":570},"5.3 — Algorithms with Selection and Repetition (CSA 2.1)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F3-algorithms-with-selection-and-repetition",{"title":6571,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.3-algorithms-with-selection-and-repetition","ZRKhIKmx9n0OiUhkcqPJEmxdXPZziYVg3zrXjFo_bzs",{"id":6684,"title":6685,"body":6686,"description":48,"extension":51,"meta":6910,"navigation":55,"path":6912,"seo":6913,"stem":6914,"__hash__":6915},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.4-boolean-expressions.md","Boolean Expressions",{"type":8,"value":6687,"toc":6903},[6688,6691,6695,6702,6737,6757,6761,6798,6802,6807,6827,6829,6858,6860,6893,6901],[11,6689,6685],{"id":6690},"boolean-expressions",[69,6692,6694],{"id":6693},"relational-operators","Relational Operators",[15,6696,6697,6698,260,6700,738],{},"Six operators compare values and always produce ",[95,6699,661],{},[95,6701,664],{},[104,6703,6705],{"className":106,"code":6704,"language":108,"meta":48,"style":48},"==   \u002F\u002F equals\n!=   \u002F\u002F does not equal\n\u003C    \u002F\u002F less than\n>    \u002F\u002F greater than\n\u003C=   \u002F\u002F less than or equal to\n>=   \u002F\u002F greater than or equal to\n",[95,6706,6707,6712,6717,6722,6727,6732],{"__ignoreMap":48},[112,6708,6709],{"class":114,"line":115},[112,6710,6711],{},"==   \u002F\u002F equals\n",[112,6713,6714],{"class":114,"line":49},[112,6715,6716],{},"!=   \u002F\u002F does not equal\n",[112,6718,6719],{"class":114,"line":126},[112,6720,6721],{},"\u003C    \u002F\u002F less than\n",[112,6723,6724],{"class":114,"line":132},[112,6725,6726],{},">    \u002F\u002F greater than\n",[112,6728,6729],{"class":114,"line":138},[112,6730,6731],{},"\u003C=   \u002F\u002F less than or equal to\n",[112,6733,6734],{"class":114,"line":144},[112,6735,6736],{},">=   \u002F\u002F greater than or equal to\n",[104,6738,6740],{"className":106,"code":6739,"language":108,"meta":48,"style":48},"double battery = 11.8;\nSystem.out.println(battery \u003C 12.0);  \u002F\u002F true — low battery\nSystem.out.println(battery >= 12.0); \u002F\u002F false\n",[95,6741,6742,6747,6752],{"__ignoreMap":48},[112,6743,6744],{"class":114,"line":115},[112,6745,6746],{},"double battery = 11.8;\n",[112,6748,6749],{"class":114,"line":49},[112,6750,6751],{},"System.out.println(battery \u003C 12.0);  \u002F\u002F true — low battery\n",[112,6753,6754],{"class":114,"line":126},[112,6755,6756],{},"System.out.println(battery >= 12.0); \u002F\u002F false\n",[69,6758,6760],{"id":6759},"equality-primitives-vs-objects","Equality: Primitives vs. Objects",[15,6762,6763,6765,6766,322,6768,322,6770,6772,6773,6775,6776,1291,6779,6781,6782,6784,6785,6788,6789,6791,6792,6794,6795,6797],{},[95,6764,1921],{}," on primitives (",[95,6767,603],{},[95,6769,631],{},[95,6771,657],{},") compares the actual values — exactly what you'd expect, with one caveat for ",[95,6774,631],{},": a computed result can carry a tiny rounding error, so ",[95,6777,6778],{},"0.1 + 0.2 == 0.3",[95,6780,664],{},". Compare computed doubles within a small tolerance instead (Lesson 2.4; Ch.13 revisits it). ",[95,6783,1921],{}," on objects compares whether two variables refer to the ",[494,6786,6787],{},"same object in memory",", not whether their contents look the same. Two separately-built ",[95,6790,4333],{}," objects (our own motor class) with identical settings are still two different objects — ",[95,6793,1921],{}," between them is ",[95,6796,664],{},". (Object equality gets its own full treatment in Ch.6, once Strings are introduced.)",[69,6799,6801],{"id":6800},"divisibility-with-the-remainder-operator","Divisibility with the Remainder Operator",[15,6803,6804,6806],{},[95,6805,1281],{}," (from Ch.2) is how you test whether a number divides evenly into another:",[104,6808,6810],{"className":106,"code":6809,"language":108,"meta":48,"style":48},"(number % 2 == 0)  \u002F\u002F true if number is even\n(number % 2 != 0)  \u002F\u002F true if number is odd\n(number % x == 0)  \u002F\u002F true if number is evenly divisible by x\n",[95,6811,6812,6817,6822],{"__ignoreMap":48},[112,6813,6814],{"class":114,"line":115},[112,6815,6816],{},"(number % 2 == 0)  \u002F\u002F true if number is even\n",[112,6818,6819],{"class":114,"line":49},[112,6820,6821],{},"(number % 2 != 0)  \u002F\u002F true if number is odd\n",[112,6823,6824],{"class":114,"line":126},[112,6825,6826],{},"(number % x == 0)  \u002F\u002F true if number is evenly divisible by x\n",[69,6828,462],{"id":461},[19,6830,6831,6840],{},[22,6832,6833,6839],{},[25,6834,6835,6836,6838],{},"Using ",[95,6837,1921],{}," on objects expecting a content comparison."," It checks \"same object,\" not \"same values\" — two different but identical-looking objects compare unequal.",[22,6841,6842,6848,6849,959,6851,6853,6854,6857],{},[25,6843,6844,6845,79],{},"Testing oddness with ",[95,6846,6847],{},"num % 2 == 1"," This looks right but fails for negative odd numbers (their remainder is ",[95,6850,1343],{},[95,6852,1294],{},"). Use ",[95,6855,6856],{},"num % 2 != 0"," instead — it works for both signs.",[69,6859,501],{"id":500},[19,6861,6862,6869,6877],{},[22,6863,6864,6865,6868],{},"Relational operators (",[95,6866,6867],{},"== != \u003C > \u003C= >=",") always produce a boolean result.",[22,6870,6871,6873,6874,6876],{},[95,6872,1921],{}," on primitives compares values; ",[95,6875,1921],{}," on objects compares identity (same object), not content.",[22,6878,6879,6881,6882,6885,6886,6888,6889,6892],{},[95,6880,1281],{}," tests divisibility — ",[95,6883,6884],{},"num % 2 == 0"," for even, ",[95,6887,6856],{}," for odd (not ",[95,6890,6891],{},"== 1",", which breaks on negatives).",[15,6894,544,6895,548,6897,6900],{},[95,6896,547],{},[95,6898,6899],{},"unit-2-selection-and-iteration\u002F2.02-boolean-expressions.md"," (CSA 2.2)",[554,6902,556],{},{"title":48,"searchDepth":49,"depth":49,"links":6904},[6905,6906,6907,6908,6909],{"id":6693,"depth":49,"text":6694},{"id":6759,"depth":49,"text":6760},{"id":6800,"depth":49,"text":6801},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":6911,"status":570},"5.4 — Boolean Expressions (CSA 2.2)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F4-boolean-expressions",{"title":6685,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.4-boolean-expressions","2z6qVy8pzYpEgzQR8CNwIo3WsoNenXmEz2pIOk4Hsi4",{"id":6917,"title":6918,"body":6919,"description":48,"extension":51,"meta":7437,"navigation":55,"path":7439,"seo":7440,"stem":7441,"__hash__":7442},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.5-nested-if-statements.md","Nested if Statements",{"type":8,"value":6920,"toc":7428},[6921,6924,6928,6934,6992,6998,7002,7014,7057,7061,7074,7104,7110,7160,7164,7175,7221,7233,7237,7256,7301,7304,7313,7329,7331,7384,7386,7418,7426],[11,6922,6918],{"id":6923},"nested-if-statements",[69,6925,6927],{"id":6926},"multiway-selection-with-else-if","Multiway Selection with else if",[15,6929,6930,6931,6933],{},"Chain ",[95,6932,5696],{}," to pick between three or more paths — only the first true branch runs:",[104,6935,6937],{"className":106,"code":6936,"language":108,"meta":48,"style":48},"if (distance \u003C 1.0)\n{\n    zone = \"CLOSE\";\n}\nelse if (distance \u003C 3.0)\n{\n    zone = \"MID\";\n}\nelse\n{\n    zone = \"FAR\";\n}\n",[95,6938,6939,6944,6948,6953,6957,6962,6966,6971,6975,6979,6983,6988],{"__ignoreMap":48},[112,6940,6941],{"class":114,"line":115},[112,6942,6943],{},"if (distance \u003C 1.0)\n",[112,6945,6946],{"class":114,"line":49},[112,6947,123],{},[112,6949,6950],{"class":114,"line":126},[112,6951,6952],{},"    zone = \"CLOSE\";\n",[112,6954,6955],{"class":114,"line":132},[112,6956,153],{},[112,6958,6959],{"class":114,"line":138},[112,6960,6961],{},"else if (distance \u003C 3.0)\n",[112,6963,6964],{"class":114,"line":144},[112,6965,123],{},[112,6967,6968],{"class":114,"line":150},[112,6969,6970],{},"    zone = \"MID\";\n",[112,6972,6973],{"class":114,"line":2276},[112,6974,153],{},[112,6976,6977],{"class":114,"line":2282},[112,6978,5131],{},[112,6980,6981],{"class":114,"line":2288},[112,6982,123],{},[112,6984,6985],{"class":114,"line":5760},[112,6986,6987],{},"    zone = \"FAR\";\n",[112,6989,6990],{"class":114,"line":5766},[112,6991,153],{},[15,6993,6994,6995,6997],{},"A trailing plain ",[95,6996,5104],{}," (no condition) catches everything not already matched — it's optional, but leaving it off means \"do nothing\" is a real possible outcome.",[69,6999,7001],{"id":7000},"chained-vs-separate-ifs","Chained vs. Separate ifs",[15,7003,7004,7006,7007,7009,7010,7013],{},[95,7005,5696],{}," connects the branches together — only one of them ever runs. Writing separate, unconnected ",[95,7008,2179],{}," statements instead is a different (and often wrong) thing entirely, because ",[494,7011,7012],{},"all"," of them get checked independently:",[104,7015,7017],{"className":106,"code":7016,"language":108,"meta":48,"style":48},"\u002F\u002F Connected — only one branch runs\nif (score >= 90) { grade = \"A\"; }\nelse if (score >= 80) { grade = \"B\"; }\nelse { grade = \"C\"; }\n\n\u002F\u002F NOT connected — multiple could run, overwriting each other\nif (score >= 90) { grade = \"A\"; }\nif (score >= 80) { grade = \"B\"; } \u002F\u002F a 95 would hit this too, overwriting \"A\" with \"B\"!\n",[95,7018,7019,7024,7029,7034,7039,7043,7048,7052],{"__ignoreMap":48},[112,7020,7021],{"class":114,"line":115},[112,7022,7023],{},"\u002F\u002F Connected — only one branch runs\n",[112,7025,7026],{"class":114,"line":49},[112,7027,7028],{},"if (score >= 90) { grade = \"A\"; }\n",[112,7030,7031],{"class":114,"line":126},[112,7032,7033],{},"else if (score >= 80) { grade = \"B\"; }\n",[112,7035,7036],{"class":114,"line":132},[112,7037,7038],{},"else { grade = \"C\"; }\n",[112,7040,7041],{"class":114,"line":138},[112,7042,907],{"emptyLinePlaceholder":55},[112,7044,7045],{"class":114,"line":144},[112,7046,7047],{},"\u002F\u002F NOT connected — multiple could run, overwriting each other\n",[112,7049,7050],{"class":114,"line":150},[112,7051,7028],{},[112,7053,7054],{"class":114,"line":2276},[112,7055,7056],{},"if (score >= 80) { grade = \"B\"; } \u002F\u002F a 95 would hit this too, overwriting \"A\" with \"B\"!\n",[69,7058,7060],{"id":7059},"the-dangling-else","The Dangling Else",[15,7062,7063,7064,7066,7067,7070,7071,7073],{},"When ifs are nested without braces, an ",[95,7065,5104],{}," always attaches to the ",[494,7068,7069],{},"closest"," unmatched ",[95,7072,2179],{}," — regardless of indentation:",[104,7075,7077],{"className":106,"code":7076,"language":108,"meta":48,"style":48},"if (sunny)\n    if (hot)\n        goToBeach();\nelse \u002F\u002F looks like it belongs to sunny, but it belongs to hot\n    bringUmbrella();\n",[95,7078,7079,7084,7089,7094,7099],{"__ignoreMap":48},[112,7080,7081],{"class":114,"line":115},[112,7082,7083],{},"if (sunny)\n",[112,7085,7086],{"class":114,"line":49},[112,7087,7088],{},"    if (hot)\n",[112,7090,7091],{"class":114,"line":126},[112,7092,7093],{},"        goToBeach();\n",[112,7095,7096],{"class":114,"line":132},[112,7097,7098],{},"else \u002F\u002F looks like it belongs to sunny, but it belongs to hot\n",[112,7100,7101],{"class":114,"line":138},[112,7102,7103],{},"    bringUmbrella();\n",[15,7105,7106,7107,7109],{},"This brings an umbrella when it's sunny but ",[494,7108,3360],{}," hot — and does nothing at all when it isn't sunny. If that's not what you meant, braces fix it:",[104,7111,7113],{"className":106,"code":7112,"language":108,"meta":48,"style":48},"if (sunny)\n{\n    if (hot)\n    {\n        goToBeach();\n    }\n}\nelse \u002F\u002F now belongs to the OUTER if, thanks to the braces\n{\n    bringUmbrella();\n}\n",[95,7114,7115,7119,7123,7127,7131,7135,7139,7143,7148,7152,7156],{"__ignoreMap":48},[112,7116,7117],{"class":114,"line":115},[112,7118,7083],{},[112,7120,7121],{"class":114,"line":49},[112,7122,123],{},[112,7124,7125],{"class":114,"line":126},[112,7126,7088],{},[112,7128,7129],{"class":114,"line":132},[112,7130,135],{},[112,7132,7133],{"class":114,"line":138},[112,7134,7093],{},[112,7136,7137],{"class":114,"line":144},[112,7138,147],{},[112,7140,7141],{"class":114,"line":150},[112,7142,153],{},[112,7144,7145],{"class":114,"line":2276},[112,7146,7147],{},"else \u002F\u002F now belongs to the OUTER if, thanks to the braces\n",[112,7149,7150],{"class":114,"line":2282},[112,7151,123],{},[112,7153,7154],{"class":114,"line":2288},[112,7155,7103],{},[112,7157,7158],{"class":114,"line":5760},[112,7159,153],{},[69,7161,7163],{"id":7162},"a-missing-else-can-leave-a-variable-unassigned","A Missing else Can Leave a Variable Unassigned",[15,7165,7166,7167,7170,7171,7174],{},"Java requires a local variable (one declared inside a method, like ",[95,7168,7169],{},"tier"," below) to be ",[494,7172,7173],{},"definitely assigned"," before it's read. If no branch is guaranteed to run, the compiler won't let you read it afterward:",[104,7176,7178],{"className":106,"code":7177,"language":108,"meta":48,"style":48},"String tier; \u002F\u002F local variable, no initial value\n\nif (score >= 8)\n{\n    tier = \"ELITE\";\n}\n\u002F\u002F no else — if score \u003C 8, tier is never assigned\n\nSystem.out.println(tier); \u002F\u002F won't compile: tier might not be assigned\n",[95,7179,7180,7185,7189,7194,7198,7203,7207,7212,7216],{"__ignoreMap":48},[112,7181,7182],{"class":114,"line":115},[112,7183,7184],{},"String tier; \u002F\u002F local variable, no initial value\n",[112,7186,7187],{"class":114,"line":49},[112,7188,907],{"emptyLinePlaceholder":55},[112,7190,7191],{"class":114,"line":126},[112,7192,7193],{},"if (score >= 8)\n",[112,7195,7196],{"class":114,"line":132},[112,7197,123],{},[112,7199,7200],{"class":114,"line":138},[112,7201,7202],{},"    tier = \"ELITE\";\n",[112,7204,7205],{"class":114,"line":144},[112,7206,153],{},[112,7208,7209],{"class":114,"line":150},[112,7210,7211],{},"\u002F\u002F no else — if score \u003C 8, tier is never assigned\n",[112,7213,7214],{"class":114,"line":2276},[112,7215,907],{"emptyLinePlaceholder":55},[112,7217,7218],{"class":114,"line":2282},[112,7219,7220],{},"System.out.println(tier); \u002F\u002F won't compile: tier might not be assigned\n",[15,7222,7223,7224,7226,7227,7229,7230,7232],{},"Adding a trailing ",[95,7225,5104],{}," that assigns ",[95,7228,7169],{}," (or giving ",[95,7231,7169],{}," a starting value) fixes it.",[69,7234,7236],{"id":7235},"choosing-between-two-values-with","Choosing Between Two Values with ?:",[15,7238,7239,7240,176,7242,7244,7245,7247,7248,7251,7252,176,7254,738],{},"When an ",[95,7241,2179],{},[95,7243,5104],{}," exists only to pick one of two values for the same variable, the conditional operator ",[95,7246,6212],{}," (often called the ",[494,7249,7250],{},"ternary"," operator, because it has three parts) does it in a single expression. This ",[95,7253,2179],{},[95,7255,5104],{},[104,7257,7259],{"className":106,"code":7258,"language":108,"meta":48,"style":48},"double speed;\nif (boosted)\n{\n    speed = 1.0;\n}\nelse\n{\n    speed = 0.5;\n}\n",[95,7260,7261,7266,7271,7275,7280,7284,7288,7292,7297],{"__ignoreMap":48},[112,7262,7263],{"class":114,"line":115},[112,7264,7265],{},"double speed;\n",[112,7267,7268],{"class":114,"line":49},[112,7269,7270],{},"if (boosted)\n",[112,7272,7273],{"class":114,"line":126},[112,7274,123],{},[112,7276,7277],{"class":114,"line":132},[112,7278,7279],{},"    speed = 1.0;\n",[112,7281,7282],{"class":114,"line":138},[112,7283,153],{},[112,7285,7286],{"class":114,"line":144},[112,7287,5131],{},[112,7289,7290],{"class":114,"line":150},[112,7291,123],{},[112,7293,7294],{"class":114,"line":2276},[112,7295,7296],{},"    speed = 0.5;\n",[112,7298,7299],{"class":114,"line":2282},[112,7300,153],{},[15,7302,7303],{},"does the same thing as this one line:",[104,7305,7307],{"className":106,"code":7306,"language":108,"meta":48,"style":48},"double speed = boosted ? 1.0 : 0.5;\n",[95,7308,7309],{"__ignoreMap":48},[112,7310,7311],{"class":114,"line":115},[112,7312,7306],{},[15,7314,7315,7316,7319,7320,176,7322,7324,7325,7328],{},"Read it as ",[95,7317,7318],{},"condition ? valueIfTrue : valueIfFalse",": Java checks the condition, then produces exactly one of the two values. Use it for short value choices; keep a regular ",[95,7321,2179],{},[95,7323,5104],{}," when a branch needs to ",[494,7326,7327],{},"do"," things, not just produce a value.",[69,7330,462],{"id":461},[19,7332,7333,7344,7360,7372],{},[22,7334,7335,7343],{},[25,7336,7337,7338,7340,7341,79],{},"Using separate ",[95,7339,2179],{},"s instead of ",[95,7342,5696],{}," Separate ifs are each checked independently — a later one can silently overwrite what an earlier one just set.",[22,7345,7346,7349,7350,7353,7354,7356,7357,7359],{},[25,7347,7348],{},"Relying on indentation instead of braces."," Java ignores indentation entirely; only ",[95,7351,7352],{},"{ }"," actually determines which ",[95,7355,2179],{}," an ",[95,7358,5104],{}," belongs to.",[22,7361,7362,7368,7369,7371],{},[25,7363,7364,7365,7367],{},"Skipping the trailing ",[95,7366,5104],{}," when a local variable is only assigned inside branches."," The compiler won't let you read a local variable that isn't definitely assigned on every path — add an ",[95,7370,5104],{},", or give the variable a starting value.",[22,7373,7374,476,7377,7380,7381,7383],{},[25,7375,7376],{},"Stacking ternaries.",[95,7378,7379],{},"a ? x : b ? y : z"," is legal but hard to read — for three or more choices, use an ",[95,7382,5696],{}," chain.",[69,7385,501],{"id":500},[19,7387,7388,7393,7399,7407],{},[22,7389,7390,7392],{},[95,7391,5696],{}," chains pick exactly one branch — the first condition that's true, and nothing after it.",[22,7394,7395,7396,7398],{},"Unconnected, separate ",[95,7397,2179],{}," statements are checked independently and can overwrite each other's results.",[22,7400,1851,7401,7403,7404,7406],{},[95,7402,5104],{}," always attaches to the nearest unmatched ",[95,7405,2179],{}," — braces are the only reliable way to control this.",[22,7408,7409,7412,7413,176,7415,7417],{},[95,7410,7411],{},"condition ? a : b"," picks one of two values in a single expression — a compact stand-in for an ",[95,7414,2179],{},[95,7416,5104],{}," that only assigns.",[15,7419,544,7420,548,7422,7425],{},[95,7421,547],{},[95,7423,7424],{},"unit-2-selection-and-iteration\u002F2.04-nested-if-statements.md"," (CSA 2.4)",[554,7427,556],{},{"title":48,"searchDepth":49,"depth":49,"links":7429},[7430,7431,7432,7433,7434,7435,7436],{"id":6926,"depth":49,"text":6927},{"id":7000,"depth":49,"text":7001},{"id":7059,"depth":49,"text":7060},{"id":7162,"depth":49,"text":7163},{"id":7235,"depth":49,"text":7236},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":7438,"status":570},"5.5 — Nested if Statements (CSA 2.4)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5-nested-if-statements",{"title":6918,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.5-nested-if-statements","gqggKkdOVUigyYJU9aJ637msB-3U-MaDVgtPRDQ41nc",{"id":7444,"title":7445,"body":7446,"description":48,"extension":51,"meta":7694,"navigation":55,"path":7696,"seo":7697,"stem":7698,"__hash__":7699},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.6-compound-boolean-expressions.md","Compound Boolean Expressions",{"type":8,"value":7447,"toc":7687},[7448,7451,7455,7470,7493,7504,7508,7511,7538,7541,7564,7585,7589,7600,7615,7617,7648,7650,7677,7685],[11,7449,7445],{"id":7450},"compound-boolean-expressions",[69,7452,7454],{"id":7453},"and-or-not","And, Or, Not",[15,7456,7457,7458,7461,7462,7465,7466,7469],{},"Combine conditions with ",[95,7459,7460],{},"&&"," (and), ",[95,7463,7464],{},"||"," (or), and ",[95,7467,7468],{},"!"," (not):",[104,7471,7473],{"className":106,"code":7472,"language":108,"meta":48,"style":48},"if (armReady && intakeReady)\n{\n    shooter.score();\n}\n",[95,7474,7475,7480,7484,7489],{"__ignoreMap":48},[112,7476,7477],{"class":114,"line":115},[112,7478,7479],{},"if (armReady && intakeReady)\n",[112,7481,7482],{"class":114,"line":49},[112,7483,123],{},[112,7485,7486],{"class":114,"line":126},[112,7487,7488],{},"    shooter.score();\n",[112,7490,7491],{"class":114,"line":132},[112,7492,153],{},[15,7494,7495,7497,7498,7500,7501,7503],{},[95,7496,7460],{}," needs both sides true; ",[95,7499,7464],{}," needs just one (or both). ",[95,7502,7468],{}," flips a boolean's value.",[69,7505,7507],{"id":7506},"short-circuit-evaluation","Short-Circuit Evaluation",[15,7509,7510],{},"Java stops checking as soon as the answer is already known — it never evaluates more than it needs to:",[19,7512,7513,7527],{},[22,7514,7515,7516,7519,7520,7522,7523,7526],{},"In ",[95,7517,7518],{},"a && b",": if ",[95,7521,292],{}," is false, ",[95,7524,7525],{},"b"," is never even checked — the whole thing is already false.",[22,7528,7515,7529,7519,7532,7534,7535,7537],{},[95,7530,7531],{},"a || b",[95,7533,292],{}," is true, ",[95,7536,7525],{}," is never checked — the whole thing is already true.",[15,7539,7540],{},"This isn't just an optimization — it's a real safety pattern:",[104,7542,7544],{"className":106,"code":7543,"language":108,"meta":48,"style":48},"if (sensor != null && sensor.isFaulty())\n{\n    report(sensor);\n}\n",[95,7545,7546,7551,7555,7560],{"__ignoreMap":48},[112,7547,7548],{"class":114,"line":115},[112,7549,7550],{},"if (sensor != null && sensor.isFaulty())\n",[112,7552,7553],{"class":114,"line":49},[112,7554,123],{},[112,7556,7557],{"class":114,"line":126},[112,7558,7559],{},"    report(sensor);\n",[112,7561,7562],{"class":114,"line":132},[112,7563,153],{},[15,7565,7566,7567,1291,7570,7572,7573,7575,7576,7579,7580,7582,7583,79],{},"If ",[95,7568,7569],{},"sensor",[95,7571,4645],{},", the left side is false, so ",[95,7574,7460],{}," never evaluates ",[95,7577,7578],{},"sensor.isFaulty()"," — which would otherwise throw a ",[95,7581,4678],{},". The order here matters: the null check has to come ",[494,7584,4161],{},[69,7586,7588],{"id":7587},"operator-precedence","Operator Precedence",[15,7590,7591,7593,7594,7596,7597,7599],{},[95,7592,7468],{}," binds tightest, then ",[95,7595,7460],{},", then ",[95,7598,7464],{}," — parentheses override all of it and make intent explicit:",[104,7601,7603],{"className":106,"code":7602,"language":108,"meta":48,"style":48},"if (!ready && !armed) { ... }        \u002F\u002F ! applies to each: true only if BOTH are false\nif (!(ready && armed)) { ... }       \u002F\u002F different! true if EITHER one is false\n",[95,7604,7605,7610],{"__ignoreMap":48},[112,7606,7607],{"class":114,"line":115},[112,7608,7609],{},"if (!ready && !armed) { ... }        \u002F\u002F ! applies to each: true only if BOTH are false\n",[112,7611,7612],{"class":114,"line":49},[112,7613,7614],{},"if (!(ready && armed)) { ... }       \u002F\u002F different! true if EITHER one is false\n",[69,7616,462],{"id":461},[19,7618,7619,7636],{},[22,7620,7621,476,7624,7627,7628,7630,7631,1291,7633,7635],{},[25,7622,7623],{},"Putting the null check on the wrong side.",[95,7625,7626],{},"sensor.isFaulty() && sensor != null"," checks the faulty status ",[494,7629,4161],{}," — if ",[95,7632,7569],{},[95,7634,4645],{},", it crashes before the null check ever runs. The null check must come first for short-circuiting to protect you.",[22,7637,7638,7647],{},[25,7639,1608,7640,7643,7644,79],{},[95,7641,7642],{},"!(a && b)"," is the same as ",[95,7645,7646],{},"!a && !b"," It's not — that's a real logic error (the correct equivalent, De Morgan's Law, comes in the next lesson).",[69,7649,501],{"id":500},[19,7651,7652,7663,7666],{},[22,7653,7654,7656,7657,7659,7660,7662],{},[95,7655,7460],{}," requires both sides true; ",[95,7658,7464],{}," requires at least one; ",[95,7661,7468],{}," flips a boolean.",[22,7664,7665],{},"Short-circuit evaluation skips the right side once the left side already determines the result — order a null-check first specifically to exploit this.",[22,7667,7668,7670,7671,7673,7674,7676],{},[95,7669,7468],{}," has higher precedence than ",[95,7672,7460],{},", which has higher precedence than ",[95,7675,7464],{},"; use parentheses when the default grouping isn't what you mean.",[15,7678,544,7679,548,7681,7684],{},[95,7680,547],{},[95,7682,7683],{},"unit-2-selection-and-iteration\u002F2.05-compound-boolean-expressions.md"," (CSA 2.5)",[554,7686,556],{},{"title":48,"searchDepth":49,"depth":49,"links":7688},[7689,7690,7691,7692,7693],{"id":7453,"depth":49,"text":7454},{"id":7506,"depth":49,"text":7507},{"id":7587,"depth":49,"text":7588},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":7695,"status":570},"5.6 — Compound Boolean Expressions (CSA 2.5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F6-compound-boolean-expressions",{"title":7445,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.6-compound-boolean-expressions","1VKoUKBp96Nxasqr9dtcnS7CSqCq9u4cH9VP3_O0CPw",{"id":7701,"title":7702,"body":7703,"description":48,"extension":51,"meta":7955,"navigation":55,"path":7957,"seo":7958,"stem":7959,"__hash__":7960},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.7-comparing-boolean-expressions-de-morgans-laws.md","Comparing Boolean Expressions (De Morgan's Laws)",{"type":8,"value":7704,"toc":7947},[7705,7708,7712,7715,7730,7746,7750,7753,7773,7787,7791,7800,7819,7823,7846,7855,7857,7891,7893,7937,7945],[11,7706,7702],{"id":7707},"comparing-boolean-expressions-de-morgans-laws",[69,7709,7711],{"id":7710},"de-morgans-laws","De Morgan's Laws",[15,7713,7714],{},"Negating a compound condition flips both the operator and each individual comparison:",[104,7716,7718],{"className":106,"code":7717,"language":108,"meta":48,"style":48},"!(a && b)  is equivalent to  !a || !b\n!(a || b)  is equivalent to  !a && !b\n",[95,7719,7720,7725],{"__ignoreMap":48},[112,7721,7722],{"class":114,"line":115},[112,7723,7724],{},"!(a && b)  is equivalent to  !a || !b\n",[112,7726,7727],{"class":114,"line":49},[112,7728,7729],{},"!(a || b)  is equivalent to  !a && !b\n",[15,7731,7732,7733,7735,7736,4029,7738,7740,7741,4029,7743,7745],{},"A simple way to remember it: push the ",[95,7734,7468],{}," inward, and flip ",[95,7737,7460],{},[95,7739,7464],{}," (or ",[95,7742,7464],{},[95,7744,7460],{},") as it moves in.",[69,7747,7749],{"id":7748},"flipping-relational-operators-under-negation","Flipping Relational Operators Under Negation",[15,7751,7752],{},"The same idea applies to relational operators — negating a comparison flips its sign:",[104,7754,7756],{"className":106,"code":7755,"language":108,"meta":48,"style":48},"!(c == d)  is  c != d\n!(c \u003C d)   is  c >= d\n!(c > d)   is  c \u003C= d\n",[95,7757,7758,7763,7768],{"__ignoreMap":48},[112,7759,7760],{"class":114,"line":115},[112,7761,7762],{},"!(c == d)  is  c != d\n",[112,7764,7765],{"class":114,"line":49},[112,7766,7767],{},"!(c \u003C d)   is  c >= d\n",[112,7769,7770],{"class":114,"line":126},[112,7771,7772],{},"!(c > d)   is  c \u003C= d\n",[15,7774,7775,7776,7779,7780,7783,7784,79],{},"Putting both rules together: ",[95,7777,7778],{},"!(x \u003C 3 && y > 2)"," becomes ",[95,7781,7782],{},"!(x \u003C 3) || !(y > 2)",", which simplifies further to ",[95,7785,7786],{},"(x >= 3 || y \u003C= 2)",[69,7788,7790],{"id":7789},"why-bother-simplifying","Why Bother Simplifying",[15,7792,7793,537,7796,7799],{},[95,7794,7795],{},"!(ready && armed)",[95,7797,7798],{},"!ready || !armed"," always evaluate to the same result — but the second one reads more directly as \"either one isn't ready\" instead of \"it's not true that both are ready.\" Simplifying a negated condition often makes the code's actual intent clearer.",[104,7801,7803],{"className":106,"code":7802,"language":108,"meta":48,"style":48},"if (!ready || !armed) {\n    abort();\n}\n",[95,7804,7805,7810,7815],{"__ignoreMap":48},[112,7806,7807],{"class":114,"line":115},[112,7808,7809],{},"if (!ready || !armed) {\n",[112,7811,7812],{"class":114,"line":49},[112,7813,7814],{},"    abort();\n",[112,7816,7817],{"class":114,"line":126},[112,7818,153],{},[69,7820,7822],{"id":7821},"a-preview-comparing-objects","A Preview: Comparing Objects",[15,7824,7825,7827,7828,7830,7831,7833,7834,7837,7838,176,7840,7843,7844,79],{},[95,7826,1921],{}," on objects (a preview from Lesson 5.4) compares whether two variables point at the ",[494,7829,3485],{}," object, not whether their contents match. This matters for ",[95,7832,361],{},"s specifically, which get their own full treatment in Ch.6 — for now, the short version: use ",[95,7835,7836],{},".equals()"," to compare what two objects actually contain, and reserve ",[95,7839,1921],{},[95,7841,7842],{},"!="," for checking against ",[95,7845,4645],{},[104,7847,7849],{"className":106,"code":7848,"language":108,"meta":48,"style":48},"if (sensor != null && sensor.isFaulty()) { ... } \u002F\u002F == used correctly, against null\n",[95,7850,7851],{"__ignoreMap":48},[112,7852,7853],{"class":114,"line":115},[112,7854,7848],{},[69,7856,462],{"id":461},[19,7858,7859,7880],{},[22,7860,7861,476,7866,1291,7869,959,7872,7875,7876,7879],{},[25,7862,7863,7864,79],{},"Forgetting to flip the operator, not just add a ",[95,7865,7468],{},[95,7867,7868],{},"!(x \u003C 3)",[95,7870,7871],{},"x >= 3",[95,7873,7874],{},"x !\u003C 3"," (which isn't valid Java) and not ",[95,7877,7878],{},"x > 3"," (which misses the equal case).",[22,7881,7882,7885,7886,176,7888,7890],{},[25,7883,7884],{},"Applying De Morgan's Law only to one side."," Both the operator (",[95,7887,7460],{},[95,7889,7464],{},") and both individual comparisons flip — doing only one produces a wrong, non-equivalent expression.",[69,7892,501],{"id":500},[19,7894,7895,7909,7926,7929],{},[22,7896,7897,7899,7900,7903,7904,7899,7907,79],{},[95,7898,7642],{}," is equivalent to ",[95,7901,7902],{},"!a || !b","; ",[95,7905,7906],{},"!(a || b)",[95,7908,7646],{},[22,7910,7911,7912,7779,7914,322,7917,7779,7920,322,7922,7779,7924,79],{},"Negating a relational operator flips its sign: ",[95,7913,5257],{},[95,7915,7916],{},">=",[95,7918,7919],{},">",[95,7921,5263],{},[95,7923,1921],{},[95,7925,7842],{},[22,7927,7928],{},"Simplifying a negated condition often makes its intent easier to read, even though it's logically equivalent either way.",[22,7930,7931,7933,7934,7936],{},[95,7932,1921],{}," on objects checks identity, not content — ",[95,7935,7836],{}," (covered fully in Ch.6) is for comparing what's actually inside.",[15,7938,544,7939,548,7941,7944],{},[95,7940,547],{},[95,7942,7943],{},"unit-2-selection-and-iteration\u002F2.06-comparing-boolean-expressions-de-morgan-s-laws.md"," (CSA 2.6)",[554,7946,556],{},{"title":48,"searchDepth":49,"depth":49,"links":7948},[7949,7950,7951,7952,7953,7954],{"id":7710,"depth":49,"text":7711},{"id":7748,"depth":49,"text":7749},{"id":7789,"depth":49,"text":7790},{"id":7821,"depth":49,"text":7822},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":7956,"status":570},"5.7 — Comparing Boolean Expressions (De Morgan's Laws) (CSA 2.6)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F7-comparing-boolean-expressions-de-morgans-laws",{"title":7702,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.7-comparing-boolean-expressions-de-morgans-laws","fBNcnhY7d7t2NbhxpMZQxwI2P25wAFnOQMVdZdbcESk",{"id":7962,"title":7963,"body":7964,"description":48,"extension":51,"meta":8394,"navigation":55,"path":8396,"seo":8397,"stem":8398,"__hash__":8399},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.8-while-loops.md","While Loops",{"type":8,"value":7965,"toc":8384},[7966,7969,7973,7982,8015,8024,8028,8031,8059,8062,8071,8083,8116,8123,8127,8137,8168,8181,8185,8195,8254,8276,8278,8332,8334,8374,8382],[11,7967,7963],{"id":7968},"while-loops",[69,7970,7972],{"id":7971},"the-three-steps-of-a-loop","The Three Steps of a Loop",[15,7974,405,7975,7978,7979,7981],{},[95,7976,7977],{},"while"," loop repeats its body as long as a condition holds, checked ",[494,7980,1814],{}," every pass, including the first:",[104,7983,7985],{"className":106,"code":7984,"language":108,"meta":48,"style":48},"int attempts = 0;             \u002F\u002F 1. initialize\nwhile (attempts \u003C 3 && !connected) \u002F\u002F 2. test\n{\n    connected = tryConnect();\n    attempts++;                \u002F\u002F 3. update\n}\n",[95,7986,7987,7992,7997,8001,8006,8011],{"__ignoreMap":48},[112,7988,7989],{"class":114,"line":115},[112,7990,7991],{},"int attempts = 0;             \u002F\u002F 1. initialize\n",[112,7993,7994],{"class":114,"line":49},[112,7995,7996],{},"while (attempts \u003C 3 && !connected) \u002F\u002F 2. test\n",[112,7998,7999],{"class":114,"line":126},[112,8000,123],{},[112,8002,8003],{"class":114,"line":132},[112,8004,8005],{},"    connected = tryConnect();\n",[112,8007,8008],{"class":114,"line":138},[112,8009,8010],{},"    attempts++;                \u002F\u002F 3. update\n",[112,8012,8013],{"class":114,"line":144},[112,8014,153],{},[15,8016,8017,8018,8020,8021,8023],{},"Every loop needs these same three steps — initialize the loop variable, test it, update it inside the loop. A ",[95,8019,5188],{}," loop (Lesson 5.1-5.2) just packs all three into one header line; a ",[95,8022,7977],{}," loop spreads them out, which is more natural when the \"update\" isn't a simple counter.",[69,8025,8027],{"id":8026},"infinite-loops","Infinite Loops",[15,8029,8030],{},"Forget step 3 and the condition never changes — the loop runs forever:",[104,8032,8034],{"className":106,"code":8033,"language":108,"meta":48,"style":48},"int i = 0;\nwhile (i \u003C 10)\n{\n    System.out.println(i); \u002F\u002F i never changes — this never stops\n}\n",[95,8035,8036,8041,8046,8050,8055],{"__ignoreMap":48},[112,8037,8038],{"class":114,"line":115},[112,8039,8040],{},"int i = 0;\n",[112,8042,8043],{"class":114,"line":49},[112,8044,8045],{},"while (i \u003C 10)\n",[112,8047,8048],{"class":114,"line":126},[112,8049,123],{},[112,8051,8052],{"class":114,"line":132},[112,8053,8054],{},"    System.out.println(i); \u002F\u002F i never changes — this never stops\n",[112,8056,8057],{"class":114,"line":138},[112,8058,153],{},[15,8060,8061],{},"An infinite loop on a robot doesn't just print forever — it can freeze the whole robot's control loop, since nothing after it ever gets a chance to run.",[69,8063,8065,8066,8068,8069],{"id":8064},"when-to-reach-for-while-instead-of-for","When to Reach for ",[95,8067,7977],{}," Instead of ",[95,8070,5188],{},[15,8072,8073,8075,8076,8078,8079,8082],{},[95,8074,5188],{}," fits naturally when you already know the number of iterations. ",[95,8077,7977],{}," fits better when you're repeating until a ",[494,8080,8081],{},"condition"," changes, not counting to a number — like retrying a connection a limited number of times:",[104,8084,8086],{"className":106,"code":8085,"language":108,"meta":48,"style":48},"int attempts = 0;\nwhile (!gyro.isConnected() && attempts \u003C 5)\n{\n    gyro.reconnect(); \u002F\u002F assume our gyro class has this retry method\n    attempts++;\n}\n",[95,8087,8088,8093,8098,8102,8107,8112],{"__ignoreMap":48},[112,8089,8090],{"class":114,"line":115},[112,8091,8092],{},"int attempts = 0;\n",[112,8094,8095],{"class":114,"line":49},[112,8096,8097],{},"while (!gyro.isConnected() && attempts \u003C 5)\n",[112,8099,8100],{"class":114,"line":126},[112,8101,123],{},[112,8103,8104],{"class":114,"line":132},[112,8105,8106],{},"    gyro.reconnect(); \u002F\u002F assume our gyro class has this retry method\n",[112,8108,8109],{"class":114,"line":138},[112,8110,8111],{},"    attempts++;\n",[112,8113,8114],{"class":114,"line":144},[112,8115,153],{},[15,8117,8118,8119,8122],{},"This tries at most 5 times, then moves on whether or not the gyro came back. What it must never do is ",[494,8120,8121],{},"wait",": robot code runs in short, repeating cycles many times per second, and a loop that sits spinning until a sensor finally responds holds up everything else — the freeze described above. In robot code, check a condition once per cycle instead of looping until it changes.",[69,8124,8126],{"id":8125},"do-while-run-the-body-at-least-once","do-while: Run the Body at Least Once",[15,8128,405,8129,8132,8133,8136],{},[95,8130,8131],{},"do-while"," loop checks its condition ",[494,8134,8135],{},"after"," each pass instead of before, so the body always runs at least once:",[104,8138,8140],{"className":106,"code":8139,"language":108,"meta":48,"style":48},"int attempts = 0;\ndo\n{\n    connected = tryConnect();\n    attempts++;\n} while (!connected && attempts \u003C 3); \u002F\u002F this semicolon is required\n",[95,8141,8142,8146,8151,8155,8159,8163],{"__ignoreMap":48},[112,8143,8144],{"class":114,"line":115},[112,8145,8092],{},[112,8147,8148],{"class":114,"line":49},[112,8149,8150],{},"do\n",[112,8152,8153],{"class":114,"line":126},[112,8154,123],{},[112,8156,8157],{"class":114,"line":132},[112,8158,8005],{},[112,8160,8161],{"class":114,"line":138},[112,8162,8111],{},[112,8164,8165],{"class":114,"line":144},[112,8166,8167],{},"} while (!connected && attempts \u003C 3); \u002F\u002F this semicolon is required\n",[15,8169,8170,8171,8174,8175,8177,8178,8180],{},"This is the first loop in this lesson, reshaped: the first connection attempt happens unconditionally, and the test only decides whether to try ",[494,8172,8173],{},"again",". Use ",[95,8176,8131],{}," when there's nothing to test until the body has run once; otherwise, a plain ",[95,8179,7977],{}," is the usual choice.",[69,8182,8184],{"id":8183},"leaving-a-loop-early-break-and-continue","Leaving a Loop Early: break and continue",[15,8186,8187,8188,8190,8191,8194],{},"Two statements change a loop's flow from inside its body. ",[95,8189,5806],{}," ends the loop immediately; ",[95,8192,8193],{},"continue"," skips the rest of the current pass and moves on to the next one:",[104,8196,8198],{"className":106,"code":8197,"language":108,"meta":48,"style":48},"for (int port = 0; port \u003C 10; port++)\n{\n    if (port == 3)\n    {\n        continue; \u002F\u002F port 3 is reserved: skip to the next pass\n    }\n    if (isFree(port))\n    {\n        System.out.println(\"First free port: \" + port);\n        break;    \u002F\u002F found one: stop the whole loop now\n    }\n}\n",[95,8199,8200,8205,8209,8214,8218,8223,8227,8232,8236,8241,8246,8250],{"__ignoreMap":48},[112,8201,8202],{"class":114,"line":115},[112,8203,8204],{},"for (int port = 0; port \u003C 10; port++)\n",[112,8206,8207],{"class":114,"line":49},[112,8208,123],{},[112,8210,8211],{"class":114,"line":126},[112,8212,8213],{},"    if (port == 3)\n",[112,8215,8216],{"class":114,"line":132},[112,8217,135],{},[112,8219,8220],{"class":114,"line":138},[112,8221,8222],{},"        continue; \u002F\u002F port 3 is reserved: skip to the next pass\n",[112,8224,8225],{"class":114,"line":144},[112,8226,147],{},[112,8228,8229],{"class":114,"line":150},[112,8230,8231],{},"    if (isFree(port))\n",[112,8233,8234],{"class":114,"line":2276},[112,8235,135],{},[112,8237,8238],{"class":114,"line":2282},[112,8239,8240],{},"        System.out.println(\"First free port: \" + port);\n",[112,8242,8243],{"class":114,"line":2288},[112,8244,8245],{},"        break;    \u002F\u002F found one: stop the whole loop now\n",[112,8247,8248],{"class":114,"line":5760},[112,8249,147],{},[112,8251,8252],{"class":114,"line":5766},[112,8253,153],{},[15,8255,8256,8257,8259,8260,8262,8263,8266,8267,8269,8270,8272,8273,8275],{},"In a ",[95,8258,5188],{}," loop, ",[95,8261,8193],{}," still runs the update (",[95,8264,8265],{},"port++",") before the next test; in a ",[95,8268,7977],{}," loop, it jumps straight to the test. Inside nested loops, both affect only the innermost loop they're in. (",[95,8271,5806],{}," also ends a case in a ",[95,8274,5700],{}," statement — Lesson 5.12.)",[69,8277,462],{"id":461},[19,8279,8280,8289,8295,8316],{},[22,8281,8282,8285,8286,8288],{},[25,8283,8284],{},"Forgetting to update the loop variable."," The single most common cause of an infinite loop — every ",[95,8287,7977],{}," loop needs something inside it that eventually makes the condition false.",[22,8290,8291,8294],{},[25,8292,8293],{},"A condition that's false from the very first check."," If the condition never holds, the loop body never runs at all — not even once. Double-check the loop variable's starting value against the condition.",[22,8296,8297,476,8303,217,8306,8308,8309,8311,8312,8315],{},[25,8298,8299,8300,8302],{},"Leaving off the semicolon after a ",[95,8301,8131],{},"'s condition.",[95,8304,8305],{},"} while (attempts \u003C 3)",[95,8307,238],{}," won't compile. The opposite mistake, a stray ",[95,8310,238],{}," right after a plain ",[95,8313,8314],{},"while (...)"," header, gives the loop an empty body — and an infinite loop if the condition starts true.",[22,8317,8318,8325,8326,8328,8329,8331],{},[25,8319,405,8320,6439,8322,8324],{},[95,8321,8193],{},[95,8323,7977],{}," loop that skips the update."," If the update (",[95,8327,5270],{},") comes after the ",[95,8330,8193],{},", the skipped pass never reaches it, and the loop repeats the same value forever.",[69,8333,501],{"id":500},[19,8335,8336,8345,8350,8353,8358,8366],{},[22,8337,8338,8339,8341,8342,8344],{},"Every loop needs three steps: initialize, test, update — ",[95,8340,7977],{}," just doesn't bundle them into one line like ",[95,8343,5188],{}," does.",[22,8346,405,8347,8349],{},[95,8348,7977],{}," loop's condition is checked before every pass, including the first — if it starts false, the body never runs.",[22,8351,8352],{},"Forgetting to update the loop variable is the classic cause of an infinite loop, which can freeze a robot's control code.",[22,8354,8355,8357],{},[95,8356,7977],{}," fits naturally when you're repeating until a condition changes rather than counting a known number of iterations.",[22,8359,405,8360,8362,8363,8365],{},[95,8361,8131],{}," checks its condition after each pass, so its body always runs at least once — and its closing ",[95,8364,8314],{}," needs a semicolon.",[22,8367,8368,8370,8371,8373],{},[95,8369,5806],{}," ends the innermost loop immediately; ",[95,8372,8193],{}," skips to that loop's next pass.",[15,8375,544,8376,548,8378,8381],{},[95,8377,547],{},[95,8379,8380],{},"unit-2-selection-and-iteration\u002F2.07-while-loops.md"," (CSA 2.7)",[554,8383,556],{},{"title":48,"searchDepth":49,"depth":49,"links":8385},[8386,8387,8388,8390,8391,8392,8393],{"id":7971,"depth":49,"text":7972},{"id":8026,"depth":49,"text":8027},{"id":8064,"depth":49,"text":8389},"When to Reach for while Instead of for",{"id":8125,"depth":49,"text":8126},{"id":8183,"depth":49,"text":8184},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":8395,"status":570},"5.8 — While Loops (CSA 2.7)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F8-while-loops",{"title":7963,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.8-while-loops","AaW0N0Efpur_KSKl4OmoYb0yB1-i0l6Q6-5yIkTgCQ8",{"id":8401,"title":8402,"body":8403,"description":8410,"extension":51,"meta":8722,"navigation":55,"path":8724,"seo":8725,"stem":8726,"__hash__":8727},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.9-implementing-selection-and-iteration-algorithms.md","Implementing Selection and Iteration Algorithms",{"type":8,"value":8404,"toc":8714},[8405,8408,8411,8435,8439,8442,8475,8479,8485,8525,8555,8559,8562,8603,8607,8616,8639,8641,8681,8683,8704,8712],[11,8406,8402],{"id":8407},"implementing-selection-and-iteration-algorithms",[15,8409,8410],{},"A handful of loop-and-selection patterns come up constantly. Once you recognize them, you'll see the same shape everywhere.",[15,8412,8413],{},[494,8414,8415,8416,322,8419,8421,8422,8424,8425,8428,8429,4090,8432,8434],{},"The examples below loop over an existing collection (",[95,8417,8418],{},"visionLatencies",[95,8420,5232],{},") with an enhanced ",[95,8423,5188],{}," — building your own comes in Ch.9. Read ",[95,8426,8427],{},"for (double sample : visionLatencies)"," as \"for each ",[95,8430,8431],{},"sample",[95,8433,8418],{},"\": the loop variable takes each value in turn, first to last, with no index to manage (Lesson 9.4 covers it fully). For now, focus on the accumulator\u002Fselection shape itself; it applies the same way once you get there.",[69,8436,8438],{"id":8437},"the-accumulator-pattern","The Accumulator Pattern",[15,8440,8441],{},"Build up a running total across a loop: initialize before the loop, update inside it, use the result after.",[104,8443,8445],{"className":106,"code":8444,"language":108,"meta":48,"style":48},"double sum = 0;\nfor (double sample : visionLatencies)\n{\n    sum += sample; \u002F\u002F accumulate\n}\ndouble average = sum \u002F visionLatencies.size();\n",[95,8446,8447,8452,8457,8461,8466,8470],{"__ignoreMap":48},[112,8448,8449],{"class":114,"line":115},[112,8450,8451],{},"double sum = 0;\n",[112,8453,8454],{"class":114,"line":49},[112,8455,8456],{},"for (double sample : visionLatencies)\n",[112,8458,8459],{"class":114,"line":126},[112,8460,123],{},[112,8462,8463],{"class":114,"line":132},[112,8464,8465],{},"    sum += sample; \u002F\u002F accumulate\n",[112,8467,8468],{"class":114,"line":138},[112,8469,153],{},[112,8471,8472],{"class":114,"line":144},[112,8473,8474],{},"double average = sum \u002F visionLatencies.size();\n",[69,8476,8478],{"id":8477},"minmax-with-an-if-inside-a-loop","Min\u002FMax with an if Inside a Loop",[15,8480,8481,8482,8484],{},"Track the smallest or largest value seen so far by pairing an accumulator with an ",[95,8483,2179],{}," inside the loop:",[104,8486,8488],{"className":106,"code":8487,"language":108,"meta":48,"style":48},"double max = Double.NEGATIVE_INFINITY; \u002F\u002F below every real number\nfor (double sample : visionLatencies)\n{\n    if (sample > max)\n    {\n        max = sample; \u002F\u002F running max\n    }\n}\n",[95,8489,8490,8495,8499,8503,8508,8512,8517,8521],{"__ignoreMap":48},[112,8491,8492],{"class":114,"line":115},[112,8493,8494],{},"double max = Double.NEGATIVE_INFINITY; \u002F\u002F below every real number\n",[112,8496,8497],{"class":114,"line":49},[112,8498,8456],{},[112,8500,8501],{"class":114,"line":126},[112,8502,123],{},[112,8504,8505],{"class":114,"line":132},[112,8506,8507],{},"    if (sample > max)\n",[112,8509,8510],{"class":114,"line":138},[112,8511,135],{},[112,8513,8514],{"class":114,"line":144},[112,8515,8516],{},"        max = sample; \u002F\u002F running max\n",[112,8518,8519],{"class":114,"line":150},[112,8520,147],{},[112,8522,8523],{"class":114,"line":2276},[112,8524,153],{},[15,8526,8527,8530,8531,8533,8534,8537,8538,8540,8541,8544,8545,476,8548,8550,8551,8554],{},[95,8528,8529],{},"Double.NEGATIVE_INFINITY"," is a special ",[95,8532,631],{}," value smaller than every real number, so the first sample always replaces it. (",[95,8535,8536],{},"Double"," is Java's wrapper class for ",[95,8539,631],{},"; its constants and the other wrapper classes come in Lesson 9.2.) Watch out for the similar-looking ",[95,8542,8543],{},"Double.MIN_VALUE",": despite the name, it's the smallest ",[494,8546,8547],{},"positive",[95,8549,631],{}," (about ",[95,8552,8553],{},"4.9E-324","), so a max seeded with it stays wrong whenever every sample is zero or negative.",[69,8556,8558],{"id":8557},"frequency-counting","Frequency Counting",[15,8560,8561],{},"Count how many values in a sequence meet some criterion, using a counter incremented inside a conditional:",[104,8563,8565],{"className":106,"code":8564,"language":108,"meta":48,"style":48},"int faultyCount = 0;\nfor (Sensor sensor : sensors)\n{\n    if (sensor.isFaulty())\n    {\n        faultyCount++;\n    }\n}\n",[95,8566,8567,8572,8577,8581,8586,8590,8595,8599],{"__ignoreMap":48},[112,8568,8569],{"class":114,"line":115},[112,8570,8571],{},"int faultyCount = 0;\n",[112,8573,8574],{"class":114,"line":49},[112,8575,8576],{},"for (Sensor sensor : sensors)\n",[112,8578,8579],{"class":114,"line":126},[112,8580,123],{},[112,8582,8583],{"class":114,"line":132},[112,8584,8585],{},"    if (sensor.isFaulty())\n",[112,8587,8588],{"class":114,"line":138},[112,8589,135],{},[112,8591,8592],{"class":114,"line":144},[112,8593,8594],{},"        faultyCount++;\n",[112,8596,8597],{"class":114,"line":150},[112,8598,147],{},[112,8600,8601],{"class":114,"line":2276},[112,8602,153],{},[69,8604,8606],{"id":8605},"simulating-probability-with-mathrandom","Simulating Probability with Math.random()",[15,8608,8609,8612,8613,8615],{},[95,8610,8611],{},"Math.random() \u003C p"," is true with probability ",[95,8614,15],{}," — a real way to simulate an event that happens some percentage of the time (useful for testing code against randomized simulated sensor noise, for instance):",[104,8617,8619],{"className":106,"code":8618,"language":108,"meta":48,"style":48},"if (Math.random() \u003C 0.1) \u002F\u002F roughly 10% of the time\n{\n    simulateSensorGlitch();\n}\n",[95,8620,8621,8626,8630,8635],{"__ignoreMap":48},[112,8622,8623],{"class":114,"line":115},[112,8624,8625],{},"if (Math.random() \u003C 0.1) \u002F\u002F roughly 10% of the time\n",[112,8627,8628],{"class":114,"line":49},[112,8629,123],{},[112,8631,8632],{"class":114,"line":126},[112,8633,8634],{},"    simulateSensorGlitch();\n",[112,8636,8637],{"class":114,"line":132},[112,8638,153],{},[69,8640,462],{"id":461},[19,8642,8643,8672],{},[22,8644,8645,8648,8649,8651,8652,8654,8655,322,8657,8660,8661,8663,8664,8666,8667,476,8669,8671],{},[25,8646,8647],{},"Initializing an accumulator with the wrong starting value."," A sum starts at ",[95,8650,1365],{},"; a max should start below every possible value (",[95,8653,8529],{}," for a ",[95,8656,631],{},[95,8658,8659],{},"Integer.MIN_VALUE"," for an ",[95,8662,603],{},") so the very first real value always replaces it. Not ",[95,8665,8543],{}," — that's the smallest ",[494,8668,8547],{},[95,8670,631],{},", not the most negative one.",[22,8673,8674,8677,8678,8680],{},[25,8675,8676],{},"Putting the accumulator update outside the loop."," It has to be ",[494,8679,2168],{}," the loop body to actually accumulate across every iteration.",[69,8682,501],{"id":500},[19,8684,8685,8688,8694,8697],{},[22,8686,8687],{},"The accumulator pattern: initialize before the loop, update inside it, use the result after.",[22,8689,8690,8691,8693],{},"Min\u002Fmax tracking pairs an accumulator with an ",[95,8692,2179],{}," inside the loop, comparing each new value against the best one seen so far.",[22,8695,8696],{},"Frequency counting increments a counter inside a conditional, once per matching iteration.",[22,8698,8699,8701,8702,79],{},[95,8700,8611],{}," simulates an event with probability ",[95,8703,15],{},[15,8705,544,8706,548,8708,8711],{},[95,8707,547],{},[95,8709,8710],{},"unit-2-selection-and-iteration\u002F2.09-implementing-selection-and-iteration-algorithms.md"," (CSA 2.9)",[554,8713,556],{},{"title":48,"searchDepth":49,"depth":49,"links":8715},[8716,8717,8718,8719,8720,8721],{"id":8437,"depth":49,"text":8438},{"id":8477,"depth":49,"text":8478},{"id":8557,"depth":49,"text":8558},{"id":8605,"depth":49,"text":8606},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":8723,"status":570},"5.9 — Implementing Selection and Iteration Algorithms (CSA 2.9)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F9-implementing-selection-and-iteration-algorithms",{"title":8402,"description":8410},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.9-implementing-selection-and-iteration-algorithms","mf26x_AIC9kv4dZoTq1lsS6pSgo4iA3SfNjE0gx9e90",{"id":8729,"title":8730,"body":8731,"description":48,"extension":51,"meta":9457,"navigation":55,"path":9459,"seo":9460,"stem":9461,"__hash__":9462},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch06-strings\u002F6.1-strings.md","Strings",{"type":8,"value":8732,"toc":9443},[8733,8736,8740,8755,8770,8780,8784,8789,8809,8813,8820,8829,8851,8855,8881,8895,8902,8919,8934,8950,8959,8963,8998,9005,9009,9015,9144,9173,9206,9228,9243,9251,9266,9291,9293,9344,9346,9433,9441],[11,8734,8730],{"id":8735},"strings",[69,8737,8739],{"id":8738},"strings-are-objects","Strings Are Objects",[15,8741,8742,8744,8745,8747,8748,8750,8751,8754],{},[95,8743,361],{}," is a class, part of ",[95,8746,3200],{}," (no import needed). Like any class, you can create one with ",[95,8749,2504],{},", or with the shorter ",[25,8752,8753],{},"string literal"," syntax:",[104,8756,8758],{"className":106,"code":8757,"language":108,"meta":48,"style":48},"String autoNameA = new String(\"BlueAlliance-Left\"); \u002F\u002F rarely used — explicit new\nString autoNameB = \"BlueAlliance-Left\";              \u002F\u002F the normal way — a literal\n",[95,8759,8760,8765],{"__ignoreMap":48},[112,8761,8762],{"class":114,"line":115},[112,8763,8764],{},"String autoNameA = new String(\"BlueAlliance-Left\"); \u002F\u002F rarely used — explicit new\n",[112,8766,8767],{"class":114,"line":49},[112,8768,8769],{},"String autoNameB = \"BlueAlliance-Left\";              \u002F\u002F the normal way — a literal\n",[15,8771,8772,8773,8775,8776,8779],{},"Both create a ",[95,8774,361],{}," object holding the same text; the literal form (",[95,8777,8778],{},"autoNameB","'s style) is what you'll use almost always. (They're written here as two separately-named variables just to compare the syntax side by side — normally you'd pick one style and use it.)",[69,8781,8783],{"id":8782},"strings-are-immutable","Strings Are Immutable",[15,8785,1153,8786,8788],{},[95,8787,361],{}," is created, its characters can never change. Every method that looks like it \"modifies\" a string actually returns a brand-new one, leaving the original untouched:",[104,8790,8792],{"className":106,"code":8791,"language":108,"meta":48,"style":48},"String name = \"Titan\";\nname.toUpperCase(); \u002F\u002F does nothing useful — the result is thrown away!\nname = name.toUpperCase(); \u002F\u002F this is how you actually keep the change\n",[95,8793,8794,8799,8804],{"__ignoreMap":48},[112,8795,8796],{"class":114,"line":115},[112,8797,8798],{},"String name = \"Titan\";\n",[112,8800,8801],{"class":114,"line":49},[112,8802,8803],{},"name.toUpperCase(); \u002F\u002F does nothing useful — the result is thrown away!\n",[112,8805,8806],{"class":114,"line":126},[112,8807,8808],{},"name = name.toUpperCase(); \u002F\u002F this is how you actually keep the change\n",[69,8810,8812],{"id":8811},"concatenation","Concatenation",[15,8814,8815,537,8817,8819],{},[95,8816,935],{},[95,8818,2375],{}," join strings together, and automatically convert non-string values into strings:",[104,8821,8823],{"className":106,"code":8822,"language":108,"meta":48,"style":48},"String status = \"Auto: \" + autoName + \", step \" + 3; \u002F\u002F the int 3 converts automatically\n",[95,8824,8825],{"__ignoreMap":48},[112,8826,8827],{"class":114,"line":115},[112,8828,8822],{},[15,8830,8831,8832,8834,8835,8838,8839,8842,8843,8846,8847,8850],{},"Watch the order when mixing ",[95,8833,935],{}," with numbers — it's evaluated left to right, so ",[95,8836,8837],{},"\"Score: \" + 1 + 2"," gives ",[95,8840,8841],{},"\"Score: 12\""," (each number appends as text in turn), not ",[95,8844,8845],{},"\"Score: 3\"",". Use parentheses — ",[95,8848,8849],{},"\"Score: \" + (1 + 2)"," — to force the addition first.",[69,8852,8854],{"id":8853},"index-and-length","Index and Length",[15,8856,8857,8858,8861,8862,8865,8866,8869,8870,8873,8874,260,8877,8880],{},"Each character has a position, or ",[25,8859,8860],{},"index",", starting at 0. ",[95,8863,8864],{},"length()"," returns the total character count — the last valid index is always ",[95,8867,8868],{},"length() - 1",". There's no bracket notation like an array's (",[95,8871,8872],{},"autoName[0]"," isn't valid Java) — getting a single character means using ",[95,8875,8876],{},"substring",[95,8878,8879],{},"charAt",", covered next.",[15,8882,8883,8884,4029,8886,6474,8888,8891,8892,4410],{},"Accessing an index outside ",[95,8885,1365],{},[95,8887,8868],{},[95,8889,8890],{},"StringIndexOutOfBoundsException"," (a kind of ",[95,8893,8894],{},"IndexOutOfBoundsException",[69,8896,8898,537,8900],{"id":8897},"charat-and-char",[95,8899,8879],{},[95,8901,686],{},[15,8903,8904,8907,8908,845,8910,8913,8914,8916,8917,738],{},[95,8905,8906],{},"substring(i, i + 1)"," gets a single character back as a one-character ",[95,8909,361],{},[95,8911,8912],{},"charAt(i)"," is the more direct way — it returns that one character as a ",[95,8915,686],{},", a primitive type (Ch.2.1), not a ",[95,8918,361],{},[104,8920,8922],{"className":106,"code":8921,"language":108,"meta":48,"style":48},"char first = autoName.charAt(0);            \u002F\u002F 'B' — a char, single-quoted\nString firstAsString = autoName.substring(0, 1); \u002F\u002F \"B\" — a String, double-quoted\n",[95,8923,8924,8929],{"__ignoreMap":48},[112,8925,8926],{"class":114,"line":115},[112,8927,8928],{},"char first = autoName.charAt(0);            \u002F\u002F 'B' — a char, single-quoted\n",[112,8930,8931],{"class":114,"line":49},[112,8932,8933],{},"String firstAsString = autoName.substring(0, 1); \u002F\u002F \"B\" — a String, double-quoted\n",[15,8935,8936,8937,8939,8940,8942,8943,959,8945,8947,8948,738],{},"Because ",[95,8938,686],{}," is a primitive, compare two ",[95,8941,686],{}," values with ",[95,8944,1921],{},[95,8946,7836],{}," — the opposite of the rule for ",[95,8949,361],{},[104,8951,8953],{"className":106,"code":8952,"language":108,"meta":48,"style":48},"if (autoName.charAt(0) == 'B') \u002F\u002F correct for char — == is fine here\n",[95,8954,8955],{"__ignoreMap":48},[112,8956,8957],{"class":114,"line":115},[112,8958,8952],{},[69,8960,8962],{"id":8961},"the-core-string-methods","The Core String Methods",[104,8964,8966],{"className":106,"code":8965,"language":108,"meta":48,"style":48},"String autoName = \"BlueAlliance-Left\";\nautoName.length();          \u002F\u002F 17\nautoName.substring(0, 4);   \u002F\u002F \"Blue\" — from index 0 up to (not including) 4\nautoName.substring(13);     \u002F\u002F \"Left\" — from index 13 to the end\nautoName.indexOf(\"Left\");   \u002F\u002F 13 — or -1 if not found\nautoName.equals(\"BlueAlliance-Left\"); \u002F\u002F true — compares actual characters\n",[95,8967,8968,8973,8978,8983,8988,8993],{"__ignoreMap":48},[112,8969,8970],{"class":114,"line":115},[112,8971,8972],{},"String autoName = \"BlueAlliance-Left\";\n",[112,8974,8975],{"class":114,"line":49},[112,8976,8977],{},"autoName.length();          \u002F\u002F 17\n",[112,8979,8980],{"class":114,"line":126},[112,8981,8982],{},"autoName.substring(0, 4);   \u002F\u002F \"Blue\" — from index 0 up to (not including) 4\n",[112,8984,8985],{"class":114,"line":132},[112,8986,8987],{},"autoName.substring(13);     \u002F\u002F \"Left\" — from index 13 to the end\n",[112,8989,8990],{"class":114,"line":138},[112,8991,8992],{},"autoName.indexOf(\"Left\");   \u002F\u002F 13 — or -1 if not found\n",[112,8994,8995],{"class":114,"line":144},[112,8996,8997],{},"autoName.equals(\"BlueAlliance-Left\"); \u002F\u002F true — compares actual characters\n",[15,8999,9000,9002,9003,79],{},[95,9001,8906],{}," is the standard way to get just the single character at index ",[95,9004,5244],{},[69,9006,9008],{"id":9007},"other-everyday-string-methods","Other Everyday String Methods",[15,9010,9011,9012,9014],{},"Several more ",[95,9013,361],{}," methods come up constantly in real code:",[3819,9016,9017,9026],{},[3822,9018,9019],{},[3825,9020,9021,9023],{},[3828,9022,3830],{},[3828,9024,9025],{},"What it does",[3838,9027,9028,9041,9054,9069,9086,9101,9114,9130],{},[3825,9029,9030,9035],{},[3843,9031,9032],{},[95,9033,9034],{},"equalsIgnoreCase(other)",[3843,9036,9037,9038,9040],{},"like ",[95,9039,7836],{},", but treats upper\u002Flowercase as the same",[3825,9042,9043,9048],{},[3843,9044,9045],{},[95,9046,9047],{},"compareTo(other)",[3843,9049,9050,9051],{},"negative\u002Fzero\u002Fpositive — alphabetical order relative to ",[95,9052,9053],{},"other",[3825,9055,9056,9061],{},[3843,9057,9058],{},[95,9059,9060],{},"contains(text)",[3843,9062,9063,9065,9066,9068],{},[95,9064,661],{}," if ",[95,9067,6629],{}," appears anywhere inside",[3825,9070,9071,9079],{},[3843,9072,9073,3848,9076],{},[95,9074,9075],{},"startsWith(text)",[95,9077,9078],{},"endsWith(text)",[3843,9080,9081,9083,9084],{},[95,9082,661],{}," if the string begins\u002Fends with ",[95,9085,6629],{},[3825,9087,9088,9096],{},[3843,9089,9090,3848,9093],{},[95,9091,9092],{},"isEmpty()",[95,9094,9095],{},"isBlank()",[3843,9097,9098,9100],{},[95,9099,661],{}," if length is 0 \u002F if it's empty or all whitespace",[3825,9102,9103,9111],{},[3843,9104,9105,3848,9108],{},[95,9106,9107],{},"trim()",[95,9109,9110],{},"strip()",[3843,9112,9113],{},"a copy with leading\u002Ftrailing whitespace removed",[3825,9115,9116,9121],{},[3843,9117,9118],{},[95,9119,9120],{},"replace(old, new)",[3843,9122,9123,9124,9127,9128],{},"a copy with every occurrence of ",[95,9125,9126],{},"old"," swapped for ",[95,9129,2504],{},[3825,9131,9132,9137],{},[3843,9133,9134],{},[95,9135,9136],{},"split(regex)",[3843,9138,9139,9140,9143],{},"breaks the string apart into a ",[95,9141,9142],{},"String[]"," around a separator",[104,9145,9147],{"className":106,"code":9146,"language":108,"meta":48,"style":48},"\"  R2-1622  \".trim();                    \u002F\u002F \"R2-1622\"\n\"BlueAlliance\".contains(\"Alliance\");     \u002F\u002F true\n\"Left\".equalsIgnoreCase(\"LEFT\");         \u002F\u002F true\n",[95,9148,9149,9157,9165],{"__ignoreMap":48},[112,9150,9151,9154],{"class":114,"line":115},[112,9152,9153],{},"\"  R2-1622  \".trim();",[112,9155,9156],{},"                    \u002F\u002F \"R2-1622\"\n",[112,9158,9159,9162],{"class":114,"line":49},[112,9160,9161],{},"\"BlueAlliance\".contains(\"Alliance\");",[112,9163,9164],{},"     \u002F\u002F true\n",[112,9166,9167,9170],{"class":114,"line":126},[112,9168,9169],{},"\"Left\".equalsIgnoreCase(\"LEFT\");",[112,9171,9172],{},"         \u002F\u002F true\n",[15,9174,405,9175,9177,9178,9180,9181,1534,9184,9186,9187,9189,9190,9192,9193,9196,9197,1291,9200,9202,9203,8344],{},[95,9176,361],{}," variable can be ",[95,9179,4645],{}," — a reference (Ch.7) pointing at no object at all. Calling a method ",[494,9182,9183],{},"on",[95,9185,4645],{}," String throws a ",[95,9188,4678],{},". If you're comparing against a value that might be ",[95,9191,4645],{},", put a known-non-null literal first: ",[95,9194,9195],{},"\"Left\".equals(status)"," never throws even if ",[95,9198,9199],{},"status",[95,9201,4645],{},", but ",[95,9204,9205],{},"status.equals(\"Left\")",[15,9207,9208,9211,9212,9215,9216,9219,9220,9223,9224,9227],{},[95,9209,9210],{},"String.format(...)"," (and ",[95,9213,9214],{},"System.out.printf(...)",", which prints the formatted result directly) builds a formatted string from a pattern: ",[95,9217,9218],{},"%.2f"," for a number to 2 decimal places, ",[95,9221,9222],{},"%d"," for an integer, ",[95,9225,9226],{},"%s"," for a string.",[104,9229,9231],{"className":106,"code":9230,"language":108,"meta":48,"style":48},"String msg = String.format(\"Speed: %.2f, Cycle: %d\", 0.755, 3);\n\u002F\u002F \"Speed: 0.76, Cycle: 3\"\n",[95,9232,9233,9238],{"__ignoreMap":48},[112,9234,9235],{"class":114,"line":115},[112,9236,9237],{},"String msg = String.format(\"Speed: %.2f, Cycle: %d\", 0.755, 3);\n",[112,9239,9240],{"class":114,"line":49},[112,9241,9242],{},"\u002F\u002F \"Speed: 0.76, Cycle: 3\"\n",[69,9244,9246,9248,9249],{"id":9245},"equals-not",[95,9247,7836],{},", Not ",[95,9250,1921],{},[15,9252,9253,9255,9256,9258,9259,9262,9263,9265],{},[95,9254,1921],{}," on a ",[95,9257,361],{}," checks whether two variables point at the ",[494,9260,9261],{},"same object"," — not whether their text matches. Use ",[95,9264,7836],{}," to compare actual content:",[104,9267,9269],{"className":106,"code":9268,"language":108,"meta":48,"style":48},"String a = new String(\"Left\");\nString b = new String(\"Left\");\nSystem.out.println(a == b);       \u002F\u002F false — two different objects\nSystem.out.println(a.equals(b));  \u002F\u002F true — same characters\n",[95,9270,9271,9276,9281,9286],{"__ignoreMap":48},[112,9272,9273],{"class":114,"line":115},[112,9274,9275],{},"String a = new String(\"Left\");\n",[112,9277,9278],{"class":114,"line":49},[112,9279,9280],{},"String b = new String(\"Left\");\n",[112,9282,9283],{"class":114,"line":126},[112,9284,9285],{},"System.out.println(a == b);       \u002F\u002F false — two different objects\n",[112,9287,9288],{"class":114,"line":132},[112,9289,9290],{},"System.out.println(a.equals(b));  \u002F\u002F true — same characters\n",[69,9292,462],{"id":461},[19,9294,9295,9312,9325],{},[22,9296,9297,9302,9303,9305,9306,9308,9309,9311],{},[25,9298,6835,9299,9301],{},[95,9300,1921],{}," to compare string content."," It always compiles and runs — ",[95,9304,1921],{}," never errors on strings. It can even seem to work at first, since identical string literals are often the very same object — but it silently fails on strings built at runtime (",[95,9307,8876],{},", concatenation, input). Always use ",[95,9310,7836],{}," for strings.",[22,9313,9314,476,9317,9320,9321,9324],{},[25,9315,9316],{},"Forgetting a string method's result has to be used.",[95,9318,9319],{},"autoName.toUpperCase();"," alone does nothing — strings are immutable, so the result must be captured (",[95,9322,9323],{},"autoName = autoName.toUpperCase();",") or it's lost.",[22,9326,9327,6471,9332,9335,9336,9339,9340,9343],{},[25,9328,9329,9330,79],{},"Off-by-one in ",[95,9331,8876],{},[95,9333,9334],{},"to"," index in ",[95,9337,9338],{},"substring(from, to)"," is exclusive — ",[95,9341,9342],{},"substring(0, 4)"," gives 4 characters (indices 0-3), not 5.",[69,9345,501],{"id":500},[19,9347,9348,9357,9360,9367,9395,9425],{},[22,9349,9350,9352,9353,9356],{},[95,9351,361],{}," is a class; string literals (",[95,9354,9355],{},"\"text\"",") are the normal way to create one.",[22,9358,9359],{},"Strings are immutable — every \"modifying\" method returns a new string instead of changing the original.",[22,9361,9362,176,9364,9366],{},[95,9363,935],{},[95,9365,2375],{}," concatenate, auto-converting non-string values to text.",[22,9368,9369,322,9371,322,9374,322,9377,9380,9381,4226,9383,9385,9386,9388,9389,4226,9391,9385,9393,4410],{},[95,9370,8864],{},[95,9372,9373],{},"substring()",[95,9375,9376],{},"indexOf()",[95,9378,9379],{},"charAt()"," are the core methods, all indexed from 0. ",[95,9382,9379],{},[95,9384,686],{}," (compare with ",[95,9387,1921],{},"); ",[95,9390,9373],{},[95,9392,361],{},[95,9394,7836],{},[22,9396,9397,322,9400,322,9403,176,9406,322,9409,322,9412,325,9415,9418,9419,9421,9422,9424],{},[95,9398,9399],{},"equalsIgnoreCase",[95,9401,9402],{},"contains",[95,9404,9405],{},"trim",[95,9407,9408],{},"strip",[95,9410,9411],{},"replace",[95,9413,9414],{},"split",[95,9416,9417],{},"String.format"," cover most everyday text work; a ",[95,9420,4645],{}," String throws ",[95,9423,4678],{}," if you call a method on it.",[22,9426,1396,9427,9429,9430,9432],{},[95,9428,7836],{}," to compare string content — ",[95,9431,1921],{}," only checks whether two variables reference the same object.",[15,9434,544,9435,548,9437,9440],{},[95,9436,547],{},[95,9438,9439],{},"unit-1-using-objects-and-methods\u002F1.15-strings.md"," (CSA 1.15)",[554,9442,556],{},{"title":48,"searchDepth":49,"depth":49,"links":9444},[9445,9446,9447,9448,9449,9451,9452,9453,9455,9456],{"id":8738,"depth":49,"text":8739},{"id":8782,"depth":49,"text":8783},{"id":8811,"depth":49,"text":8812},{"id":8853,"depth":49,"text":8854},{"id":8897,"depth":49,"text":9450},"charAt and char",{"id":8961,"depth":49,"text":8962},{"id":9007,"depth":49,"text":9008},{"id":9245,"depth":49,"text":9454},".equals(), Not ==",{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":9458,"status":570},"6.1 — Strings (CSA 1.15)","\u002Fshockwave-curriculum\u002Flessons\u002Fch06-strings\u002F1-strings",{"title":8730,"description":48},"shockwave-curriculum\u002Flessons\u002Fch06-strings\u002F6.1-strings","Cyn0JW5XhUyzVjniENh-Y3q1-cvNxjQDiDP-B53oPPo",{"id":9464,"title":9465,"body":9466,"description":48,"extension":51,"meta":9766,"navigation":55,"path":9768,"seo":9769,"stem":9770,"__hash__":9771},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch06-strings\u002F6.2-string-algorithms.md","String Algorithms",{"type":8,"value":9467,"toc":9758},[9468,9471,9475,9482,9527,9536,9546,9554,9601,9622,9626,9629,9661,9688,9690,9724,9726,9748,9756],[11,9469,9465],{"id":9470},"string-algorithms",[69,9472,9474],{"id":9473},"scanning-a-string-character-by-character","Scanning a String Character by Character",[15,9476,405,9477,9479,9480,738],{},[95,9478,5188],{}," loop is the standard way to visit every character of a string — start at 0, stop before ",[95,9481,8864],{},[104,9483,9485],{"className":106,"code":9484,"language":108,"meta":48,"style":48},"String autoName = \"BlueAlliance-Left\";\nint dashCount = 0;\nfor (int i = 0; i \u003C autoName.length(); i++)\n{\n    if (autoName.substring(i, i + 1).equals(\"-\"))\n    {\n        dashCount++;\n    }\n}\n",[95,9486,9487,9491,9496,9501,9505,9510,9514,9519,9523],{"__ignoreMap":48},[112,9488,9489],{"class":114,"line":115},[112,9490,8972],{},[112,9492,9493],{"class":114,"line":49},[112,9494,9495],{},"int dashCount = 0;\n",[112,9497,9498],{"class":114,"line":126},[112,9499,9500],{},"for (int i = 0; i \u003C autoName.length(); i++)\n",[112,9502,9503],{"class":114,"line":132},[112,9504,123],{},[112,9506,9507],{"class":114,"line":138},[112,9508,9509],{},"    if (autoName.substring(i, i + 1).equals(\"-\"))\n",[112,9511,9512],{"class":114,"line":144},[112,9513,135],{},[112,9515,9516],{"class":114,"line":150},[112,9517,9518],{},"        dashCount++;\n",[112,9520,9521],{"class":114,"line":2276},[112,9522,147],{},[112,9524,9525],{"class":114,"line":2282},[112,9526,153],{},[15,9528,9529,9530,9532,9533,9535],{},"Use a ",[95,9531,5188],{}," loop when you know you want to check every character. Use a ",[95,9534,7977],{}," loop instead when you're searching for something and don't know in advance how many characters you'll need to check — see the find-and-replace pattern below.",[69,9537,9539,9540,9543,9544],{"id":9538},"find-and-replace-with-indexof-substring","Find and Replace with ",[95,9541,9542],{},"indexOf"," + ",[95,9545,8876],{},[15,9547,405,9548,9550,9551,9553],{},[95,9549,7977],{}," loop paired with ",[95,9552,9542],{}," repeatedly finds and processes one match at a time, until none remain:",[104,9555,9557],{"className":106,"code":9556,"language":108,"meta":48,"style":48},"String name = \"A11iance\";\nint i = 0;\nwhile (name.indexOf(\"1\") >= 0)\n{\n    i = name.indexOf(\"1\");\n    String firstPart = name.substring(0, i);\n    String lastPart = name.substring(i + 1);\n    name = firstPart + \"l\" + lastPart; \u002F\u002F replace the \"1\" with \"l\"\n}\n",[95,9558,9559,9564,9568,9573,9577,9582,9587,9592,9597],{"__ignoreMap":48},[112,9560,9561],{"class":114,"line":115},[112,9562,9563],{},"String name = \"A11iance\";\n",[112,9565,9566],{"class":114,"line":49},[112,9567,8040],{},[112,9569,9570],{"class":114,"line":126},[112,9571,9572],{},"while (name.indexOf(\"1\") >= 0)\n",[112,9574,9575],{"class":114,"line":132},[112,9576,123],{},[112,9578,9579],{"class":114,"line":138},[112,9580,9581],{},"    i = name.indexOf(\"1\");\n",[112,9583,9584],{"class":114,"line":144},[112,9585,9586],{},"    String firstPart = name.substring(0, i);\n",[112,9588,9589],{"class":114,"line":150},[112,9590,9591],{},"    String lastPart = name.substring(i + 1);\n",[112,9593,9594],{"class":114,"line":2276},[112,9595,9596],{},"    name = firstPart + \"l\" + lastPart; \u002F\u002F replace the \"1\" with \"l\"\n",[112,9598,9599],{"class":114,"line":2282},[112,9600,153],{},[15,9602,9603,9604,1694,9607,9610,9611,9614,9615,9618,9619,79],{},"This loop runs twice: the first pass turns ",[95,9605,9606],{},"\"A11iance\"",[95,9608,9609],{},"\"Al1iance\"",", and the second turns that into ",[95,9612,9613],{},"\"Alliance\"",". Each pass finds the ",[494,9616,9617],{},"next"," occurrence, because the string was already reassigned — the search always runs against the current (updated) value of ",[95,9620,9621],{},"name",[69,9623,9625],{"id":9624},"building-a-new-string","Building a New String",[15,9627,9628],{},"Since strings are immutable, \"building\" one really means starting with an empty string and concatenating onto it inside a loop:",[104,9630,9632],{"className":106,"code":9631,"language":108,"meta":48,"style":48},"String reversed = \"\";\nfor (int i = 0; i \u003C autoName.length(); i++)\n{\n    String letter = autoName.substring(i, i + 1);\n    reversed = letter + reversed; \u002F\u002F prepend — builds the string backwards\n}\n",[95,9633,9634,9639,9643,9647,9652,9657],{"__ignoreMap":48},[112,9635,9636],{"class":114,"line":115},[112,9637,9638],{},"String reversed = \"\";\n",[112,9640,9641],{"class":114,"line":49},[112,9642,9500],{},[112,9644,9645],{"class":114,"line":126},[112,9646,123],{},[112,9648,9649],{"class":114,"line":132},[112,9650,9651],{},"    String letter = autoName.substring(i, i + 1);\n",[112,9653,9654],{"class":114,"line":138},[112,9655,9656],{},"    reversed = letter + reversed; \u002F\u002F prepend — builds the string backwards\n",[112,9658,9659],{"class":114,"line":144},[112,9660,153],{},[15,9662,9663,9664,9667,9668,9670,9671,9674,9675,9678,9679,9682,9683,9685,9686,8344],{},"In real code, two shortcuts save you from hand-writing these patterns: ",[95,9665,9666],{},"name.replace(\"1\", \"l\")"," does the entire find-and-replace loop above in one call (every occurrence, no manual ",[95,9669,9542],{}," loop), and ",[95,9672,9673],{},"StringBuilder"," is built for exactly this kind of repeated concatenation — ",[95,9676,9677],{},"new StringBuilder(autoName).reverse().toString()"," reverses a string in one line, and ",[95,9680,9681],{},"append(...)"," avoids creating a new ",[95,9684,361],{}," object on every pass the way ",[95,9687,2375],{},[69,9689,462],{"id":461},[19,9691,9692,9698,9715],{},[22,9693,9694,9697],{},[25,9695,9696],{},"Starting a string-scanning loop at 1 instead of 0."," The first character is always at index 0 — starting at 1 skips it.",[22,9699,9700,476,9709,9712,9713,79],{},[25,9701,6835,9702,3181,9704,9706,9707,79],{},[95,9703,5263],{},[95,9705,5257],{}," against ",[95,9708,8864],{},[95,9710,9711],{},"i \u003C= autoName.length()"," reads one index past the end and throws ",[95,9714,8890],{},[22,9716,9717,9720,9721,9723],{},[25,9718,9719],{},"An infinite loop in a find-and-replace pattern."," If the replacement text itself still contains the thing you're searching for, ",[95,9722,9542],{}," finds it again forever — make sure each pass genuinely reduces what's left to find.",[69,9725,501],{"id":500},[19,9727,9728,9736,9745],{},[22,9729,9730,9732,9733,9735],{},[95,9731,5188],{}," loops fit scanning every character; ",[95,9734,7977],{}," loops fit searching for an unknown number of matches.",[22,9737,9738,9739,9741,9742,9744],{},"A find-and-replace loop combines ",[95,9740,9542],{}," (to locate) with ",[95,9743,8876],{}," (to rebuild around the match), reassigning the string each pass.",[22,9746,9747],{},"Building a new string from scratch means starting empty and concatenating inside a loop — strings can't be modified in place.",[15,9749,544,9750,548,9752,9755],{},[95,9751,547],{},[95,9753,9754],{},"unit-2-selection-and-iteration\u002F2.10-implementing-string-algorithms.md"," (CSA 2.10)",[554,9757,556],{},{"title":48,"searchDepth":49,"depth":49,"links":9759},[9760,9761,9763,9764,9765],{"id":9473,"depth":49,"text":9474},{"id":9538,"depth":49,"text":9762},"Find and Replace with indexOf + substring",{"id":9624,"depth":49,"text":9625},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":9767,"status":570},"6.2 — String Algorithms (CSA 2.10)","\u002Fshockwave-curriculum\u002Flessons\u002Fch06-strings\u002F2-string-algorithms",{"title":9465,"description":48},"shockwave-curriculum\u002Flessons\u002Fch06-strings\u002F6.2-string-algorithms","06R5z5Mo7disM1QtJqyftS12Eh1h31NfkZqry9MIUqo",{"id":9773,"title":9774,"body":9775,"description":48,"extension":51,"meta":10131,"navigation":55,"path":10133,"seo":10134,"stem":10135,"__hash__":10136},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.1-anatomy-of-a-java-class.md","The Class Blueprint",{"type":8,"value":9776,"toc":10122},[9777,9780,9784,9787,9828,9857,9861,9867,9899,9906,9919,9948,9970,9974,10065,10071,10073,10090,10092,10112,10120],[11,9778,9774],{"id":9779},"the-class-blueprint",[69,9781,9783],{"id":9782},"the-three-anatomical-parts","The Three Anatomical Parts",[15,9785,9786],{},"Every class you write has the same three main parts, conventionally written in this order (Java doesn't enforce the order, and a class doesn't have to have a constructor at all — with none written, Java supplies an empty default one, covered in Ch.8):",[104,9788,9790],{"className":106,"code":9789,"language":108,"meta":48,"style":48},"public class Intake\n{\n    \u002F\u002F 1. instance variables — the data each object owns\n\n    \u002F\u002F 2. constructors — initialize the instance variables\n\n    \u002F\u002F 3. methods — the behaviors\n}\n",[95,9791,9792,9797,9801,9806,9810,9815,9819,9824],{"__ignoreMap":48},[112,9793,9794],{"class":114,"line":115},[112,9795,9796],{},"public class Intake\n",[112,9798,9799],{"class":114,"line":49},[112,9800,123],{},[112,9802,9803],{"class":114,"line":126},[112,9804,9805],{},"    \u002F\u002F 1. instance variables — the data each object owns\n",[112,9807,9808],{"class":114,"line":132},[112,9809,907],{"emptyLinePlaceholder":55},[112,9811,9812],{"class":114,"line":138},[112,9813,9814],{},"    \u002F\u002F 2. constructors — initialize the instance variables\n",[112,9816,9817],{"class":114,"line":144},[112,9818,907],{"emptyLinePlaceholder":55},[112,9820,9821],{"class":114,"line":150},[112,9822,9823],{},"    \u002F\u002F 3. methods — the behaviors\n",[112,9825,9826],{"class":114,"line":2276},[112,9827,153],{},[19,9829,9830,9843,9851],{},[22,9831,9832,9835,9836,9839,9840,79],{},[25,9833,9834],{},"Instance variables"," hold the data — each object gets its own separate copy. Two ",[95,9837,9838],{},"Intake"," objects can each have their own ",[95,9841,9842],{},"currentSpeed",[22,9844,9845,9848,9849,79],{},[25,9846,9847],{},"Constructors"," initialize those instance variables when an object is built with ",[95,9850,2504],{},[22,9852,9853,9856],{},[25,9854,9855],{},"Methods"," define what the object can do, and can read\u002Fchange its instance variables.",[69,9858,9860],{"id":9859},"designing-a-class-what-data-does-it-represent","Designing a Class: What Data Does It Represent?",[15,9862,9863,9864,9866],{},"Before writing any code, ask: what does this thing need to know about itself? For an ",[95,9865,9838],{}," subsystem: is it currently deployed? What's its current motor speed? Does it have a sensor reading a game piece?",[104,9868,9870],{"className":106,"code":9869,"language":108,"meta":48,"style":48},"public class Intake\n{\n    private boolean isDeployed;\n    private double currentSpeed;\n    private boolean hasGamePiece;\n}\n",[95,9871,9872,9876,9880,9885,9890,9895],{"__ignoreMap":48},[112,9873,9874],{"class":114,"line":115},[112,9875,9796],{},[112,9877,9878],{"class":114,"line":49},[112,9879,123],{},[112,9881,9882],{"class":114,"line":126},[112,9883,9884],{},"    private boolean isDeployed;\n",[112,9886,9887],{"class":114,"line":132},[112,9888,9889],{},"    private double currentSpeed;\n",[112,9891,9892],{"class":114,"line":138},[112,9893,9894],{},"    private boolean hasGamePiece;\n",[112,9896,9897],{"class":114,"line":144},[112,9898,153],{},[69,9900,9902,9903],{"id":9901},"encapsulation-why-instance-variables-are-private","Encapsulation: Why Instance Variables Are ",[95,9904,9905],{},"private",[15,9907,9908,537,9910,9912,9913,9915,9916,9918],{},[95,9909,175],{},[95,9911,9905],{}," control who can access something. ",[95,9914,175],{}," means any other class can reach it; ",[95,9917,9905],{}," restricts access to code inside that same class only.",[15,9920,9921,9922,9924,9925,9928,9929,9931,9932,9934,9935,9937,9938,9940,9941,9944,9945,9947],{},"Instance variables should almost always be ",[95,9923,9905],{}," — this is ",[25,9926,9927],{},"encapsulation",": the class's internal data is hidden, and other code can only interact with it through the methods the class chooses to expose. This matters in practice: if ",[95,9930,9842],{}," were ",[95,9933,175],{},", any other subsystem could set it directly, bypassing whatever safety logic the ",[95,9936,9838],{}," class's own methods enforce (a ramp limit, a max-speed clamp). Keeping it ",[95,9939,9905],{}," means the ",[494,9942,9943],{},"only"," way to change it is through ",[95,9946,9838],{},"'s own methods, which can enforce those rules every time.",[104,9949,9951],{"className":106,"code":9950,"language":108,"meta":48,"style":48},"public class Intake\n{\n    private double currentSpeed; \u002F\u002F only Intake's own code can touch this directly\n}\n",[95,9952,9953,9957,9961,9966],{"__ignoreMap":48},[112,9954,9955],{"class":114,"line":115},[112,9956,9796],{},[112,9958,9959],{"class":114,"line":49},[112,9960,123],{},[112,9962,9963],{"class":114,"line":126},[112,9964,9965],{},"    private double currentSpeed; \u002F\u002F only Intake's own code can touch this directly\n",[112,9967,9968],{"class":114,"line":132},[112,9969,153],{},[69,9971,9973],{"id":9972},"putting-it-together","Putting It Together",[104,9975,9977],{"className":106,"code":9976,"language":108,"meta":48,"style":48},"public class Intake\n{\n    \u002F\u002F 1. instance variables\n    private boolean isDeployed;\n    private double currentSpeed;\n\n    \u002F\u002F 2. constructor\n    public Intake()\n    {\n        isDeployed = false;\n        currentSpeed = 0.0;\n    }\n\n    \u002F\u002F 3. methods\n    public void deploy()\n    {\n        isDeployed = true;\n    }\n}\n",[95,9978,9979,9983,9987,9992,9996,10000,10004,10009,10014,10018,10023,10028,10032,10036,10041,10046,10050,10055,10060],{"__ignoreMap":48},[112,9980,9981],{"class":114,"line":115},[112,9982,9796],{},[112,9984,9985],{"class":114,"line":49},[112,9986,123],{},[112,9988,9989],{"class":114,"line":126},[112,9990,9991],{},"    \u002F\u002F 1. instance variables\n",[112,9993,9994],{"class":114,"line":132},[112,9995,9884],{},[112,9997,9998],{"class":114,"line":138},[112,9999,9889],{},[112,10001,10002],{"class":114,"line":144},[112,10003,907],{"emptyLinePlaceholder":55},[112,10005,10006],{"class":114,"line":150},[112,10007,10008],{},"    \u002F\u002F 2. constructor\n",[112,10010,10011],{"class":114,"line":2276},[112,10012,10013],{},"    public Intake()\n",[112,10015,10016],{"class":114,"line":2282},[112,10017,135],{},[112,10019,10020],{"class":114,"line":2288},[112,10021,10022],{},"        isDeployed = false;\n",[112,10024,10025],{"class":114,"line":5760},[112,10026,10027],{},"        currentSpeed = 0.0;\n",[112,10029,10030],{"class":114,"line":5766},[112,10031,147],{},[112,10033,10034],{"class":114,"line":5772},[112,10035,907],{"emptyLinePlaceholder":55},[112,10037,10038],{"class":114,"line":5777},[112,10039,10040],{},"    \u002F\u002F 3. methods\n",[112,10042,10043],{"class":114,"line":5783},[112,10044,10045],{},"    public void deploy()\n",[112,10047,10048],{"class":114,"line":5789},[112,10049,135],{},[112,10051,10052],{"class":114,"line":5794},[112,10053,10054],{},"        isDeployed = true;\n",[112,10056,10058],{"class":114,"line":10057},18,[112,10059,147],{},[112,10061,10063],{"class":114,"line":10062},19,[112,10064,153],{},[15,10066,10067,10068,10070],{},"Any class can also have a ",[95,10069,101],{}," method — usually not for the class's normal job, but as a quick way to test that one class in isolation.",[69,10072,462],{"id":461},[19,10074,10075,10084],{},[22,10076,10077,10083],{},[25,10078,10079,10080,10082],{},"Making instance variables ",[95,10081,175],{}," \"to keep things simple.\""," This defeats encapsulation — any other class can then set them to anything, with none of the class's own safety logic enforced.",[22,10085,10086,10089],{},[25,10087,10088],{},"Skipping the design step."," Jumping straight to code without first asking \"what does this class need to know about itself\" tends to produce classes with the wrong data, discovered only after writing several methods around it.",[69,10091,501],{"id":500},[19,10093,10094,10097,10100,10109],{},[22,10095,10096],{},"Every class has the same three parts, conventionally in this order: instance variables, constructors, methods — Java doesn't enforce the order, and a class with no constructor gets an empty default one (Ch.8).",[22,10098,10099],{},"Instance variables are per-object — each object gets its own independent copies.",[22,10101,10102,10103,10105,10106,10108],{},"Instance variables should be ",[95,10104,9905],{},"; methods that are meant to be used by other classes are ",[95,10107,175],{},". This is encapsulation.",[22,10110,10111],{},"Design a class by first asking what data it needs to represent, before writing any code.",[15,10113,544,10114,548,10116,10119],{},[95,10115,547],{},[95,10117,10118],{},"unit-3-class-creation\u002F3.03-anatomy-of-a-java-class.md"," (CSA 3.3)",[554,10121,556],{},{"title":48,"searchDepth":49,"depth":49,"links":10123},[10124,10125,10126,10128,10129,10130],{"id":9782,"depth":49,"text":9783},{"id":9859,"depth":49,"text":9860},{"id":9901,"depth":49,"text":10127},"Encapsulation: Why Instance Variables Are private",{"id":9972,"depth":49,"text":9973},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":10132,"status":570},"7.1 — Anatomy of a Java Class (CSA 3.3)","\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F1-anatomy-of-a-java-class",{"title":9774,"description":48},"shockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.1-anatomy-of-a-java-class","D3971mtj37hbgsc3O11b3MzzQBb4jxlaNBwz2vYZZCU",{"id":10138,"title":10139,"body":10140,"description":48,"extension":51,"meta":10596,"navigation":55,"path":10598,"seo":10599,"stem":10600,"__hash__":10601},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.2-methods-how-to-write-them.md","Methods: How to Write Them",{"type":8,"value":10141,"toc":10586},[10142,10145,10149,10155,10198,10200,10214,10237,10269,10273,10285,10308,10315,10319,10345,10373,10387,10391,10398,10402,10405,10427,10448,10512,10523,10525,10544,10546,10576,10584],[11,10143,10139],{"id":10144},"methods-how-to-write-them",[69,10146,10148],{"id":10147},"void-vs-non-void-revisited-for-your-own-classes","Void vs. Non-Void, Revisited for Your Own Classes",[15,10150,10151,10152,10154],{},"Same rule as Ch.4, now applied to methods you write inside your own class: ",[95,10153,183],{}," methods act (no return value); non-void methods compute and return one.",[104,10156,10158],{"className":106,"code":10157,"language":108,"meta":48,"style":48},"public class Intake\n{\n    private double currentSpeed;\n\n    public void spin(double speed) \u002F\u002F void — acts, doesn't return anything\n    {\n        currentSpeed = speed;\n    }\n}\n",[95,10159,10160,10164,10168,10172,10176,10181,10185,10190,10194],{"__ignoreMap":48},[112,10161,10162],{"class":114,"line":115},[112,10163,9796],{},[112,10165,10166],{"class":114,"line":49},[112,10167,123],{},[112,10169,10170],{"class":114,"line":126},[112,10171,9889],{},[112,10173,10174],{"class":114,"line":132},[112,10175,907],{"emptyLinePlaceholder":55},[112,10177,10178],{"class":114,"line":138},[112,10179,10180],{},"    public void spin(double speed) \u002F\u002F void — acts, doesn't return anything\n",[112,10182,10183],{"class":114,"line":144},[112,10184,135],{},[112,10186,10187],{"class":114,"line":150},[112,10188,10189],{},"        currentSpeed = speed;\n",[112,10191,10192],{"class":114,"line":2276},[112,10193,147],{},[112,10195,10196],{"class":114,"line":2282},[112,10197,153],{},[69,10199,4946],{"id":4945},[15,10201,10202,10203,10205,10206,10208,10209,10211,10212,79],{},"Since instance variables are ",[95,10204,9905],{}," (Lesson 7.1), other classes need a way to read them — a ",[25,10207,4952],{},": a ",[95,10210,175],{}," method, no arguments, that returns one instance variable's value. By convention its name starts with ",[95,10213,4956],{},[104,10215,10217],{"className":106,"code":10216,"language":108,"meta":48,"style":48},"public double getCurrentSpeed()\n{\n    return currentSpeed;\n}\n",[95,10218,10219,10224,10228,10233],{"__ignoreMap":48},[112,10220,10221],{"class":114,"line":115},[112,10222,10223],{},"public double getCurrentSpeed()\n",[112,10225,10226],{"class":114,"line":49},[112,10227,123],{},[112,10229,10230],{"class":114,"line":126},[112,10231,10232],{},"    return currentSpeed;\n",[112,10234,10235],{"class":114,"line":132},[112,10236,153],{},[15,10238,10239,10240,10242,10243,260,10246,3181,10249,10252,10253,10255,10256,260,10259,10262,10263,959,10266,79],{},"You don't need a getter for every instance variable — only the ones other code genuinely needs to read. A getter for a ",[95,10241,657],{}," field is conventionally named ",[95,10244,10245],{},"is...",[95,10247,10248],{},"has...",[95,10250,10251],{},"get..."," (matching a ",[95,10254,657],{}," field itself, like ",[95,10257,10258],{},"isDeployed",[95,10260,10261],{},"hasGamePiece"," from Lesson 7.1) — e.g. ",[95,10264,10265],{},"isDeployed()",[95,10267,10268],{},"getIsDeployed()",[69,10270,10272],{"id":10271},"setters-mutators","Setters (Mutators)",[15,10274,405,10275,10278,10279,10281,10282,10284],{},[25,10276,10277],{},"setter"," is the write-side equivalent: a ",[95,10280,183],{}," method, named starting with ",[95,10283,2531],{},", taking one parameter — the new value — and assigning it to the instance variable.",[104,10286,10288],{"className":106,"code":10287,"language":108,"meta":48,"style":48},"public void setCurrentSpeed(double newSpeed)\n{\n    currentSpeed = newSpeed;\n}\n",[95,10289,10290,10295,10299,10304],{"__ignoreMap":48},[112,10291,10292],{"class":114,"line":115},[112,10293,10294],{},"public void setCurrentSpeed(double newSpeed)\n",[112,10296,10297],{"class":114,"line":49},[112,10298,123],{},[112,10300,10301],{"class":114,"line":126},[112,10302,10303],{},"    currentSpeed = newSpeed;\n",[112,10305,10306],{"class":114,"line":132},[112,10307,153],{},[15,10309,10310,10311,10314],{},"Think just as hard before writing a setter as before writing a getter. Not every instance variable should be freely settable from outside — sometimes the class should only change its own data through a specific method (like ",[95,10312,10313],{},"spin(speed)"," above) that also enforces some rule, rather than through a bare setter that lets anyone assign anything.",[69,10316,10318],{"id":10317},"tostring","toString",[15,10320,10321,10323,10324,10327,10328,10330,10331,10333,10334,10337,10338,10340,10341,10344],{},[95,10322,10318],{}," is a special method Java calls automatically whenever it needs to turn an object into text — including every time you ",[95,10325,10326],{},"System.out.println(someObject)"," or concatenate an object with ",[95,10329,935],{},". Every class actually already has a ",[95,10332,10318],{}," (inherited — Ch.17); writing your own ",[25,10335,10336],{},"overrides"," it with something more useful, which is why the method's name and signature (no parameters, returns ",[95,10339,361],{},") have to match exactly (",[95,10342,10343],{},"@Override"," makes that explicit — also Ch.17).",[104,10346,10348],{"className":106,"code":10347,"language":108,"meta":48,"style":48},"\u002F\u002F assumes 7.1's full Intake, with isDeployed added\npublic String toString()\n{\n    return \"Intake[speed=\" + currentSpeed + \", deployed=\" + isDeployed + \"]\";\n}\n",[95,10349,10350,10355,10360,10364,10369],{"__ignoreMap":48},[112,10351,10352],{"class":114,"line":115},[112,10353,10354],{},"\u002F\u002F assumes 7.1's full Intake, with isDeployed added\n",[112,10356,10357],{"class":114,"line":49},[112,10358,10359],{},"public String toString()\n",[112,10361,10362],{"class":114,"line":126},[112,10363,123],{},[112,10365,10366],{"class":114,"line":132},[112,10367,10368],{},"    return \"Intake[speed=\" + currentSpeed + \", deployed=\" + isDeployed + \"]\";\n",[112,10370,10371],{"class":114,"line":138},[112,10372,153],{},[15,10374,10375,10376,10378,10379,10382,10383,10386],{},"Without a ",[95,10377,10318],{},", printing an object directly gives an unhelpful default (something like ",[95,10380,10381],{},"Intake@1a2b3c",") — writing your own gives every ",[95,10384,10385],{},"System.out.println(myIntake)"," a genuinely useful message instead.",[69,10388,10390],{"id":10389},"method-parameters-revisited","Method Parameters, Revisited",[15,10392,10393,10394,10397],{},"Same call-by-value rule from Ch.4.1: a primitive parameter (",[95,10395,10396],{},"double speed",") gets a copy. Changing it inside the method never affects the caller's original variable.",[69,10399,10401],{"id":10400},"where-variables-live","Where Variables Live",[15,10403,10404],{},"Every variable you've written falls into one of three kinds, based on where it's declared:",[19,10406,10407,10412,10418],{},[22,10408,10409,10411],{},[25,10410,9834],{}," — declared inside the class, outside any method (Lesson 7.1). One copy per object; it lives as long as the object does.",[22,10413,10414,10417],{},[25,10415,10416],{},"Parameters"," — declared in a method's (or constructor's) parameter list. It lives only for that one call — created when the call starts, gone the instant it returns.",[22,10419,10420,10423,10424,10426],{},[25,10421,10422],{},"Local variables"," — declared inside a method's body, or inside a block like an ",[95,10425,2179],{}," or a loop. It lives only inside the block where it's declared — once that block ends, the variable is gone.",[15,10428,10429,10430,10433,10434,10437,10438,10433,10441,10444,10445,10447],{},"Where a variable can be ",[494,10431,10432],{},"used"," is its ",[25,10435,10436],{},"scope","; how long it ",[494,10439,10440],{},"exists",[25,10442,10443],{},"lifetime",". A local variable declared inside an ",[95,10446,2179],{}," block doesn't exist outside that block — reading it afterward is a compile error, not a runtime surprise.",[104,10449,10451],{"className":106,"code":10450,"language":108,"meta":48,"style":48},"public class Intake\n{\n    \u002F\u002F currentSpeed is an instance variable — lives as long as the Intake object does\n    private double currentSpeed;\n\n    \u002F\u002F targetSpeed is a parameter — lives only during this one call to spin()\n    public void spin(double targetSpeed)\n    {\n        \u002F\u002F clamped is a local variable — lives only inside spin()\n        double clamped = targetSpeed;\n        currentSpeed = clamped;\n    } \u002F\u002F clamped and targetSpeed both cease to exist here\n}\n",[95,10452,10453,10457,10461,10466,10470,10474,10479,10484,10488,10493,10498,10503,10508],{"__ignoreMap":48},[112,10454,10455],{"class":114,"line":115},[112,10456,9796],{},[112,10458,10459],{"class":114,"line":49},[112,10460,123],{},[112,10462,10463],{"class":114,"line":126},[112,10464,10465],{},"    \u002F\u002F currentSpeed is an instance variable — lives as long as the Intake object does\n",[112,10467,10468],{"class":114,"line":132},[112,10469,9889],{},[112,10471,10472],{"class":114,"line":138},[112,10473,907],{"emptyLinePlaceholder":55},[112,10475,10476],{"class":114,"line":144},[112,10477,10478],{},"    \u002F\u002F targetSpeed is a parameter — lives only during this one call to spin()\n",[112,10480,10481],{"class":114,"line":150},[112,10482,10483],{},"    public void spin(double targetSpeed)\n",[112,10485,10486],{"class":114,"line":2276},[112,10487,135],{},[112,10489,10490],{"class":114,"line":2282},[112,10491,10492],{},"        \u002F\u002F clamped is a local variable — lives only inside spin()\n",[112,10494,10495],{"class":114,"line":2288},[112,10496,10497],{},"        double clamped = targetSpeed;\n",[112,10499,10500],{"class":114,"line":5760},[112,10501,10502],{},"        currentSpeed = clamped;\n",[112,10504,10505],{"class":114,"line":5766},[112,10506,10507],{},"    } \u002F\u002F clamped and targetSpeed both cease to exist here\n",[112,10509,10510],{"class":114,"line":5772},[112,10511,153],{},[15,10513,10514,10515,10518,10519,10522],{},"A parameter or local variable can have the ",[494,10516,10517],{},"same name"," as an instance variable — inside that method, the closer one (the parameter\u002Flocal) \"wins,\" which is called ",[25,10520,10521],{},"shadowing",". Ch.8 covers this in full, once you've seen a constructor use it on purpose.",[69,10524,462],{"id":461},[19,10526,10527,10533],{},[22,10528,10529,10532],{},[25,10530,10531],{},"Writing a getter or setter for every instance variable reflexively."," Only write one when something outside the class genuinely needs to read or change that specific value — a setter in particular can undermine whatever rules the class's own methods were meant to enforce.",[22,10534,10535,10540,10541,10543],{},[25,10536,4719,10537,10539],{},[95,10538,10318],{}," and being surprised by ugly default output."," If you're going to print an object for debugging or status, ",[95,10542,10318],{}," is worth the two minutes it takes to write.",[69,10545,501],{"id":500},[19,10547,10548,10562,10565,10570,10573],{},[22,10549,10550,10551,260,10553,8654,10556,10558,10559,10561],{},"Getters return an instance variable's value (no parameters, conventionally ",[95,10552,10251],{},[95,10554,10555],{},"is...\u002Fhas...",[95,10557,657],{},"); setters assign a new value (one parameter, ",[95,10560,183],{}," return).",[22,10563,10564],{},"Not every instance variable needs a getter or setter — only add one when something outside the class actually needs it.",[22,10566,10567,10569],{},[95,10568,10318],{}," is called automatically whenever Java needs to convert an object to text — write your own for useful debug output (it overrides the one every class inherits, Ch.17).",[22,10571,10572],{},"Method parameters follow the same call-by-value rule as before: primitives are copied.",[22,10574,10575],{},"Instance variables, parameters, and local variables each have their own scope (where they're visible) and lifetime (how long they exist) — a parameter or local variable can shadow an instance variable of the same name (Ch.8).",[15,10577,544,10578,548,10580,10583],{},[95,10579,547],{},[95,10581,10582],{},"unit-3-class-creation\u002F3.05-methods-how-to-write-them.md"," (CSA 3.5)",[554,10585,556],{},{"title":48,"searchDepth":49,"depth":49,"links":10587},[10588,10589,10590,10591,10592,10593,10594,10595],{"id":10147,"depth":49,"text":10148},{"id":4945,"depth":49,"text":4946},{"id":10271,"depth":49,"text":10272},{"id":10317,"depth":49,"text":10318},{"id":10389,"depth":49,"text":10390},{"id":10400,"depth":49,"text":10401},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":10597,"status":570},"7.2 — Methods: How to Write Them (CSA 3.5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F2-methods-how-to-write-them",{"title":10139,"description":48},"shockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.2-methods-how-to-write-them","6jVxqK6qern1NvP91CU7G-MROzNkOn60Yu3AVocy-Gk",{"id":10603,"title":10604,"body":10605,"description":48,"extension":51,"meta":11047,"navigation":55,"path":11049,"seo":11050,"stem":11051,"__hash__":11052},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.3-methods-passing-and-returning-references-of-an-object.md","Methods: Passing & Returning References of an Object",{"type":8,"value":10606,"toc":11038},[10607,10610,10614,10629,10689,10740,10744,10756,10784,10795,10799,10802,10838,10848,10881,10885,10892,10915,10930,10933,10937,10961,10963,10994,10996,11028,11036],[11,10608,10604],{"id":10609},"methods-passing-returning-references-of-an-object",[69,10611,10613],{"id":10612},"objects-as-instance-variables-has-a","Objects as Instance Variables (Has-A)",[15,10615,10616,10617,10620,10621,10624,10625,10628],{},"A class's instance variable can itself be an object of another class — a ",[25,10618,10619],{},"has-a"," relationship. A ",[95,10622,10623],{},"Subsystem"," might have a ",[95,10626,10627],{},"MotorConfig"," (its tuning settings) as an instance variable:",[104,10630,10632],{"className":106,"code":10631,"language":108,"meta":48,"style":48},"class MotorConfig\n{\n    private double rampRate;\n    private int currentLimit;\n    \u002F\u002F constructor, getters, setters not shown\n}\n\nclass Subsystem\n{\n    private String name;\n    private MotorConfig config; \u002F\u002F instance variable of type MotorConfig\n}\n",[95,10633,10634,10639,10643,10648,10653,10658,10662,10666,10671,10675,10680,10685],{"__ignoreMap":48},[112,10635,10636],{"class":114,"line":115},[112,10637,10638],{},"class MotorConfig\n",[112,10640,10641],{"class":114,"line":49},[112,10642,123],{},[112,10644,10645],{"class":114,"line":126},[112,10646,10647],{},"    private double rampRate;\n",[112,10649,10650],{"class":114,"line":132},[112,10651,10652],{},"    private int currentLimit;\n",[112,10654,10655],{"class":114,"line":138},[112,10656,10657],{},"    \u002F\u002F constructor, getters, setters not shown\n",[112,10659,10660],{"class":114,"line":144},[112,10661,153],{},[112,10663,10664],{"class":114,"line":150},[112,10665,907],{"emptyLinePlaceholder":55},[112,10667,10668],{"class":114,"line":2276},[112,10669,10670],{},"class Subsystem\n",[112,10672,10673],{"class":114,"line":2282},[112,10674,123],{},[112,10676,10677],{"class":114,"line":2288},[112,10678,10679],{},"    private String name;\n",[112,10681,10682],{"class":114,"line":5760},[112,10683,10684],{},"    private MotorConfig config; \u002F\u002F instance variable of type MotorConfig\n",[112,10686,10687],{"class":114,"line":5766},[112,10688,153],{},[10690,10691,10692],"blockquote",{},[15,10693,10694,3708,10699,10702,10703,537,10705,10707,10708,10710,10711,10713,10714,10716,10717,10719,10720,10723,10724,10726,10727,10729,10730,10733,10734,10736,10737,10739],{},[25,10695,5160,10696,10698],{},[95,10697,175],{}," class per file.",[95,10700,10701],{},".java"," file can hold several classes (like ",[95,10704,10627],{},[95,10706,10623],{}," above), but at most one of them can be ",[95,10709,175],{},", and (with a normal ",[95,10712,190],{}," compile) a ",[95,10715,175],{}," class's name must match the file name exactly (",[95,10718,10623],{}," must live in ",[95,10721,10722],{},"Subsystem.java",") — that's a compile error otherwise, not just a style rule. A class with no modifier at all (like both shown here) is fine too — see 7.4 for what that means for access. When a file has a ",[95,10725,101],{}," method, put the class containing it ",[25,10728,4161],{}," in the file: running it directly with ",[95,10731,10732],{},"java File.java"," (no separate compile step, 1.2) runs the ",[494,10735,4161],{}," class's ",[95,10738,101],{},", not necessarily the one matching the file name — true on both Java 25 and Java 17, so this one rule covers both.",[69,10741,10743],{"id":10742},"call-by-value-for-object-references","Call by Value, for Object References",[15,10745,10746,10747,10749,10750,10752,10753,10755],{},"Java always uses call by value — but for an object, the ",[494,10748,4024],{}," being copied is the reference (the pointer to the object), not the object itself. Passing a ",[95,10751,10627],{}," into a method copies the reference — the parameter and the argument then both point at the ",[494,10754,3485],{}," object.",[104,10757,10759],{"className":106,"code":10758,"language":108,"meta":48,"style":48},"public Subsystem(String initName, MotorConfig initConfig)\n{\n    name = initName;\n    config = initConfig; \u002F\u002F stores the SAME reference the caller passed in\n}\n",[95,10760,10761,10766,10770,10775,10780],{"__ignoreMap":48},[112,10762,10763],{"class":114,"line":115},[112,10764,10765],{},"public Subsystem(String initName, MotorConfig initConfig)\n",[112,10767,10768],{"class":114,"line":49},[112,10769,123],{},[112,10771,10772],{"class":114,"line":126},[112,10773,10774],{},"    name = initName;\n",[112,10776,10777],{"class":114,"line":132},[112,10778,10779],{},"    config = initConfig; \u002F\u002F stores the SAME reference the caller passed in\n",[112,10781,10782],{"class":114,"line":138},[112,10783,153],{},[15,10785,7566,10786,10788,10789,10791,10792,10794],{},[95,10787,10627],{}," is mutable (has setters), this matters a lot: whoever else holds a reference to that same ",[95,10790,10627],{}," object can change it, and the ",[95,10793,10623],{}," sees the change too — because it's not a separate copy, it's the same object viewed from two places.",[69,10796,10798],{"id":10797},"defensive-copying","Defensive Copying",[15,10800,10801],{},"If you don't want outside code to be able to reach in and change your object's data after the fact, make a copy instead of storing the reference you were handed:",[104,10803,10805],{"className":106,"code":10804,"language":108,"meta":48,"style":48},"public Subsystem(String initName, MotorConfig initConfig)\n{\n    name = initName;\n    \u002F\u002F Defensive copy — a brand new MotorConfig with the same values,\n    \u002F\u002F not the same object\n    config = new MotorConfig(initConfig.getRampRate(), initConfig.getCurrentLimit());\n}\n",[95,10806,10807,10811,10815,10819,10824,10829,10834],{"__ignoreMap":48},[112,10808,10809],{"class":114,"line":115},[112,10810,10765],{},[112,10812,10813],{"class":114,"line":49},[112,10814,123],{},[112,10816,10817],{"class":114,"line":126},[112,10818,10774],{},[112,10820,10821],{"class":114,"line":132},[112,10822,10823],{},"    \u002F\u002F Defensive copy — a brand new MotorConfig with the same values,\n",[112,10825,10826],{"class":114,"line":138},[112,10827,10828],{},"    \u002F\u002F not the same object\n",[112,10830,10831],{"class":114,"line":144},[112,10832,10833],{},"    config = new MotorConfig(initConfig.getRampRate(), initConfig.getCurrentLimit());\n",[112,10835,10836],{"class":114,"line":150},[112,10837,153],{},[15,10839,10840,10841,10844,10845,10847],{},"Now changing the original ",[95,10842,10843],{},"initConfig"," object afterward has zero effect on ",[95,10846,10623],{},"'s own copy.",[15,10849,10850,10851,10853,10854,10856,10857,10859,10860,10863,10864,10866,10867,10869,10870,6474,10873,9065,10875,10877,10878,10880],{},"Notice ",[95,10852,9621],{}," (a ",[95,10855,361],{},") needed no defensive copy above — ",[95,10858,361],{}," is immutable (Ch.6), so there's no \"reaching in and changing it later\" to defend against; only a ",[494,10861,10862],{},"mutable"," object reference (like ",[95,10865,10627],{},", which has setters) needs one. Also watch for a ",[95,10868,4645],{}," argument: ",[95,10871,10872],{},"initConfig.getRampRate()",[95,10874,4678],{},[95,10876,10843],{}," itself is ",[95,10879,4645],{}," — a defensive copy still has to handle (or explicitly rule out) that case.",[69,10882,10884],{"id":10883},"returning-an-object-reference","Returning an Object Reference",[15,10886,10887,10888,10891],{},"The same rule applies in reverse: a method that returns an object returns a reference to the ",[494,10889,10890],{},"real"," object, not a copy. If that object is mutable, whoever calls the getter can reach in and change it:",[104,10893,10895],{"className":106,"code":10894,"language":108,"meta":48,"style":48},"public MotorConfig getConfig()\n{\n    return config; \u002F\u002F returns the SAME object — caller can mutate it!\n}\n",[95,10896,10897,10902,10906,10911],{"__ignoreMap":48},[112,10898,10899],{"class":114,"line":115},[112,10900,10901],{},"public MotorConfig getConfig()\n",[112,10903,10904],{"class":114,"line":49},[112,10905,123],{},[112,10907,10908],{"class":114,"line":126},[112,10909,10910],{},"    return config; \u002F\u002F returns the SAME object — caller can mutate it!\n",[112,10912,10913],{"class":114,"line":132},[112,10914,153],{},[104,10916,10918],{"className":106,"code":10917,"language":108,"meta":48,"style":48},"MotorConfig c = subsystem.getConfig();\nc.setRampRate(0.5); \u002F\u002F this actually changes subsystem's real config!\n",[95,10919,10920,10925],{"__ignoreMap":48},[112,10921,10922],{"class":114,"line":115},[112,10923,10924],{},"MotorConfig c = subsystem.getConfig();\n",[112,10926,10927],{"class":114,"line":49},[112,10928,10929],{},"c.setRampRate(0.5); \u002F\u002F this actually changes subsystem's real config!\n",[15,10931,10932],{},"If that's not what you want, return a defensive copy from the getter too.",[69,10934,10936],{"id":10935},"chaining-method-calls","Chaining Method Calls",[15,10938,10939,10940,10943,10944,10947,10948,10951,10952,325,10954,10956,10957,10960],{},"Calling a method directly on another method's return value — ",[95,10941,10942],{},"subsystem.getConfig().getRampRate()"," — is called chaining. It only compiles if the first call's ",[494,10945,10946],{},"declared return type"," actually has the second method — ",[95,10949,10950],{},"getConfig()","'s return type is ",[95,10953,10627],{},[95,10955,10627],{}," has a ",[95,10958,10959],{},"getRampRate()",", so the chain is valid; the compiler checks this, not the programmer.",[69,10962,462],{"id":461},[19,10964,10965,10971,10977],{},[22,10966,10967,10970],{},[25,10968,10969],{},"Assuming storing a passed-in object automatically makes an independent copy."," It doesn't — only the reference is copied, so the stored object is the exact same one the caller still has.",[22,10972,10973,10976],{},[25,10974,10975],{},"Returning a mutable instance variable directly from a getter."," This hands the caller a live reference to your object's actual internal state — they can change it without going through any of your class's own methods.",[22,10978,10979,476,10982,10985,10986,10989,10990,10993],{},[25,10980,10981],{},"Chaining calls without checking each return type.",[95,10983,10984],{},"a.getX().getY()"," only compiles if ",[95,10987,10988],{},"getX()","'s return type actually has a ",[95,10991,10992],{},"getY()"," method.",[69,10995,501],{"id":500},[19,10997,10998,11001,11007,11010,11016],{},[22,10999,11000],{},"An object can be another object's instance variable — a \"has-a\" relationship.",[22,11002,11003,11004,11006],{},"Passing or returning an object copies its ",[494,11005,1475],{},", not the object itself — both sides then point at the same object.",[22,11008,11009],{},"If the object is mutable and you don't want outside code able to change it later, make a defensive copy — on the way in (constructor\u002Fsetter) and\u002For on the way out (getter).",[22,11011,11012,11013,11015],{},"Chaining method calls (",[95,11014,10984],{},") compiles only if each call's declared return type actually has the next method in the chain.",[22,11017,11018,11019,11021,11022,11024,11025,11027],{},"A file can hold several classes but only one ",[95,11020,175],{}," one; put the class with ",[95,11023,101],{}," first so ",[95,11026,10732],{}," runs it, on both Java 25 and Java 17.",[15,11029,544,11030,548,11032,11035],{},[95,11031,547],{},[95,11033,11034],{},"unit-3-class-creation\u002F3.06-methods-passing-and-returning-references-of-an-object.md"," (CSA 3.6)",[554,11037,556],{},{"title":48,"searchDepth":49,"depth":49,"links":11039},[11040,11041,11042,11043,11044,11045,11046],{"id":10612,"depth":49,"text":10613},{"id":10742,"depth":49,"text":10743},{"id":10797,"depth":49,"text":10798},{"id":10883,"depth":49,"text":10884},{"id":10935,"depth":49,"text":10936},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":11048,"status":570},"7.3 — Methods: Passing\u002FReturning References of an Object (CSA 3.6)","\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F3-methods-passing-and-returning-references-of-an-object",{"title":10604,"description":48},"shockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.3-methods-passing-and-returning-references-of-an-object","hw1wxncdiWxKfw0EVC3lylRKbhmw3nxoSbMZ8OoFCHc",{"id":11054,"title":11055,"body":11056,"description":48,"extension":51,"meta":11458,"navigation":55,"path":11460,"seo":11461,"stem":11462,"__hash__":11463},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.4-class-static-variables-and-methods.md","Class (static) Variables & Methods",{"type":8,"value":11057,"toc":11449},[11058,11061,11065,11077,11137,11158,11162,11169,11213,11216,11249,11253,11258,11322,11325,11331,11336,11345,11351,11362,11390,11392,11406,11408,11439,11447],[11,11059,11055],{"id":11060},"class-static-variables-methods",[69,11062,11064],{"id":11063},"class-methods-belong-to-the-class-not-an-object","Class Methods Belong to the Class, Not an Object",[15,11066,405,11067,11069,11070,11072,11073,11076],{},[95,11068,179],{}," method or variable belongs to the class itself — there's exactly one shared copy, no matter how many objects (or zero objects) exist. ",[95,11071,4086],{}," is the example you already know: you never make a ",[95,11074,11075],{},"new Math()"," first.",[104,11078,11080],{"className":106,"code":11079,"language":108,"meta":48,"style":48},"public class Subsystem\n{\n    public static int instanceCount = 0; \u002F\u002F one shared copy for ALL Subsystem objects\n    \u002F\u002F (kept public here for brevity, so the examples below can read\u002Fwrite it directly —\n    \u002F\u002F in real code a static field is usually private, with a static getter, same as an\n    \u002F\u002F instance field, Ch.7.2)\n\n    public Subsystem()\n    {\n        instanceCount++; \u002F\u002F every constructor call increments the ONE shared counter\n    }\n}\n",[95,11081,11082,11087,11091,11096,11101,11106,11111,11115,11120,11124,11129,11133],{"__ignoreMap":48},[112,11083,11084],{"class":114,"line":115},[112,11085,11086],{},"public class Subsystem\n",[112,11088,11089],{"class":114,"line":49},[112,11090,123],{},[112,11092,11093],{"class":114,"line":126},[112,11094,11095],{},"    public static int instanceCount = 0; \u002F\u002F one shared copy for ALL Subsystem objects\n",[112,11097,11098],{"class":114,"line":132},[112,11099,11100],{},"    \u002F\u002F (kept public here for brevity, so the examples below can read\u002Fwrite it directly —\n",[112,11102,11103],{"class":114,"line":138},[112,11104,11105],{},"    \u002F\u002F in real code a static field is usually private, with a static getter, same as an\n",[112,11107,11108],{"class":114,"line":144},[112,11109,11110],{},"    \u002F\u002F instance field, Ch.7.2)\n",[112,11112,11113],{"class":114,"line":150},[112,11114,907],{"emptyLinePlaceholder":55},[112,11116,11117],{"class":114,"line":2276},[112,11118,11119],{},"    public Subsystem()\n",[112,11121,11122],{"class":114,"line":2282},[112,11123,135],{},[112,11125,11126],{"class":114,"line":2288},[112,11127,11128],{},"        instanceCount++; \u002F\u002F every constructor call increments the ONE shared counter\n",[112,11130,11131],{"class":114,"line":5760},[112,11132,147],{},[112,11134,11135],{"class":114,"line":5766},[112,11136,153],{},[15,11138,11139,11140,11142,11143,11146,11147,959,11150,11153,11154,11157],{},"Read or write a ",[95,11141,179],{}," member through the ",[25,11144,11145],{},"class name",", not through an object — ",[95,11148,11149],{},"Subsystem.instanceCount",[95,11151,11152],{},"someSubsystem.instanceCount",". Accessing it through an object variable actually compiles (Java allows it), but it's misleading: it reads as if each object had its own ",[95,11155,11156],{},"instanceCount",", when there's really only ever the one, shared copy.",[69,11159,11161],{"id":11160},"static-code-cant-touch-instance-data-directly","Static Code Can't Touch Instance Data Directly",[15,11163,11164,11165,11168],{},"A static method can access other static members freely, but it ",[494,11166,11167],{},"cannot"," reach an instance variable or call an instance method — because static code runs without any particular object in hand, and instance data only exists per-object.",[104,11170,11172],{"className":106,"code":11171,"language":108,"meta":48,"style":48},"public class Subsystem\n{\n    private double currentSpeed; \u002F\u002F instance variable — belongs to ONE object\n\n    public static void printStatic()\n    {\n        System.out.println(currentSpeed); \u002F\u002F compile error! no object to read this from\n    }\n}\n",[95,11173,11174,11178,11182,11187,11191,11196,11200,11205,11209],{"__ignoreMap":48},[112,11175,11176],{"class":114,"line":115},[112,11177,11086],{},[112,11179,11180],{"class":114,"line":49},[112,11181,123],{},[112,11183,11184],{"class":114,"line":126},[112,11185,11186],{},"    private double currentSpeed; \u002F\u002F instance variable — belongs to ONE object\n",[112,11188,11189],{"class":114,"line":132},[112,11190,907],{"emptyLinePlaceholder":55},[112,11192,11193],{"class":114,"line":138},[112,11194,11195],{},"    public static void printStatic()\n",[112,11197,11198],{"class":114,"line":144},[112,11199,135],{},[112,11201,11202],{"class":114,"line":150},[112,11203,11204],{},"        System.out.println(currentSpeed); \u002F\u002F compile error! no object to read this from\n",[112,11206,11207],{"class":114,"line":2276},[112,11208,147],{},[112,11210,11211],{"class":114,"line":2282},[112,11212,153],{},[15,11214,11215],{},"The fix, if a static method genuinely needs instance data, is to pass in an actual object as a parameter:",[104,11217,11219],{"className":106,"code":11218,"language":108,"meta":48,"style":48},"\u002F\u002F inside Subsystem — private access to another Subsystem's field is allowed\n\u002F\u002F here because it's still the same class, just a different object (Ch.7.1)\npublic static void printSpeed(Subsystem s)\n{\n    System.out.println(s.currentSpeed); \u002F\u002F fine — reading a specific object's data\n}\n",[95,11220,11221,11226,11231,11236,11240,11245],{"__ignoreMap":48},[112,11222,11223],{"class":114,"line":115},[112,11224,11225],{},"\u002F\u002F inside Subsystem — private access to another Subsystem's field is allowed\n",[112,11227,11228],{"class":114,"line":49},[112,11229,11230],{},"\u002F\u002F here because it's still the same class, just a different object (Ch.7.1)\n",[112,11232,11233],{"class":114,"line":126},[112,11234,11235],{},"public static void printSpeed(Subsystem s)\n",[112,11237,11238],{"class":114,"line":132},[112,11239,123],{},[112,11241,11242],{"class":114,"line":138},[112,11243,11244],{},"    System.out.println(s.currentSpeed); \u002F\u002F fine — reading a specific object's data\n",[112,11246,11247],{"class":114,"line":144},[112,11248,153],{},[69,11250,11252],{"id":11251},"class-variables-one-shared-copy","Class Variables: One Shared Copy",[15,11254,405,11255,11257],{},[95,11256,179],{}," variable is shared by every object of the class — changing it from one object's constructor or method affects what every other object sees, since there's only ever one copy.",[104,11259,11261],{"className":106,"code":11260,"language":108,"meta":48,"style":48},"public class Subsystem\n{\n    \u002F\u002F public for brevity here too — see the note above\n    public static double maxObservedCurrent = 0;\n\n    public Subsystem(double current)\n    {\n        if (current > maxObservedCurrent)\n        {\n            maxObservedCurrent = current; \u002F\u002F updates the ONE shared value\n        }\n    }\n}\n",[95,11262,11263,11267,11271,11276,11281,11285,11290,11294,11299,11304,11309,11314,11318],{"__ignoreMap":48},[112,11264,11265],{"class":114,"line":115},[112,11266,11086],{},[112,11268,11269],{"class":114,"line":49},[112,11270,123],{},[112,11272,11273],{"class":114,"line":126},[112,11274,11275],{},"    \u002F\u002F public for brevity here too — see the note above\n",[112,11277,11278],{"class":114,"line":132},[112,11279,11280],{},"    public static double maxObservedCurrent = 0;\n",[112,11282,11283],{"class":114,"line":138},[112,11284,907],{"emptyLinePlaceholder":55},[112,11286,11287],{"class":114,"line":144},[112,11288,11289],{},"    public Subsystem(double current)\n",[112,11291,11292],{"class":114,"line":150},[112,11293,135],{},[112,11295,11296],{"class":114,"line":2276},[112,11297,11298],{},"        if (current > maxObservedCurrent)\n",[112,11300,11301],{"class":114,"line":2282},[112,11302,11303],{},"        {\n",[112,11305,11306],{"class":114,"line":2288},[112,11307,11308],{},"            maxObservedCurrent = current; \u002F\u002F updates the ONE shared value\n",[112,11310,11311],{"class":114,"line":5760},[112,11312,11313],{},"        }\n",[112,11315,11316],{"class":114,"line":5766},[112,11317,147],{},[112,11319,11320],{"class":114,"line":5772},[112,11321,153],{},[15,11323,11324],{},"This is a genuinely common real use: tracking a running maximum, minimum, or count across every object ever created from a class.",[69,11326,11328,11330],{"id":11327},"final-for-constants",[95,11329,381],{}," for Constants",[15,11332,11333,11335],{},[95,11334,381],{}," makes a variable's value unchangeable after it's set — used for true constants, conventionally named in all caps:",[104,11337,11339],{"className":106,"code":11338,"language":108,"meta":48,"style":48},"public static final double MAX_SPEED = 1.0;\n",[95,11340,11341],{"__ignoreMap":48},[112,11342,11343],{"class":114,"line":115},[112,11344,11338],{},[15,11346,11347,11348,11350],{},"Trying to reassign a ",[95,11349,381],{}," variable later is a compile error.",[15,11352,11353,11354,11357,11358,11361],{},"A common pattern: gather a class's constants into their own class, so other code reads them as ",[95,11355,11356],{},"Constants.MAX_SPEED"," instead of scattering ",[95,11359,11360],{},"public static final"," fields across whatever class happens to use them first:",[104,11363,11365],{"className":106,"code":11364,"language":108,"meta":48,"style":48},"public class Constants\n{\n    public static final double MAX_SPEED = 1.0;\n    public static final int MAX_CURRENT_AMPS = 40;\n}\n",[95,11366,11367,11372,11376,11381,11386],{"__ignoreMap":48},[112,11368,11369],{"class":114,"line":115},[112,11370,11371],{},"public class Constants\n",[112,11373,11374],{"class":114,"line":49},[112,11375,123],{},[112,11377,11378],{"class":114,"line":126},[112,11379,11380],{},"    public static final double MAX_SPEED = 1.0;\n",[112,11382,11383],{"class":114,"line":132},[112,11384,11385],{},"    public static final int MAX_CURRENT_AMPS = 40;\n",[112,11387,11388],{"class":114,"line":138},[112,11389,153],{},[69,11391,462],{"id":461},[19,11393,11394,11400],{},[22,11395,11396,11399],{},[25,11397,11398],{},"Trying to read an instance variable from a static method."," It doesn't compile — static code has no specific object to read from, unless one is explicitly passed in as a parameter.",[22,11401,11402,11405],{},[25,11403,11404],{},"Expecting a static variable to have a separate copy per object."," It doesn't — there's exactly one, shared by everything, which is precisely what makes it useful for things like a running count or max.",[69,11407,501],{"id":500},[19,11409,11410,11415,11418,11421,11430],{},[22,11411,11412,11414],{},[95,11413,179],{}," members belong to the class itself — one shared copy, independent of how many objects exist.",[22,11416,11417],{},"Static code cannot access instance variables or instance methods directly — it needs an actual object passed in to do that.",[22,11419,11420],{},"A static variable's value is shared across every object of the class — useful for running totals, counts, or maximums.",[22,11422,11423,11424,11426,11427,11429],{},"Access a ",[95,11425,179],{}," member through the class name (",[95,11428,11149],{},"), not through an object — an object reference compiles but is misleading.",[22,11431,11432,11434,11435,11438],{},[95,11433,381],{}," marks a variable as an unchangeable constant, conventionally named in ALL_CAPS; a dedicated ",[95,11436,11437],{},"Constants"," class is a common place to collect them.",[15,11440,544,11441,548,11443,11446],{},[95,11442,547],{},[95,11444,11445],{},"unit-3-class-creation\u002F3.07-class-static-variables-and-methods.md"," (CSA 3.7)",[554,11448,556],{},{"title":48,"searchDepth":49,"depth":49,"links":11450},[11451,11452,11453,11454,11456,11457],{"id":11063,"depth":49,"text":11064},{"id":11160,"depth":49,"text":11161},{"id":11251,"depth":49,"text":11252},{"id":11327,"depth":49,"text":11455},"final for Constants",{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":11459,"status":570},"7.4 — Class (static) Variables and Methods (CSA 3.7)","\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F4-class-static-variables-and-methods",{"title":11055,"description":48},"shockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.4-class-static-variables-and-methods","FBg9JNIuNrVu-Sfllb2UNUs2jrEGCM4ILwh1mUSIijU",{"id":11465,"title":11466,"body":11467,"description":48,"extension":51,"meta":11984,"navigation":55,"path":11986,"seo":11987,"stem":11988,"__hash__":11989},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch08-constructors-and-this\u002F8.1-8.2-constructors-and-this.md","Constructors & \"this\"",{"type":8,"value":11468,"toc":11971},[11469,11472,11476,11486,11531,11535,11553,11575,11579,11585,11663,11670,11684,11754,11770,11776,11793,11816,11825,11836,11842,11847,11891,11893,11934,11936,11962,11969],[11,11470,11466],{"id":11471},"constructors-this",[69,11473,11475],{"id":11474},"a-constructors-job","A Constructor's Job",[15,11477,11478,11479,11482,11483,11485],{},"A constructor's only job is to put a new object into a ",[25,11480,11481],{},"valid state"," — every instance variable set to something usable. Its signature looks like a method's, but with two differences: no return type (not even ",[95,11484,183],{},"), and its name is always exactly the class's name.",[104,11487,11489],{"className":106,"code":11488,"language":108,"meta":48,"style":48},"public class Climber\n{\n    private int motorPort;\n\n    public Climber(int motorPort) \u002F\u002F same name as the class, no return type\n    {\n        this.motorPort = motorPort;\n    }\n}\n",[95,11490,11491,11496,11500,11505,11509,11514,11518,11523,11527],{"__ignoreMap":48},[112,11492,11493],{"class":114,"line":115},[112,11494,11495],{},"public class Climber\n",[112,11497,11498],{"class":114,"line":49},[112,11499,123],{},[112,11501,11502],{"class":114,"line":126},[112,11503,11504],{},"    private int motorPort;\n",[112,11506,11507],{"class":114,"line":132},[112,11508,907],{"emptyLinePlaceholder":55},[112,11510,11511],{"class":114,"line":138},[112,11512,11513],{},"    public Climber(int motorPort) \u002F\u002F same name as the class, no return type\n",[112,11515,11516],{"class":114,"line":144},[112,11517,135],{},[112,11519,11520],{"class":114,"line":150},[112,11521,11522],{},"        this.motorPort = motorPort;\n",[112,11524,11525],{"class":114,"line":2276},[112,11526,147],{},[112,11528,11529],{"class":114,"line":2282},[112,11530,153],{},[69,11532,11534],{"id":11533},"the-default-constructor","The Default Constructor",[15,11536,11537,11538,199,11540,322,11542,199,11544,322,11546,199,11548,322,11550,11552],{},"Every instance variable starts at its type's default the instant an object exists — ",[95,11539,1365],{},[95,11541,603],{},[95,11543,1369],{},[95,11545,631],{},[95,11547,664],{},[95,11549,657],{},[95,11551,4645],{}," for any reference type — whether or not you ever write a constructor. If you don't write any constructor at all, Java adds an empty no-argument one for you; it doesn't do anything beyond that automatic default-initialization. The moment you write even one constructor yourself, that free one disappears — you have to cover every way you want objects of your class to be built.",[104,11554,11556],{"className":106,"code":11555,"language":108,"meta":48,"style":48},"public class Climber\n{\n    private int motorPort; \u002F\u002F if no constructor is written, this defaults to 0\n}\n",[95,11557,11558,11562,11566,11571],{"__ignoreMap":48},[112,11559,11560],{"class":114,"line":115},[112,11561,11495],{},[112,11563,11564],{"class":114,"line":49},[112,11565,123],{},[112,11567,11568],{"class":114,"line":126},[112,11569,11570],{},"    private int motorPort; \u002F\u002F if no constructor is written, this defaults to 0\n",[112,11572,11573],{"class":114,"line":132},[112,11574,153],{},[69,11576,11578],{"id":11577},"overloaded-constructors","Overloaded Constructors",[15,11580,11581,11582,11584],{},"Just like methods (Ch.4.1), a class can have several constructors, distinguished by their parameter lists — this is the same ",[25,11583,3420],{}," concept:",[104,11586,11588],{"className":106,"code":11587,"language":108,"meta":48,"style":48},"public class Climber\n{\n    private int motorPort;\n    private double climbSpeed;\n\n    public Climber(int motorPort)\n    {\n        this.motorPort = motorPort;\n        this.climbSpeed = 0.5; \u002F\u002F a sensible default\n    }\n\n    public Climber(int motorPort, double climbSpeed)\n    {\n        this.motorPort = motorPort;\n        this.climbSpeed = climbSpeed;\n    }\n}\n",[95,11589,11590,11594,11598,11602,11607,11611,11616,11620,11624,11629,11633,11637,11642,11646,11650,11655,11659],{"__ignoreMap":48},[112,11591,11592],{"class":114,"line":115},[112,11593,11495],{},[112,11595,11596],{"class":114,"line":49},[112,11597,123],{},[112,11599,11600],{"class":114,"line":126},[112,11601,11504],{},[112,11603,11604],{"class":114,"line":132},[112,11605,11606],{},"    private double climbSpeed;\n",[112,11608,11609],{"class":114,"line":138},[112,11610,907],{"emptyLinePlaceholder":55},[112,11612,11613],{"class":114,"line":144},[112,11614,11615],{},"    public Climber(int motorPort)\n",[112,11617,11618],{"class":114,"line":150},[112,11619,135],{},[112,11621,11622],{"class":114,"line":2276},[112,11623,11522],{},[112,11625,11626],{"class":114,"line":2282},[112,11627,11628],{},"        this.climbSpeed = 0.5; \u002F\u002F a sensible default\n",[112,11630,11631],{"class":114,"line":2288},[112,11632,147],{},[112,11634,11635],{"class":114,"line":5760},[112,11636,907],{"emptyLinePlaceholder":55},[112,11638,11639],{"class":114,"line":5766},[112,11640,11641],{},"    public Climber(int motorPort, double climbSpeed)\n",[112,11643,11644],{"class":114,"line":5772},[112,11645,135],{},[112,11647,11648],{"class":114,"line":5777},[112,11649,11522],{},[112,11651,11652],{"class":114,"line":5783},[112,11653,11654],{},"        this.climbSpeed = climbSpeed;\n",[112,11656,11657],{"class":114,"line":5789},[112,11658,147],{},[112,11660,11661],{"class":114,"line":5794},[112,11662,153],{},[69,11664,11666,11667],{"id":11665},"chaining-constructors-with-this","Chaining Constructors with ",[95,11668,11669],{},"this(...)",[15,11671,11672,11673,11676,11677,11680,11681,11683],{},"The two ",[95,11674,11675],{},"Climber"," constructors above duplicate the ",[95,11678,11679],{},"this.motorPort = motorPort;"," line. When one constructor's job is really \"do what another constructor does, plus a little more,\" it can call that other constructor directly with ",[95,11682,11669],{}," instead of repeating its body:",[104,11685,11687],{"className":106,"code":11686,"language":108,"meta":48,"style":48},"public class Climber\n{\n    private int motorPort;\n    private double climbSpeed;\n\n    public Climber(int motorPort)\n    {\n        this(motorPort, 0.5); \u002F\u002F delegates to the two-argument constructor below\n    }\n\n    public Climber(int motorPort, double climbSpeed)\n    {\n        this.motorPort = motorPort;\n        this.climbSpeed = climbSpeed;\n    }\n}\n",[95,11688,11689,11693,11697,11701,11705,11709,11713,11717,11722,11726,11730,11734,11738,11742,11746,11750],{"__ignoreMap":48},[112,11690,11691],{"class":114,"line":115},[112,11692,11495],{},[112,11694,11695],{"class":114,"line":49},[112,11696,123],{},[112,11698,11699],{"class":114,"line":126},[112,11700,11504],{},[112,11702,11703],{"class":114,"line":132},[112,11704,11606],{},[112,11706,11707],{"class":114,"line":138},[112,11708,907],{"emptyLinePlaceholder":55},[112,11710,11711],{"class":114,"line":144},[112,11712,11615],{},[112,11714,11715],{"class":114,"line":150},[112,11716,135],{},[112,11718,11719],{"class":114,"line":2276},[112,11720,11721],{},"        this(motorPort, 0.5); \u002F\u002F delegates to the two-argument constructor below\n",[112,11723,11724],{"class":114,"line":2282},[112,11725,147],{},[112,11727,11728],{"class":114,"line":2288},[112,11729,907],{"emptyLinePlaceholder":55},[112,11731,11732],{"class":114,"line":5760},[112,11733,11641],{},[112,11735,11736],{"class":114,"line":5766},[112,11737,135],{},[112,11739,11740],{"class":114,"line":5772},[112,11741,11522],{},[112,11743,11744],{"class":114,"line":5777},[112,11745,11654],{},[112,11747,11748],{"class":114,"line":5783},[112,11749,147],{},[112,11751,11752],{"class":114,"line":5789},[112,11753,153],{},[15,11755,11756,11757,11759,11760,11763,11764,11766,11767,11769],{},"On Java 17, a ",[95,11758,11669],{}," call must be the very first statement in the constructor — nothing can come before it, not even a simple argument check. Java 25 (JEP 513, ",[494,11761,11762],{},"Flexible Constructor Bodies",") relaxes this: statements can now run before ",[95,11765,11669],{},", as long as they don't touch the new object's fields or call its methods yet (validating an argument, for example, is fine). This lesson still puts ",[95,11768,11669],{}," first, which works unchanged on both versions.",[69,11771,11773,11775],{"id":11772},"this-referring-to-the-current-object",[95,11774,3132],{},": Referring to the Current Object",[15,11777,11778,11779,11781,11782,11785,11786,11789,11790,11792],{},"Inside an instance method or constructor, ",[95,11780,3132],{}," refers to the specific object the method\u002Fconstructor is currently running for. It's most useful when a parameter shares a name with an instance variable — ",[95,11783,11784],{},"this.motorPort"," unambiguously means \"this object's ",[95,11787,11788],{},"motorPort",",\" while bare ",[95,11791,11788],{}," means the parameter:",[104,11794,11796],{"className":106,"code":11795,"language":108,"meta":48,"style":48},"public Climber(int motorPort)\n{\n    this.motorPort = motorPort; \u002F\u002F left side: instance variable. right side: parameter.\n}\n",[95,11797,11798,11803,11807,11812],{"__ignoreMap":48},[112,11799,11800],{"class":114,"line":115},[112,11801,11802],{},"public Climber(int motorPort)\n",[112,11804,11805],{"class":114,"line":49},[112,11806,123],{},[112,11808,11809],{"class":114,"line":126},[112,11810,11811],{},"    this.motorPort = motorPort; \u002F\u002F left side: instance variable. right side: parameter.\n",[112,11813,11814],{"class":114,"line":132},[112,11815,153],{},[15,11817,11818,11819,322,11821,11824],{},"Without ",[95,11820,3132],{},[95,11822,11823],{},"motorPort = motorPort;"," would just assign the parameter to itself — the instance variable would never actually get set.",[15,11826,11827,11829,11830,11832,11833,11835],{},[95,11828,3132],{}," only exists inside instance methods and constructors — a ",[95,11831,179],{}," method has no current object to refer to, so it has no ",[95,11834,3132],{}," (Ch.7.4).",[69,11837,11839,11841],{"id":11838},"this-as-an-argument",[95,11840,3132],{}," as an Argument",[15,11843,11844,11846],{},[95,11845,3132],{}," is a real reference, usable anywhere an object reference is expected — including passing the current object into another method or constructor:",[104,11848,11850],{"className":106,"code":11849,"language":108,"meta":48,"style":48},"public class Climber\n{\n    private double currentHeight;\n\n    public void reportTo(ClimbLogger logger)\n    {\n        logger.record(this); \u002F\u002F pass the current Climber object itself\n    }\n}\n",[95,11851,11852,11856,11860,11865,11869,11874,11878,11883,11887],{"__ignoreMap":48},[112,11853,11854],{"class":114,"line":115},[112,11855,11495],{},[112,11857,11858],{"class":114,"line":49},[112,11859,123],{},[112,11861,11862],{"class":114,"line":126},[112,11863,11864],{},"    private double currentHeight;\n",[112,11866,11867],{"class":114,"line":132},[112,11868,907],{"emptyLinePlaceholder":55},[112,11870,11871],{"class":114,"line":138},[112,11872,11873],{},"    public void reportTo(ClimbLogger logger)\n",[112,11875,11876],{"class":114,"line":144},[112,11877,135],{},[112,11879,11880],{"class":114,"line":150},[112,11881,11882],{},"        logger.record(this); \u002F\u002F pass the current Climber object itself\n",[112,11884,11885],{"class":114,"line":2276},[112,11886,147],{},[112,11888,11889],{"class":114,"line":2282},[112,11890,153],{},[69,11892,462],{"id":461},[19,11894,11895,11909,11919],{},[22,11896,11897,11902,11903,11905,11906,11908],{},[25,11898,4719,11899,11901],{},[95,11900,3132],{}," when a parameter shadows an instance variable"," — the general scope\u002Flifetime rule behind this is Ch.7.2's \"Where Variables Live.\" ",[95,11904,11823],{}," (no ",[95,11907,3132],{},") does nothing useful — it assigns the parameter to itself, leaving the actual instance variable untouched.",[22,11910,11911,11914,11915,11918],{},[25,11912,11913],{},"Assuming a class always gets a free default constructor."," Only true if you write ",[494,11916,11917],{},"zero"," constructors yourself. Write even one, and you're responsible for every constructor your class needs.",[22,11920,11921,11927,11928,11930,11931,11933],{},[25,11922,6120,11923,11926],{},[95,11924,11925],{},"void Climber(...)"," instead of a constructor."," Adding a return type — even ",[95,11929,183],{}," — makes it an ordinary method that just happens to share the class's name, not a constructor. It never runs automatically when you ",[95,11932,2504],{}," the class; Java still builds the object with whichever real constructor exists (or the free default one, if you wrote none).",[69,11935,501],{"id":500},[19,11937,11938,11941,11944,11950,11955],{},[22,11939,11940],{},"A constructor's signature has no return type and always matches the class's name; its job is to leave the object in a valid state.",[22,11942,11943],{},"Every instance variable starts at its type's default regardless of any constructor; with no constructor written, Java adds an empty default one — writing any constructor yourself removes it.",[22,11945,11946,11947,11949],{},"Constructors can be overloaded, just like methods, distinguished by parameter lists; one overload can delegate to another with ",[95,11948,11669],{}," instead of repeating setup code (first statement on Java 17; Java 25 also allows validation before it, JEP 513).",[22,11951,11952,11954],{},[95,11953,3132],{}," refers to the current object inside an instance method or constructor — essential for disambiguating a parameter from an instance variable of the same name (shadowing, Ch.7.2).",[22,11956,11957,11959,11960,79],{},[95,11958,3132],{}," can be passed as an argument, like any other object reference. Static methods have no ",[95,11961,3132],{},[15,11963,11964,476,11966,11968],{},[25,11965,5351],{},[95,11967,5354],{},", slide 8 (\"CONSTRUCTORS\")",[554,11970,556],{},{"title":48,"searchDepth":49,"depth":49,"links":11972},[11973,11974,11975,11976,11978,11980,11982,11983],{"id":11474,"depth":49,"text":11475},{"id":11533,"depth":49,"text":11534},{"id":11577,"depth":49,"text":11578},{"id":11665,"depth":49,"text":11977},"Chaining Constructors with this(...)",{"id":11772,"depth":49,"text":11979},"this: Referring to the Current Object",{"id":11838,"depth":49,"text":11981},"this as an Argument",{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":11985,"status":5368},"8.1 (Writing Constructors, CSA 3.4) + 8.2 (this Keyword, CSA 3.9) — combined","\u002Fshockwave-curriculum\u002Flessons\u002Fch08-constructors-and-this\u002F1-8.2-constructors-and-this",{"title":11466,"description":48},"shockwave-curriculum\u002Flessons\u002Fch08-constructors-and-this\u002F8.1-8.2-constructors-and-this","kptM8evpl6ma8R5WHgpaYj2WZEqh0WrM_u5lnK7nMwc",{"id":11991,"title":11992,"body":11993,"description":48,"extension":51,"meta":12317,"navigation":55,"path":12320,"seo":12321,"stem":12322,"__hash__":12323},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.1-array-creation-and-access.md","Array Creation and Access",{"type":8,"value":11994,"toc":12307},[11995,11998,12002,12018,12033,12037,12061,12067,12090,12094,12107,12127,12138,12142,12151,12171,12175,12178,12198,12202,12225,12227,12271,12273,12297,12305],[11,11996,11992],{"id":11997},"array-creation-and-access",[69,11999,12001],{"id":12000},"what-an-array-is","What an Array Is",[15,12003,12004,12005,12007,12008,322,12011,322,12014,12017],{},"An array is a fixed-size block of memory holding several values of the same type, accessed by position (",[25,12006,8860],{},") instead of by separate variable names — the fix for needing ",[95,12009,12010],{},"motor1",[95,12012,12013],{},"motor2",[95,12015,12016],{},"motor3","... variables.",[104,12019,12021],{"className":106,"code":12020,"language":108,"meta":48,"style":48},"\u002F\u002F an initializer list — size inferred, values set immediately\nint[] canBusIds = {1, 2, 3, 4};\n",[95,12022,12023,12028],{"__ignoreMap":48},[112,12024,12025],{"class":114,"line":115},[112,12026,12027],{},"\u002F\u002F an initializer list — size inferred, values set immediately\n",[112,12029,12030],{"class":114,"line":49},[112,12031,12032],{},"int[] canBusIds = {1, 2, 3, 4};\n",[69,12034,12036],{"id":12035},"two-ways-to-create-one","Two Ways to Create One",[104,12038,12040],{"className":106,"code":12039,"language":108,"meta":48,"style":48},"int[] canBusIds;              \u002F\u002F declares the variable — no array exists yet (it's null)\ncanBusIds = new int[4];       \u002F\u002F creates a 4-element array — all elements start at 0\n\nint[] canBusIds2 = {1, 2, 3, 4}; \u002F\u002F initializer list: create + fill in one step\n",[95,12041,12042,12047,12052,12056],{"__ignoreMap":48},[112,12043,12044],{"class":114,"line":115},[112,12045,12046],{},"int[] canBusIds;              \u002F\u002F declares the variable — no array exists yet (it's null)\n",[112,12048,12049],{"class":114,"line":49},[112,12050,12051],{},"canBusIds = new int[4];       \u002F\u002F creates a 4-element array — all elements start at 0\n",[112,12053,12054],{"class":114,"line":126},[112,12055,907],{"emptyLinePlaceholder":55},[112,12057,12058],{"class":114,"line":132},[112,12059,12060],{},"int[] canBusIds2 = {1, 2, 3, 4}; \u002F\u002F initializer list: create + fill in one step\n",[15,12062,12063,12064,12066],{},"An array is itself an object — a declared-but-not-yet-created array variable holds ",[95,12065,4645],{},", exactly like any other reference type.",[15,12068,12069,12070,12072,12073,199,12075,322,12077,199,12079,322,12081,199,12083,322,12085,199,12087,12089],{},"When you create an array with ",[95,12071,2504],{}," and a size, every element starts at that type's default: ",[95,12074,1365],{},[95,12076,603],{},[95,12078,1369],{},[95,12080,631],{},[95,12082,664],{},[95,12084,657],{},[95,12086,4645],{},[95,12088,361],{}," or any reference type.",[69,12091,12093],{"id":12092},"indexing","Indexing",[15,12095,12096,12097,10853,12100,12103,12104,4410],{},"Indices start at 0; the last valid index is always ",[95,12098,12099],{},"length - 1",[95,12101,12102],{},"public final int"," field, not a method — no parentheses, unlike ",[95,12105,12106],{},"String.length()",[104,12108,12110],{"className":106,"code":12109,"language":108,"meta":48,"style":48},"System.out.println(canBusIds.length); \u002F\u002F 4\ncanBusIds[0] = 5;                     \u002F\u002F assign\nSystem.out.println(canBusIds[0]);     \u002F\u002F read — prints 5\n",[95,12111,12112,12117,12122],{"__ignoreMap":48},[112,12113,12114],{"class":114,"line":115},[112,12115,12116],{},"System.out.println(canBusIds.length); \u002F\u002F 4\n",[112,12118,12119],{"class":114,"line":49},[112,12120,12121],{},"canBusIds[0] = 5;                     \u002F\u002F assign\n",[112,12123,12124],{"class":114,"line":126},[112,12125,12126],{},"System.out.println(canBusIds[0]);     \u002F\u002F read — prints 5\n",[15,12128,8883,12129,4029,12131,12133,12134,12137],{},[95,12130,1365],{},[95,12132,12099],{}," throws ",[95,12135,12136],{},"ArrayIndexOutOfBoundsException"," — one of the most common real runtime errors.",[69,12139,12141],{"id":12140},"parallel-arrays","Parallel Arrays",[15,12143,12144,12145,12147,12148,12150],{},"Two (or more) arrays, kept in the same order, where index ",[95,12146,5244],{}," in one corresponds to index ",[95,12149,5244],{}," in the other:",[104,12152,12154],{"className":106,"code":12153,"language":108,"meta":48,"style":48},"String[] autoNames = {\"3-Piece-Left\", \"1-Piece-Safe\", \"Mobility-Only\"};\n\u002F\u002F autoTimes[i] is the recorded time for autoNames[i]\ndouble[] autoTimes = {14.2, 8.5, 3.1};\n",[95,12155,12156,12161,12166],{"__ignoreMap":48},[112,12157,12158],{"class":114,"line":115},[112,12159,12160],{},"String[] autoNames = {\"3-Piece-Left\", \"1-Piece-Safe\", \"Mobility-Only\"};\n",[112,12162,12163],{"class":114,"line":49},[112,12164,12165],{},"\u002F\u002F autoTimes[i] is the recorded time for autoNames[i]\n",[112,12167,12168],{"class":114,"line":126},[112,12169,12170],{},"double[] autoTimes = {14.2, 8.5, 3.1};\n",[69,12172,12174],{"id":12173},"arrays-of-objects","Arrays of Objects",[15,12176,12177],{},"An array can hold any type, including your own classes — but each element still has to be constructed individually:",[104,12179,12181],{"className":106,"code":12180,"language":108,"meta":48,"style":48},"DriveMotor[] driveMotors = new DriveMotor[4]; \u002F\u002F 4 slots, all currently null\ndriveMotors[0] = new DriveMotor(1);           \u002F\u002F must construct each element separately\ndriveMotors[0].setThrottle(0.5);              \u002F\u002F then call methods through the index\n",[95,12182,12183,12188,12193],{"__ignoreMap":48},[112,12184,12185],{"class":114,"line":115},[112,12186,12187],{},"DriveMotor[] driveMotors = new DriveMotor[4]; \u002F\u002F 4 slots, all currently null\n",[112,12189,12190],{"class":114,"line":49},[112,12191,12192],{},"driveMotors[0] = new DriveMotor(1);           \u002F\u002F must construct each element separately\n",[112,12194,12195],{"class":114,"line":126},[112,12196,12197],{},"driveMotors[0].setThrottle(0.5);              \u002F\u002F then call methods through the index\n",[69,12199,12201],{"id":12200},"printing-an-array","Printing an Array",[15,12203,12204,12207,12208,12210,12211,8174,12214,12217,12218,12221,12222,79],{},[95,12205,12206],{},"System.out.println(canBusIds)"," doesn't print the values — arrays don't override ",[95,12209,10318],{}," (Ch.17), so it prints something unreadable like ",[95,12212,12213],{},"[I@1a2b3c",[95,12215,12216],{},"Arrays.toString(canBusIds)"," (from ",[95,12219,12220],{},"java.util.Arrays",") instead: ",[95,12223,12224],{},"System.out.println(Arrays.toString(canBusIds)); \u002F\u002F [1, 2, 3, 4]",[69,12226,462],{"id":461},[19,12228,12229,12245,12256],{},[22,12230,12231,476,12234,12237,12238,12240,12241,12244],{},[25,12232,12233],{},"Forgetting an array must be constructed, not just declared.",[95,12235,12236],{},"int[] canBusIds;"," alone is ",[95,12239,4645],{}," — you need ",[95,12242,12243],{},"new int[size]"," or an initializer list before using it.",[22,12246,12247,12250,12251,959,12253,79],{},[25,12248,12249],{},"Off-by-one on the last index."," The last valid index is ",[95,12252,12099],{},[95,12254,12255],{},"length",[22,12257,12258,476,12261,12264,12265,12267,12268,79],{},[25,12259,12260],{},"Forgetting to construct each element of an object array.",[95,12262,12263],{},"new DriveMotor[4]"," gives you 4 ",[95,12266,4645],{}," slots, not 4 ready-to-use motor objects — each one still needs its own ",[95,12269,12270],{},"new DriveMotor(...)",[69,12272,501],{"id":500},[19,12274,12275,12278,12284,12291,12294],{},[22,12276,12277],{},"An array is a fixed-size, same-type collection, accessed by a 0-based index.",[22,12279,12280,12283],{},[95,12281,12282],{},"new type[size]"," creates an array with every element at its type's default; an initializer list creates and fills it in one step.",[22,12285,12286,12288,12289,79],{},[95,12287,12255],{}," is a field (no parentheses); the last valid index is ",[95,12290,12099],{},[22,12292,12293],{},"Parallel arrays keep related data in sync by index.",[22,12295,12296],{},"An array of objects still requires constructing each element individually — the array itself doesn't build the objects for you.",[15,12298,544,12299,548,12301,12304],{},[95,12300,547],{},[95,12302,12303],{},"unit-4-data-collections\u002F4.03-array-creation-and-access.md"," (CSA 4.3)",[554,12306,556],{},{"title":48,"searchDepth":49,"depth":49,"links":12308},[12309,12310,12311,12312,12313,12314,12315,12316],{"id":12000,"depth":49,"text":12001},{"id":12035,"depth":49,"text":12036},{"id":12092,"depth":49,"text":12093},{"id":12140,"depth":49,"text":12141},{"id":12173,"depth":49,"text":12174},{"id":12200,"depth":49,"text":12201},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":12318,"status":12319},"9.1 — Array Creation and Access (CSA 4.3)","new — authored lesson (fuller depth than the teaser slide). The existing deck slide combines items 9.1-9.3 into one teaser; this Lesson covers 9.1 (Arrays) on its own, since each of the three data structures (array, ArrayList, HashMap) warrants its own full-depth treatment.","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F1-array-creation-and-access",{"title":11992,"description":48},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.1-array-creation-and-access","CVBUbrxKem0BOMrkhGYAfhffx4zp1lcvTPinvAkLEL0",{"id":12325,"title":12326,"body":12327,"description":48,"extension":51,"meta":12925,"navigation":55,"path":12928,"seo":12929,"stem":12930,"__hash__":12931},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.2-arraylist-and-its-methods.md","ArrayList and its Methods",{"type":8,"value":12328,"toc":12916},[12329,12332,12336,12345,12374,12387,12391,12405,12420,12424,12433,12489,12498,12509,12573,12577,12636,12649,12653,12730,12732,12820,12822,12906,12914],[11,12330,12326],{"id":12331},"arraylist-and-its-methods",[69,12333,12335],{"id":12334},"why-arraylist-exists","Why ArrayList Exists",[15,12337,12338,12339,12344],{},"An array's size is fixed forever once created. ",[25,12340,12341],{},[95,12342,12343],{},"ArrayList"," is Java's resizable alternative — use it whenever you don't know the final size up front, or items will be added\u002Fremoved while the program runs (a growing log of events, for instance).",[104,12346,12348],{"className":106,"code":12347,"language":108,"meta":48,"style":48},"import java.util.ArrayList;\n\n\u002F\u002F \u003C> (\"the diamond\") repeats the left side's type\nArrayList\u003CString> logs = new ArrayList\u003C>();\nlogs.add(\"Robot Initialized\");\n",[95,12349,12350,12355,12359,12364,12369],{"__ignoreMap":48},[112,12351,12352],{"class":114,"line":115},[112,12353,12354],{},"import java.util.ArrayList;\n",[112,12356,12357],{"class":114,"line":49},[112,12358,907],{"emptyLinePlaceholder":55},[112,12360,12361],{"class":114,"line":126},[112,12362,12363],{},"\u002F\u002F \u003C> (\"the diamond\") repeats the left side's type\n",[112,12365,12366],{"class":114,"line":132},[112,12367,12368],{},"ArrayList\u003CString> logs = new ArrayList\u003C>();\n",[112,12370,12371],{"class":114,"line":138},[112,12372,12373],{},"logs.add(\"Robot Initialized\");\n",[15,12375,2424,12376,12379,12380,12382,12383,12386],{},[95,12377,12378],{},"\u003C>"," on the right doesn't need to spell out ",[95,12381,361],{}," again — Java infers it from the declared type on the left. ",[95,12384,12385],{},"new ArrayList\u003CString>()"," still works too; the diamond form is what you'll see in real code.",[69,12388,12390],{"id":12389},"the-type-parameter","The Type Parameter",[15,12392,12393,12396,12397,12399,12400,176,12402,12404],{},[95,12394,12395],{},"ArrayList\u003CType>"," — the type in angle brackets is what kind of object the list holds. ",[95,12398,12343],{}," can only hold objects, never primitives directly — a list of numbers uses a wrapper type like ",[95,12401,1869],{},[95,12403,8536],{}," (Java auto-converts back and forth, called autoboxing\u002Funboxing):",[104,12406,12408],{"className":106,"code":12407,"language":108,"meta":48,"style":48},"ArrayList\u003CDouble> sensorReadings = new ArrayList\u003C>();\nsensorReadings.add(2.4); \u002F\u002F autoboxed into a Double automatically\n",[95,12409,12410,12415],{"__ignoreMap":48},[112,12411,12412],{"class":114,"line":115},[112,12413,12414],{},"ArrayList\u003CDouble> sensorReadings = new ArrayList\u003C>();\n",[112,12416,12417],{"class":114,"line":49},[112,12418,12419],{},"sensorReadings.add(2.4); \u002F\u002F autoboxed into a Double automatically\n",[69,12421,12423],{"id":12422},"wrapper-classes","Wrapper Classes",[15,12425,12426,12427,12430,12431,738],{},"Every primitive type has a matching ",[25,12428,12429],{},"wrapper class"," — an object version of that value, which is what makes it usable inside an ",[95,12432,12343],{},[3819,12434,12435,12445],{},[3822,12436,12437],{},[3825,12438,12439,12442],{},[3828,12440,12441],{},"Primitive",[3828,12443,12444],{},"Wrapper",[3838,12446,12447,12457,12467,12478],{},[3825,12448,12449,12453],{},[3843,12450,12451],{},[95,12452,603],{},[3843,12454,12455],{},[95,12456,1869],{},[3825,12458,12459,12463],{},[3843,12460,12461],{},[95,12462,631],{},[3843,12464,12465],{},[95,12466,8536],{},[3825,12468,12469,12473],{},[3843,12470,12471],{},[95,12472,657],{},[3843,12474,12475],{},[95,12476,12477],{},"Boolean",[3825,12479,12480,12484],{},[3843,12481,12482],{},[95,12483,686],{},[3843,12485,12486],{},[95,12487,12488],{},"Character",[104,12490,12492],{"className":106,"code":12491,"language":108,"meta":48,"style":48},"double first = sensorReadings.get(0); \u002F\u002F unboxed back into a double automatically\n",[95,12493,12494],{"__ignoreMap":48},[112,12495,12496],{"class":114,"line":115},[112,12497,12491],{},[15,12499,12500,12501,12504,12505,12508],{},"Java converts back and forth automatically — ",[25,12502,12503],{},"autoboxing"," (primitive → wrapper) and ",[25,12506,12507],{},"unboxing"," (wrapper → primitive). Three things worth knowing before they bite:",[19,12510,12511,12528,12551],{},[22,12512,12513,12520,12521,12524,12525,12527],{},[25,12514,12515,12516,12133,12518,79],{},"Unboxing a ",[95,12517,4645],{},[95,12519,4678],{}," A wrapper variable (or an ",[95,12522,12523],{},"ArrayList\u003CInteger>"," slot) can hold ",[95,12526,4645],{},"; the instant Java tries to unbox it into a primitive, it crashes — this is exactly what a \"missing key\" bug in Lesson 9.3 looks like.",[22,12529,12530,12538,12539,12541,12542,12544,12545,12547,12548,12550],{},[25,12531,12532,12534,12535,12537],{},[95,12533,1921],{}," on ",[95,12536,1869],{}," is unreliable."," Like any object, ",[95,12540,1921],{}," checks identity, not value — except Java happens to cache small ",[95,12543,1869],{}," values (-128 to 127), so ",[95,12546,1921],{}," can look like it \"works\" for small numbers and silently fail for larger ones. Use ",[95,12549,7836],{}," for wrapper objects, same as any other object.",[22,12552,12553,476,12563,537,12566,12569,12570,12572],{},[25,12554,12555,12556,176,12559,12562],{},"Turning text into a number needs ",[95,12557,12558],{},"parseInt",[95,12560,12561],{},"parseDouble",", not autoboxing.",[95,12564,12565],{},"Integer.parseInt(\"42\")",[95,12567,12568],{},"Double.parseDouble(\"3.14\")"," convert ",[494,12571,6629],{}," (e.g. a field split from a CSV line, Ch.9.8) into a primitive — a separate conversion from autoboxing, which only ever converts between a primitive and its own wrapper.",[69,12574,12576],{"id":12575},"core-methods","Core Methods",[104,12578,12580],{"className":106,"code":12579,"language":108,"meta":48,"style":48},"ArrayList\u003CString> logs = new ArrayList\u003C>();\nlogs.size();             \u002F\u002F number of elements (like length, but a method — () required)\nlogs.add(\"started\");     \u002F\u002F appends to the end\nlogs.add(0, \"boot\");     \u002F\u002F inserts at index 0, shifting everything else right\nlogs.get(0);              \u002F\u002F reads the element at index 0\nlogs.set(0, \"ready\");     \u002F\u002F replaces the element at index 0\nlogs.remove(0);           \u002F\u002F removes BY INDEX — the element at index 0\nlogs.remove(\"ready\");     \u002F\u002F removes BY VALUE — the first element .equals(\"ready\")\nlogs.contains(\"ready\");   \u002F\u002F true if any element .equals(\"ready\")\nlogs.indexOf(\"ready\");    \u002F\u002F index of the first match, or -1 if not present\nlogs.isEmpty();           \u002F\u002F true if size() == 0\n",[95,12581,12582,12586,12591,12596,12601,12606,12611,12616,12621,12626,12631],{"__ignoreMap":48},[112,12583,12584],{"class":114,"line":115},[112,12585,12368],{},[112,12587,12588],{"class":114,"line":49},[112,12589,12590],{},"logs.size();             \u002F\u002F number of elements (like length, but a method — () required)\n",[112,12592,12593],{"class":114,"line":126},[112,12594,12595],{},"logs.add(\"started\");     \u002F\u002F appends to the end\n",[112,12597,12598],{"class":114,"line":132},[112,12599,12600],{},"logs.add(0, \"boot\");     \u002F\u002F inserts at index 0, shifting everything else right\n",[112,12602,12603],{"class":114,"line":138},[112,12604,12605],{},"logs.get(0);              \u002F\u002F reads the element at index 0\n",[112,12607,12608],{"class":114,"line":144},[112,12609,12610],{},"logs.set(0, \"ready\");     \u002F\u002F replaces the element at index 0\n",[112,12612,12613],{"class":114,"line":150},[112,12614,12615],{},"logs.remove(0);           \u002F\u002F removes BY INDEX — the element at index 0\n",[112,12617,12618],{"class":114,"line":2276},[112,12619,12620],{},"logs.remove(\"ready\");     \u002F\u002F removes BY VALUE — the first element .equals(\"ready\")\n",[112,12622,12623],{"class":114,"line":2282},[112,12624,12625],{},"logs.contains(\"ready\");   \u002F\u002F true if any element .equals(\"ready\")\n",[112,12627,12628],{"class":114,"line":2288},[112,12629,12630],{},"logs.indexOf(\"ready\");    \u002F\u002F index of the first match, or -1 if not present\n",[112,12632,12633],{"class":114,"line":5760},[112,12634,12635],{},"logs.isEmpty();           \u002F\u002F true if size() == 0\n",[15,12637,12638,12640,12641,176,12643,2050,12645,12648],{},[95,12639,12343],{}," uses methods (",[95,12642,4956],{},[95,12644,2531],{},[95,12646,12647],{},"[]"," — it's a real class, not a built-in language feature the way arrays are.",[69,12650,12652],{"id":12651},"array-vs-arraylist-side-by-side","Array vs. ArrayList, Side by Side",[3819,12654,12655,12667],{},[3822,12656,12657],{},[3825,12658,12659,12662,12665],{},[3828,12660,12661],{},"Operation",[3828,12663,12664],{},"array",[3828,12666,12343],{},[3838,12668,12669,12684,12699,12714],{},[3825,12670,12671,12674,12679],{},[3843,12672,12673],{},"count",[3843,12675,12676],{},[95,12677,12678],{},"arr.length",[3843,12680,12681],{},[95,12682,12683],{},"list.size()",[3825,12685,12686,12689,12694],{},[3843,12687,12688],{},"read",[3843,12690,12691],{},[95,12692,12693],{},"arr[i]",[3843,12695,12696],{},[95,12697,12698],{},"list.get(i)",[3825,12700,12701,12704,12709],{},[3843,12702,12703],{},"write",[3843,12705,12706],{},[95,12707,12708],{},"arr[i] = v;",[3843,12710,12711],{},[95,12712,12713],{},"list.set(i, v);",[3825,12715,12716,12719,12722],{},[3843,12717,12718],{},"grow\u002Fshrink",[3843,12720,12721],{},"not possible",[3843,12723,12724,176,12727],{},[95,12725,12726],{},"add",[95,12728,12729],{},"remove",[69,12731,462],{"id":461},[19,12733,12734,12748,12767,12788],{},[22,12735,12736,12741,12742,176,12745,652],{},[25,12737,6835,12738,12740],{},[95,12739,12647],{}," on an ArrayList."," It doesn't compile — always ",[95,12743,12744],{},"get(i)",[95,12746,12747],{},"set(i, v)",[22,12749,12750,12759,12760,7903,12762,12764,12765,79],{},[25,12751,12752,12753,537,12756,79],{},"Mixing up ",[95,12754,12755],{},".length",[95,12757,12758],{},".size()"," Arrays use the field ",[95,12761,12755],{},[95,12763,12343],{}," uses the method ",[95,12766,12758],{},[22,12768,12769,12774,12775,12778,12779,12782,12783,12785,12786,79],{},[25,12770,12771,12772,79],{},"Using an uninitialized ",[95,12773,12343],{}," Declaring ",[95,12776,12777],{},"ArrayList\u003CString> list;"," without ",[95,12780,12781],{},"new ArrayList\u003C>()"," leaves it ",[95,12784,4645],{}," — calling any method on it throws ",[95,12787,4678],{},[22,12789,12790,12802,12803,12805,12806,12809,12810,12813,12814,7740,12817,4410],{},[25,12791,12792,12795,12796,12798,12799,79],{},[95,12793,12794],{},"remove(30)"," on an ",[95,12797,12523],{}," doesn't remove the value ",[95,12800,12801],{},"30"," An ",[95,12804,603],{}," argument always picks the ",[95,12807,12808],{},"remove(int index)"," overload — it removes ",[494,12811,12812],{},"by position",". To remove the value, wrap it: ",[95,12815,12816],{},"remove(Integer.valueOf(30))",[95,12818,12819],{},"remove((Integer) 30)",[69,12821,501],{"id":500},[19,12823,12824,12829,12853,12859,12890],{},[22,12825,12826,12828],{},[95,12827,12343],{}," is a resizable list — use it when the size isn't known up front or will change at runtime.",[22,12830,12831,12832,12834,12835,322,12837,322,12839,322,12841,12843,12844,12133,12846,325,12848,12850,12851,4410],{},"The type parameter (",[95,12833,12395],{},") says what it holds; primitives need their wrapper type (",[95,12836,1869],{},[95,12838,8536],{},[95,12840,12477],{},[95,12842,12488],{},") — autoboxing\u002Funboxing converts automatically, but unboxing a ",[95,12845,4645],{},[95,12847,4678],{},[95,12849,1921],{}," on wrappers is unreliable (use ",[95,12852,7836],{},[22,12854,12855,12856,12858],{},"The diamond (",[95,12857,12781],{},") infers the type parameter from the declared type on the left.",[22,12860,12861,12862,322,12865,322,12868,322,12871,322,12874,322,12877,322,12880,322,12883,322,12886,322,12888,79],{},"Core methods: ",[95,12863,12864],{},"size()",[95,12866,12867],{},"add()",[95,12869,12870],{},"add(index, obj)",[95,12872,12873],{},"get(index)",[95,12875,12876],{},"set(index, obj)",[95,12878,12879],{},"remove(index)",[95,12881,12882],{},"remove(Object)",[95,12884,12885],{},"contains()",[95,12887,9376],{},[95,12889,9092],{},[22,12891,12892,12893,537,12895,7903,12897,12899,12900,537,12902,176,12904,79],{},"Arrays use ",[95,12894,12755],{},[95,12896,12647],{},[95,12898,12343],{}," uses ",[95,12901,12758],{},[95,12903,4956],{},[95,12905,2531],{},[15,12907,544,12908,548,12910,12913],{},[95,12909,547],{},[95,12911,12912],{},"unit-4-data-collections\u002F4.08-arraylist-and-its-methods.md"," (CSA 4.8)",[554,12915,556],{},{"title":48,"searchDepth":49,"depth":49,"links":12917},[12918,12919,12920,12921,12922,12923,12924],{"id":12334,"depth":49,"text":12335},{"id":12389,"depth":49,"text":12390},{"id":12422,"depth":49,"text":12423},{"id":12575,"depth":49,"text":12576},{"id":12651,"depth":49,"text":12652},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":12926,"status":12927},"9.2 — ArrayList and its Methods (CSA 4.8)","new — authored lesson (fuller depth than the teaser slide). See 9.1's note on why this combined-slide topic gets its own separate Lesson.","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F2-arraylist-and-its-methods",{"title":12326,"description":48},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.2-arraylist-and-its-methods","q5YVtCZdDD6rcvODZx8URaT4mNOKhwf04FSgVrQQEiw",{"id":12933,"title":12934,"body":12935,"description":48,"extension":51,"meta":13258,"navigation":55,"path":13261,"seo":13262,"stem":13263,"__hash__":13264},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.3-optional-hashmap-dictionary-data-structure.md","HashMap (Dictionary) Data Structure",{"type":8,"value":12936,"toc":13250},[12937,12940,12944,12959,12997,13007,13011,13020,13040,13044,13058,13086,13090,13131,13133,13186,13188,13240,13248],[11,12938,12934],{"id":12939},"hashmap-dictionary-data-structure",[69,12941,12943],{"id":12942},"key-value-pairs","Key-Value Pairs",[15,12945,405,12946,12951,12952,12955,12956,12958],{},[25,12947,12948],{},[95,12949,12950],{},"HashMap"," stores pairs — each unique ",[25,12953,12954],{},"key"," maps to a ",[25,12957,4024],{},", like a real dictionary mapping a word to its definition:",[104,12960,12962],{"className":106,"code":12961,"language":108,"meta":48,"style":48},"import java.util.HashMap;\n\nHashMap\u003CInteger, Double> motorOffsets = new HashMap\u003CInteger, Double>();\nmotorOffsets.put(5, 0.02);   \u002F\u002F CAN ID 5's calibration offset is 0.02\nmotorOffsets.put(6, -0.01);\n\ndouble offset = motorOffsets.get(5); \u002F\u002F 0.02\n",[95,12963,12964,12969,12973,12978,12983,12988,12992],{"__ignoreMap":48},[112,12965,12966],{"class":114,"line":115},[112,12967,12968],{},"import java.util.HashMap;\n",[112,12970,12971],{"class":114,"line":49},[112,12972,907],{"emptyLinePlaceholder":55},[112,12974,12975],{"class":114,"line":126},[112,12976,12977],{},"HashMap\u003CInteger, Double> motorOffsets = new HashMap\u003CInteger, Double>();\n",[112,12979,12980],{"class":114,"line":132},[112,12981,12982],{},"motorOffsets.put(5, 0.02);   \u002F\u002F CAN ID 5's calibration offset is 0.02\n",[112,12984,12985],{"class":114,"line":138},[112,12986,12987],{},"motorOffsets.put(6, -0.01);\n",[112,12989,12990],{"class":114,"line":144},[112,12991,907],{"emptyLinePlaceholder":55},[112,12993,12994],{"class":114,"line":150},[112,12995,12996],{},"double offset = motorOffsets.get(5); \u002F\u002F 0.02\n",[15,12998,12999,13002,13003,13006],{},[95,13000,13001],{},"put(key, value)"," adds or replaces a pair; ",[95,13004,13005],{},"get(key)"," retrieves the value for a key.",[69,13008,13010],{"id":13009},"when-to-reach-for-a-hashmap","When to Reach for a HashMap",[15,13012,13013,13014,13016,13017,13019],{},"Arrays and ",[95,13015,12343],{}," are naturally indexed by position (0, 1, 2...). A ",[95,13018,12950],{}," is for when the natural \"index\" is something else entirely — a name, an ID number, a label — and you want to look values up by that instead of a position:",[104,13021,13023],{"className":106,"code":13022,"language":108,"meta":48,"style":48},"HashMap\u003CString, String> subsystemStatus = new HashMap\u003CString, String>();\nsubsystemStatus.put(\"Intake\", \"Ready\");\nsubsystemStatus.put(\"Shooter\", \"Spinning Up\");\n",[95,13024,13025,13030,13035],{"__ignoreMap":48},[112,13026,13027],{"class":114,"line":115},[112,13028,13029],{},"HashMap\u003CString, String> subsystemStatus = new HashMap\u003CString, String>();\n",[112,13031,13032],{"class":114,"line":49},[112,13033,13034],{},"subsystemStatus.put(\"Intake\", \"Ready\");\n",[112,13036,13037],{"class":114,"line":126},[112,13038,13039],{},"subsystemStatus.put(\"Shooter\", \"Spinning Up\");\n",[69,13041,13043],{"id":13042},"looping-through-every-pair","Looping Through Every Pair",[15,13045,13046,13049,13050,13053,13054,13057],{},[95,13047,13048],{},"keySet()"," gives you every key, which you can then use with ",[95,13051,13052],{},"get()"," to reach each value. This loops with the for-each form (",[95,13055,13056],{},"for (type item : collection)",") — Lesson 9.4 covers it in full, but the short version: it visits every key in turn, with no index needed:",[104,13059,13061],{"className":106,"code":13060,"language":108,"meta":48,"style":48},"for (String name : subsystemStatus.keySet())\n{\n    String status = subsystemStatus.get(name);\n    System.out.println(name + \": \" + status);\n}\n",[95,13062,13063,13068,13072,13077,13082],{"__ignoreMap":48},[112,13064,13065],{"class":114,"line":115},[112,13066,13067],{},"for (String name : subsystemStatus.keySet())\n",[112,13069,13070],{"class":114,"line":49},[112,13071,123],{},[112,13073,13074],{"class":114,"line":126},[112,13075,13076],{},"    String status = subsystemStatus.get(name);\n",[112,13078,13079],{"class":114,"line":132},[112,13080,13081],{},"    System.out.println(name + \": \" + status);\n",[112,13083,13084],{"class":114,"line":138},[112,13085,153],{},[69,13087,13089],{"id":13088},"other-useful-methods","Other Useful Methods",[19,13091,13092,13105,13120,13126],{},[22,13093,13094,195,13097,13099,13100,13102,13103,79],{},[95,13095,13096],{},"containsKey(key)",[95,13098,661],{}," if that key has a value, without the risk of ",[95,13101,4956],{}," returning ",[95,13104,4645],{},[22,13106,13107,13110,13111,13113,13114,3181,13117,13119],{},[95,13108,13109],{},"getOrDefault(key, fallback)"," — like ",[95,13112,4956],{},", but returns ",[95,13115,13116],{},"fallback",[95,13118,4645],{}," when the key is missing.",[22,13121,13122,13125],{},[95,13123,13124],{},"remove(key)"," — deletes a pair by key.",[22,13127,13128,13130],{},[95,13129,12864],{}," — how many pairs the map holds.",[69,13132,462],{"id":461},[19,13134,13135,13149],{},[22,13136,13137,13143,13144,13146,13147,79],{},[25,13138,13139,13140,13142],{},"Assuming a ",[95,13141,12950],{}," remembers insertion order."," Unlike ",[95,13145,12343],{},", it doesn't guarantee any particular order when you loop through ",[95,13148,13048],{},[22,13150,13151,13160,13161,13163,13164,13167,13168,13170,13171,13173,13174,13176,13177,13179,13180,13182,13183,13185],{},[25,13152,13153,13154,13156,13157,79],{},"Calling ",[95,13155,13052],{}," with a key that was never ",[95,13158,13159],{},"put()"," Returns ",[95,13162,4645],{}," rather than throwing an error ",[494,13165,13166],{},"at that point"," — but if the value type is a primitive wrapper (like the ",[95,13169,8536],{}," offsets above), assigning that ",[95,13172,4645],{}," into a ",[95,13175,631],{}," unboxes it and throws ",[95,13178,4678],{}," right there (Ch.9.2's wrapper-class pitfalls). Use ",[95,13181,13096],{}," first, or ",[95,13184,13109],{},", whenever a lookup might legitimately miss.",[69,13187,501],{"id":500},[19,13189,13190,13196,13203,13209,13217],{},[22,13191,405,13192,13195],{},[95,13193,13194],{},"HashMap\u003CKeyType, ValueType>"," stores unique keys mapped to values.",[22,13197,13198,13002,13200,13202],{},[95,13199,13001],{},[95,13201,13005],{}," retrieves the value.",[22,13204,13205,13206,13208],{},"Reach for a ",[95,13207,12950],{}," when you naturally look things up by name\u002FID rather than by position.",[22,13210,13211,13213,13214,13216],{},[95,13212,13048],{}," gives every key, for looping through all pairs with a for-each loop and ",[95,13215,13052],{}," (Ch.9.4).",[22,13218,13219,13221,13222,13224,13225,13227,13228,176,13231,13234,13235,537,13237,13239],{},[95,13220,13052],{}," on a missing key returns ",[95,13223,4645],{},", which throws ",[95,13226,4678],{}," the moment it's unboxed into a primitive — check with ",[95,13229,13230],{},"containsKey()",[95,13232,13233],{},"getOrDefault()"," instead. ",[95,13236,13124],{},[95,13238,12864],{}," round out the common operations.",[15,13241,544,13242,548,13244,13247],{},[95,13243,547],{},[95,13245,13246],{},"unit-4-data-collections\u002F4.60-optional-hashmap-dictionary-data-structure.md"," (CSA 4.60)",[554,13249,556],{},{"title":48,"searchDepth":49,"depth":49,"links":13251},[13252,13253,13254,13255,13256,13257],{"id":12942,"depth":49,"text":12943},{"id":13009,"depth":49,"text":13010},{"id":13042,"depth":49,"text":13043},{"id":13088,"depth":49,"text":13089},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":13259,"status":13260},"9.3 — HashMap (Dictionary) Data Structure (CSA 4.60)","new — authored lesson (fuller depth than the teaser slide). See 9.1's note on why this combined-slide topic gets its own separate Lesson. Not on the AP CSA exam, but genuinely useful, common in real code, and required here since Ch.15 builds on it.","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F3-optional-hashmap-dictionary-data-structure",{"title":12934,"description":48},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.3-optional-hashmap-dictionary-data-structure","Npz2XzUlHx-GOYykOHF43X8LfJlvES2mQ8M3LmXe5Dg",{"id":13266,"title":13267,"body":13268,"description":48,"extension":51,"meta":13503,"navigation":55,"path":13505,"seo":13506,"stem":13507,"__hash__":13508},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.4-array-traversals.md","Array Traversals",{"type":8,"value":13269,"toc":13495},[13270,13273,13277,13283,13311,13317,13321,13327,13363,13367,13370,13393,13400,13404,13435,13437,13463,13465,13485,13493],[11,13271,13267],{"id":13272},"array-traversals",[69,13274,13276],{"id":13275},"looping-through-an-array","Looping Through an Array",[15,13278,13279,13282],{},[25,13280,13281],{},"Traversing"," an array means visiting its elements, usually with a loop. The loop variable doubles as the index:",[104,13284,13286],{"className":106,"code":13285,"language":108,"meta":48,"style":48},"double[] sensorReadings = {2.1, 2.4, 1.9, 2.2};\nfor (int i = 0; i \u003C sensorReadings.length; i++)\n{\n    System.out.println(sensorReadings[i]);\n}\n",[95,13287,13288,13293,13298,13302,13307],{"__ignoreMap":48},[112,13289,13290],{"class":114,"line":115},[112,13291,13292],{},"double[] sensorReadings = {2.1, 2.4, 1.9, 2.2};\n",[112,13294,13295],{"class":114,"line":49},[112,13296,13297],{},"for (int i = 0; i \u003C sensorReadings.length; i++)\n",[112,13299,13300],{"class":114,"line":126},[112,13301,123],{},[112,13303,13304],{"class":114,"line":132},[112,13305,13306],{},"    System.out.println(sensorReadings[i]);\n",[112,13308,13309],{"class":114,"line":138},[112,13310,153],{},[15,13312,13313,13314,13316],{},"Writing the loop against ",[95,13315,12755],{}," (not a hardcoded number) means the same code keeps working no matter how many elements the array actually has.",[69,13318,13320],{"id":13319},"arrays-are-objects-the-reference-is-copied","Arrays Are Objects — the Reference Is Copied",[15,13322,13323,13324,13326],{},"An array is an object, so passing one into a method copies the ",[494,13325,1475],{},", not the array itself — Java always uses call by value (Ch.7.3), but for an array the value being copied is a reference, so both the caller's variable and the parameter point at the same array. Changes a method makes to the array's contents are visible back in the caller:",[104,13328,13330],{"className":106,"code":13329,"language":108,"meta":48,"style":48},"public static void zeroOut(double[] values)\n{\n    for (int i = 0; i \u003C values.length; i++)\n    {\n        values[i] = 0.0; \u002F\u002F this really does change the caller's array\n    }\n}\n",[95,13331,13332,13337,13341,13346,13350,13355,13359],{"__ignoreMap":48},[112,13333,13334],{"class":114,"line":115},[112,13335,13336],{},"public static void zeroOut(double[] values)\n",[112,13338,13339],{"class":114,"line":49},[112,13340,123],{},[112,13342,13343],{"class":114,"line":126},[112,13344,13345],{},"    for (int i = 0; i \u003C values.length; i++)\n",[112,13347,13348],{"class":114,"line":132},[112,13349,135],{},[112,13351,13352],{"class":114,"line":138},[112,13353,13354],{},"        values[i] = 0.0; \u002F\u002F this really does change the caller's array\n",[112,13356,13357],{"class":114,"line":144},[112,13358,147],{},[112,13360,13361],{"class":114,"line":150},[112,13362,153],{},[69,13364,13366],{"id":13365},"the-enhanced-for-each-loop","The Enhanced For-Each Loop",[15,13368,13369],{},"When you just need every value, with no index and no plan to modify elements, the for-each form is simpler:",[104,13371,13373],{"className":106,"code":13372,"language":108,"meta":48,"style":48},"for (double reading : sensorReadings)\n{\n    System.out.println(reading);\n}\n",[95,13374,13375,13380,13384,13389],{"__ignoreMap":48},[112,13376,13377],{"class":114,"line":115},[112,13378,13379],{},"for (double reading : sensorReadings)\n",[112,13381,13382],{"class":114,"line":49},[112,13383,123],{},[112,13385,13386],{"class":114,"line":126},[112,13387,13388],{},"    System.out.println(reading);\n",[112,13390,13391],{"class":114,"line":132},[112,13392,153],{},[15,13394,13395,13396,13399],{},"It always starts at index 0 and runs through every element in order — a simpler ",[494,13397,13398],{},"choice"," than an indexed loop when you don't need the index, though (as the next section shows) not a drop-in replacement for every indexed-loop use.",[69,13401,13403],{"id":13402},"what-for-each-cant-do","What For-Each Can't Do",[19,13405,13406,13419,13429],{},[22,13407,13408,476,13411,13414,13415,13418],{},[25,13409,13410],{},"Can't modify a primitive array's elements.",[95,13412,13413],{},"reading = 0.0;"," inside the loop only changes the local copy, not the real array — you need an indexed loop (",[95,13416,13417],{},"values[i] = 0.0;",") to actually change values.",[22,13420,13421,13424,13425,13428],{},[25,13422,13423],{},"Can't get the index."," If you need to know ",[494,13426,13427],{},"where"," something is, use an indexed loop.",[22,13430,13431,13434],{},[25,13432,13433],{},"Can't skip around or go partway."," For-each always visits every element in order, front to back.",[69,13436,462],{"id":461},[19,13438,13439,13454],{},[22,13440,13441,476,13444,13447,13448,13450,13451,79],{},[25,13442,13443],{},"Off-by-one on the loop bound.",[95,13445,13446],{},"i \u003C= values.length"," runs one iteration too many and throws ",[95,13449,12136],{},"; the correct bound is always ",[95,13452,13453],{},"i \u003C values.length",[22,13455,13456,476,13459,13462],{},[25,13457,13458],{},"Expecting a for-each loop to change array values.",[95,13460,13461],{},"for (double v : values) { v = 0.0; }"," compiles, runs, and does absolutely nothing to the real array.",[69,13464,501],{"id":500},[19,13466,13467,13472,13475,13482],{},[22,13468,13469,13470,79],{},"Traversing an array means looping through it, index by index, with the loop bound written against ",[95,13471,12755],{},[22,13473,13474],{},"Arrays are objects — passing one copies the reference, so a method that changes array elements changes the caller's real array too.",[22,13476,13477,13478,13481],{},"The for-each loop (",[95,13479,13480],{},"for (type v : array)",") is simpler when you don't need the index and won't modify elements.",[22,13483,13484],{},"For-each cannot modify primitive array elements or provide the index — use an indexed loop for those.",[15,13486,544,13487,548,13489,13492],{},[95,13488,547],{},[95,13490,13491],{},"unit-4-data-collections\u002F4.04-array-traversals.md"," (CSA 4.4)",[554,13494,556],{},{"title":48,"searchDepth":49,"depth":49,"links":13496},[13497,13498,13499,13500,13501,13502],{"id":13275,"depth":49,"text":13276},{"id":13319,"depth":49,"text":13320},{"id":13365,"depth":49,"text":13366},{"id":13402,"depth":49,"text":13403},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":13504,"status":570},"9.4 — Array Traversals (CSA 4.4)","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F4-array-traversals",{"title":13267,"description":48},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.4-array-traversals","GX7W2-U8yznfI-bDj8I5m5M7cUkI6QldVhYOcmYRu78",{"id":13510,"title":13511,"body":13512,"description":13519,"extension":51,"meta":14075,"navigation":55,"path":14077,"seo":14078,"stem":14079,"__hash__":14080},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.5-implementing-array-algorithms.md","Implementing Array Algorithms",{"type":8,"value":13513,"toc":14064},[13514,13517,13520,13524,13555,13559,13604,13608,13662,13687,13691,13694,13717,13721,13864,13868,13871,13894,13897,13933,13937,13990,13992,14038,14040,14054,14062],[11,13515,13511],{"id":13516},"implementing-array-algorithms",[15,13518,13519],{},"A handful of patterns, all built from a loop plus a little bookkeeping, cover almost everything you'll want to do with an array.",[69,13521,13523],{"id":13522},"sum-average-accumulator","Sum \u002F Average (Accumulator)",[104,13525,13527],{"className":106,"code":13526,"language":108,"meta":48,"style":48},"double sum = 0;\nfor (double reading : sensorReadings)\n{\n    sum += reading;\n}\ndouble average = sum \u002F sensorReadings.length;\n",[95,13528,13529,13533,13537,13541,13546,13550],{"__ignoreMap":48},[112,13530,13531],{"class":114,"line":115},[112,13532,8451],{},[112,13534,13535],{"class":114,"line":49},[112,13536,13379],{},[112,13538,13539],{"class":114,"line":126},[112,13540,123],{},[112,13542,13543],{"class":114,"line":132},[112,13544,13545],{},"    sum += reading;\n",[112,13547,13548],{"class":114,"line":138},[112,13549,153],{},[112,13551,13552],{"class":114,"line":144},[112,13553,13554],{},"double average = sum \u002F sensorReadings.length;\n",[69,13556,13558],{"id":13557},"min-max","Min \u002F Max",[104,13560,13562],{"className":106,"code":13561,"language":108,"meta":48,"style":48},"\u002F\u002F seed with the first element, not 0 — a reading could be negative\ndouble max = sensorReadings[0];\nfor (double reading : sensorReadings)\n{\n    if (reading > max)\n    {\n        max = reading;\n    }\n}\n",[95,13563,13564,13569,13574,13578,13582,13587,13591,13596,13600],{"__ignoreMap":48},[112,13565,13566],{"class":114,"line":115},[112,13567,13568],{},"\u002F\u002F seed with the first element, not 0 — a reading could be negative\n",[112,13570,13571],{"class":114,"line":49},[112,13572,13573],{},"double max = sensorReadings[0];\n",[112,13575,13576],{"class":114,"line":126},[112,13577,13379],{},[112,13579,13580],{"class":114,"line":132},[112,13581,123],{},[112,13583,13584],{"class":114,"line":138},[112,13585,13586],{},"    if (reading > max)\n",[112,13588,13589],{"class":114,"line":144},[112,13590,135],{},[112,13592,13593],{"class":114,"line":150},[112,13594,13595],{},"        max = reading;\n",[112,13597,13598],{"class":114,"line":2276},[112,13599,147],{},[112,13601,13602],{"class":114,"line":2282},[112,13603,153],{},[69,13605,13607],{"id":13606},"search-check-everything-before-giving-up","Search — Check Everything Before Giving Up",[104,13609,13611],{"className":106,"code":13610,"language":108,"meta":48,"style":48},"public static boolean contains(double[] values, double target)\n{\n    for (double v : values)\n    {\n        if (v == target)\n        {\n            return true; \u002F\u002F fine to return early on a MATCH\n        }\n    }\n    return false; \u002F\u002F only after checking every element\n}\n",[95,13612,13613,13618,13622,13627,13631,13636,13640,13645,13649,13653,13658],{"__ignoreMap":48},[112,13614,13615],{"class":114,"line":115},[112,13616,13617],{},"public static boolean contains(double[] values, double target)\n",[112,13619,13620],{"class":114,"line":49},[112,13621,123],{},[112,13623,13624],{"class":114,"line":126},[112,13625,13626],{},"    for (double v : values)\n",[112,13628,13629],{"class":114,"line":132},[112,13630,135],{},[112,13632,13633],{"class":114,"line":138},[112,13634,13635],{},"        if (v == target)\n",[112,13637,13638],{"class":114,"line":144},[112,13639,11303],{},[112,13641,13642],{"class":114,"line":150},[112,13643,13644],{},"            return true; \u002F\u002F fine to return early on a MATCH\n",[112,13646,13647],{"class":114,"line":2276},[112,13648,11313],{},[112,13650,13651],{"class":114,"line":2282},[112,13652,147],{},[112,13654,13655],{"class":114,"line":2288},[112,13656,13657],{},"    return false; \u002F\u002F only after checking every element\n",[112,13659,13660],{"class":114,"line":5760},[112,13661,153],{},[15,13663,13664,13667,13668,13670,13671,176,13673,13675,13676,13679,13680,13682,13683,13686],{},[95,13665,13666],{},"v == target"," only makes sense when ",[95,13669,1968],{}," is a value you know is exact (a literal you just assigned, or an ",[95,13672,603],{},[95,13674,616],{}," count). Comparing ",[494,13677,13678],{},"computed"," or measured ",[95,13681,631],{},"s this way is risky (Ch.2.4, Ch.5.4) — use a tolerance comparison (",[95,13684,13685],{},"Math.abs(v - target) \u003C tolerance",") instead when either side came from a calculation or a sensor.",[69,13688,13690],{"id":13689},"looping-back-to-front","Looping Back to Front",[15,13692,13693],{},"Same shape, just counting down:",[104,13695,13697],{"className":106,"code":13696,"language":108,"meta":48,"style":48},"for (int i = values.length - 1; i >= 0; i--)\n{\n    \u002F\u002F process values[i], starting from the end\n}\n",[95,13698,13699,13704,13708,13713],{"__ignoreMap":48},[112,13700,13701],{"class":114,"line":115},[112,13702,13703],{},"for (int i = values.length - 1; i >= 0; i--)\n",[112,13705,13706],{"class":114,"line":49},[112,13707,123],{},[112,13709,13710],{"class":114,"line":126},[112,13711,13712],{},"    \u002F\u002F process values[i], starting from the end\n",[112,13714,13715],{"class":114,"line":132},[112,13716,153],{},[69,13718,13720],{"id":13719},"at-least-one-all-count","\"At Least One\" \u002F \"All\" \u002F \"Count\"",[104,13722,13724],{"className":106,"code":13723,"language":108,"meta":48,"style":48},"\u002F\u002F at least one has the property\nfor (double v : values)\n{\n    if (isFaulty(v))\n    {\n        return true;\n    }\n}\nreturn false;\n\n\u002F\u002F all have the property (check the NEGATION, bail early on a counter-example)\nfor (double v : values)\n{\n    if (!isFaulty(v))\n    {\n        return false;\n    }\n}\nreturn true;\n\n\u002F\u002F count how many have the property\nint count = 0;\nfor (double v : values)\n{\n    if (isFaulty(v))\n    {\n        count++;\n    }\n}\n",[95,13725,13726,13731,13736,13740,13745,13749,13754,13758,13762,13767,13771,13776,13780,13784,13789,13793,13798,13802,13806,13811,13816,13822,13828,13833,13838,13843,13848,13854,13859],{"__ignoreMap":48},[112,13727,13728],{"class":114,"line":115},[112,13729,13730],{},"\u002F\u002F at least one has the property\n",[112,13732,13733],{"class":114,"line":49},[112,13734,13735],{},"for (double v : values)\n",[112,13737,13738],{"class":114,"line":126},[112,13739,123],{},[112,13741,13742],{"class":114,"line":132},[112,13743,13744],{},"    if (isFaulty(v))\n",[112,13746,13747],{"class":114,"line":138},[112,13748,135],{},[112,13750,13751],{"class":114,"line":144},[112,13752,13753],{},"        return true;\n",[112,13755,13756],{"class":114,"line":150},[112,13757,147],{},[112,13759,13760],{"class":114,"line":2276},[112,13761,153],{},[112,13763,13764],{"class":114,"line":2282},[112,13765,13766],{},"return false;\n",[112,13768,13769],{"class":114,"line":2288},[112,13770,907],{"emptyLinePlaceholder":55},[112,13772,13773],{"class":114,"line":5760},[112,13774,13775],{},"\u002F\u002F all have the property (check the NEGATION, bail early on a counter-example)\n",[112,13777,13778],{"class":114,"line":5766},[112,13779,13735],{},[112,13781,13782],{"class":114,"line":5772},[112,13783,123],{},[112,13785,13786],{"class":114,"line":5777},[112,13787,13788],{},"    if (!isFaulty(v))\n",[112,13790,13791],{"class":114,"line":5783},[112,13792,135],{},[112,13794,13795],{"class":114,"line":5789},[112,13796,13797],{},"        return false;\n",[112,13799,13800],{"class":114,"line":5794},[112,13801,147],{},[112,13803,13804],{"class":114,"line":10057},[112,13805,153],{},[112,13807,13808],{"class":114,"line":10062},[112,13809,13810],{},"return true;\n",[112,13812,13814],{"class":114,"line":13813},20,[112,13815,907],{"emptyLinePlaceholder":55},[112,13817,13819],{"class":114,"line":13818},21,[112,13820,13821],{},"\u002F\u002F count how many have the property\n",[112,13823,13825],{"class":114,"line":13824},22,[112,13826,13827],{},"int count = 0;\n",[112,13829,13831],{"class":114,"line":13830},23,[112,13832,13735],{},[112,13834,13836],{"class":114,"line":13835},24,[112,13837,123],{},[112,13839,13841],{"class":114,"line":13840},25,[112,13842,13744],{},[112,13844,13846],{"class":114,"line":13845},26,[112,13847,135],{},[112,13849,13851],{"class":114,"line":13850},27,[112,13852,13853],{},"        count++;\n",[112,13855,13857],{"class":114,"line":13856},28,[112,13858,147],{},[112,13860,13862],{"class":114,"line":13861},29,[112,13863,153],{},[69,13865,13867],{"id":13866},"duplicates","Duplicates",[15,13869,13870],{},"Adjacent only — a single loop comparing neighbors:",[104,13872,13874],{"className":106,"code":13873,"language":108,"meta":48,"style":48},"for (int i = 0; i \u003C values.length - 1; i++)\n{\n    if (values[i] == values[i + 1]) return true;\n}\n",[95,13875,13876,13881,13885,13890],{"__ignoreMap":48},[112,13877,13878],{"class":114,"line":115},[112,13879,13880],{},"for (int i = 0; i \u003C values.length - 1; i++)\n",[112,13882,13883],{"class":114,"line":49},[112,13884,123],{},[112,13886,13887],{"class":114,"line":126},[112,13888,13889],{},"    if (values[i] == values[i + 1]) return true;\n",[112,13891,13892],{"class":114,"line":132},[112,13893,153],{},[15,13895,13896],{},"Anywhere in the array — a nested loop comparing every pair:",[104,13898,13900],{"className":106,"code":13899,"language":108,"meta":48,"style":48},"for (int i = 0; i \u003C values.length; i++)\n{\n    for (int j = i + 1; j \u003C values.length; j++)\n    {\n        if (values[i] == values[j]) return true;\n    }\n}\n",[95,13901,13902,13907,13911,13916,13920,13925,13929],{"__ignoreMap":48},[112,13903,13904],{"class":114,"line":115},[112,13905,13906],{},"for (int i = 0; i \u003C values.length; i++)\n",[112,13908,13909],{"class":114,"line":49},[112,13910,123],{},[112,13912,13913],{"class":114,"line":126},[112,13914,13915],{},"    for (int j = i + 1; j \u003C values.length; j++)\n",[112,13917,13918],{"class":114,"line":132},[112,13919,135],{},[112,13921,13922],{"class":114,"line":138},[112,13923,13924],{},"        if (values[i] == values[j]) return true;\n",[112,13926,13927],{"class":114,"line":144},[112,13928,147],{},[112,13930,13931],{"class":114,"line":150},[112,13932,153],{},[69,13934,13936],{"id":13935},"reversing-swap-from-both-ends","Reversing (Swap From Both Ends)",[104,13938,13940],{"className":106,"code":13939,"language":108,"meta":48,"style":48},"int start = 0;\nint end = values.length - 1;\nwhile (start \u003C end)\n{\n    double temp = values[start];\n    values[start] = values[end];\n    values[end] = temp;\n    start++;\n    end--;\n}\n",[95,13941,13942,13947,13952,13957,13961,13966,13971,13976,13981,13986],{"__ignoreMap":48},[112,13943,13944],{"class":114,"line":115},[112,13945,13946],{},"int start = 0;\n",[112,13948,13949],{"class":114,"line":49},[112,13950,13951],{},"int end = values.length - 1;\n",[112,13953,13954],{"class":114,"line":126},[112,13955,13956],{},"while (start \u003C end)\n",[112,13958,13959],{"class":114,"line":132},[112,13960,123],{},[112,13962,13963],{"class":114,"line":138},[112,13964,13965],{},"    double temp = values[start];\n",[112,13967,13968],{"class":114,"line":144},[112,13969,13970],{},"    values[start] = values[end];\n",[112,13972,13973],{"class":114,"line":150},[112,13974,13975],{},"    values[end] = temp;\n",[112,13977,13978],{"class":114,"line":2276},[112,13979,13980],{},"    start++;\n",[112,13982,13983],{"class":114,"line":2282},[112,13984,13985],{},"    end--;\n",[112,13987,13988],{"class":114,"line":2288},[112,13989,153],{},[69,13991,462],{"id":461},[19,13993,13994,14009,14019],{},[22,13995,13996,14002,14003,14005,14006,14008],{},[25,13997,13998,13999,14001],{},"Seeding min\u002Fmax with ",[95,14000,1365],{}," instead of the first element."," If every real value is negative, ",[95,14004,1365],{}," looks like a (wrong) max that never gets beaten; if every real value is positive, ",[95,14007,1365],{}," looks like a (wrong) min that never gets beaten. Seeding with the first element avoids both failure modes.",[22,14010,14011,14014,14015,14018],{},[25,14012,14013],{},"Returning \"not found\" from inside the loop."," Only a ",[494,14016,14017],{},"match"," should return early; \"not found\" has to wait until the loop has checked every element.",[22,14020,14021,14030,14031,14034,14035,4410],{},[25,14022,1995,14023,4029,14026,14029],{},[95,14024,14025],{},"values[i]",[95,14027,14028],{},"values[i+1]"," all the way to the last index."," This reads one past the end — the adjacent-duplicate loop must stop at ",[95,14032,14033],{},"length - 2"," (i.e., bound the loop by ",[95,14036,14037],{},"i \u003C values.length - 1",[69,14039,501],{"id":500},[19,14041,14042,14045,14048,14051],{},[22,14043,14044],{},"Sum\u002Faverage, min\u002Fmax, search, and property-counting are all the same basic shape: a loop plus a little state (an accumulator, a running best, a counter, or an early return).",[22,14046,14047],{},"A search for \"not found\" must check every element before concluding absence; a search for a match can return the instant it's found.",[22,14049,14050],{},"Adjacent-duplicate checks are a single loop; any-pair duplicate checks need a nested loop.",[22,14052,14053],{},"Reversing in place swaps from both ends toward the middle using a temporary variable.",[15,14055,544,14056,548,14058,14061],{},[95,14057,547],{},[95,14059,14060],{},"unit-4-data-collections\u002F4.05-implementing-array-algorithms.md"," (CSA 4.5)",[554,14063,556],{},{"title":48,"searchDepth":49,"depth":49,"links":14065},[14066,14067,14068,14069,14070,14071,14072,14073,14074],{"id":13522,"depth":49,"text":13523},{"id":13557,"depth":49,"text":13558},{"id":13606,"depth":49,"text":13607},{"id":13689,"depth":49,"text":13690},{"id":13719,"depth":49,"text":13720},{"id":13866,"depth":49,"text":13867},{"id":13935,"depth":49,"text":13936},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":14076,"status":570},"9.5 — Implementing Array Algorithms (CSA 4.5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F5-implementing-array-algorithms",{"title":13511,"description":13519},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.5-implementing-array-algorithms","ZqwqOt6FUnXWNcnMPF7V-qEmCqG47WkidTUrs_CciiA",{"id":14082,"title":14083,"body":14084,"description":48,"extension":51,"meta":14375,"navigation":55,"path":14377,"seo":14378,"stem":14379,"__hash__":14380},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.6-arraylist-traversals.md","ArrayList Traversals",{"type":8,"value":14085,"toc":14366},[14086,14089,14093,14113,14138,14142,14157,14161,14168,14231,14235,14260,14264,14279,14281,14321,14323,14356,14364],[11,14087,14083],{"id":14088},"arraylist-traversals",[69,14090,14092],{"id":14091},"same-loop-shapes-as-arrays","Same Loop Shapes as Arrays",[15,14094,14095,14096,325,14098,14100,14101,14103,14104,3181,14106,325,14109,3181,14111,738],{},"For-each, indexed ",[95,14097,5188],{},[95,14099,7977],{}," all work on an ",[95,14102,12343],{}," — just with ",[95,14105,12744],{},[95,14107,14108],{},"[i]",[95,14110,12758],{},[95,14112,12755],{},[104,14114,14116],{"className":106,"code":14115,"language":108,"meta":48,"style":48},"\u002F\u002F for-each — read-only pass\nfor (String log : logs) { System.out.println(log); }\n\u002F\u002F indexed\nfor (int i = 0; i \u003C logs.size(); i++) { System.out.println(logs.get(i)); }\n",[95,14117,14118,14123,14128,14133],{"__ignoreMap":48},[112,14119,14120],{"class":114,"line":115},[112,14121,14122],{},"\u002F\u002F for-each — read-only pass\n",[112,14124,14125],{"class":114,"line":49},[112,14126,14127],{},"for (String log : logs) { System.out.println(log); }\n",[112,14129,14130],{"class":114,"line":126},[112,14131,14132],{},"\u002F\u002F indexed\n",[112,14134,14135],{"class":114,"line":132},[112,14136,14137],{},"for (int i = 0; i \u003C logs.size(); i++) { System.out.println(logs.get(i)); }\n",[69,14139,14141],{"id":14140},"the-big-restriction-dont-resize-during-a-for-each","The Big Restriction: Don't Resize During a For-Each",[15,14143,14144,14145,14147,14148,14151,14152,260,14154,14156],{},"Adding or removing elements from an ",[95,14146,12343],{}," while a for-each loop is traversing it usually throws ",[95,14149,14150],{},"ConcurrentModificationException"," — but not always. Remove the second-to-last element and the loop can end silently instead, quietly skipping the last element rather than throwing anything. Either way, it's broken; never rely on the exception to catch this for you. If you need to add or remove while looping, use an indexed ",[95,14153,5188],{},[95,14155,7977],{}," loop instead.",[69,14158,14160],{"id":14159},"removing-while-looping-the-careful-way","Removing While Looping — The Careful Way",[15,14162,14163,14164,14167],{},"Removing an element shifts every later element down by one index. If you increment the loop index ",[494,14165,14166],{},"unconditionally"," after a removal, you skip checking the element that just got shifted into the spot you were on:",[104,14169,14171],{"className":106,"code":14170,"language":108,"meta":48,"style":48},"int i = 0;\nwhile (i \u003C logs.size())\n{\n    if (shouldRemove(logs.get(i)))\n    {\n        \u002F\u002F don't increment i here — the next element just shifted into index i\n        logs.remove(i);\n    }\n    else\n    {\n        i++; \u002F\u002F only advance when nothing was removed this iteration\n    }\n}\n",[95,14172,14173,14177,14182,14186,14191,14195,14200,14205,14209,14214,14218,14223,14227],{"__ignoreMap":48},[112,14174,14175],{"class":114,"line":115},[112,14176,8040],{},[112,14178,14179],{"class":114,"line":49},[112,14180,14181],{},"while (i \u003C logs.size())\n",[112,14183,14184],{"class":114,"line":126},[112,14185,123],{},[112,14187,14188],{"class":114,"line":132},[112,14189,14190],{},"    if (shouldRemove(logs.get(i)))\n",[112,14192,14193],{"class":114,"line":138},[112,14194,135],{},[112,14196,14197],{"class":114,"line":144},[112,14198,14199],{},"        \u002F\u002F don't increment i here — the next element just shifted into index i\n",[112,14201,14202],{"class":114,"line":150},[112,14203,14204],{},"        logs.remove(i);\n",[112,14206,14207],{"class":114,"line":2276},[112,14208,147],{},[112,14210,14211],{"class":114,"line":2282},[112,14212,14213],{},"    else\n",[112,14215,14216],{"class":114,"line":2288},[112,14217,135],{},[112,14219,14220],{"class":114,"line":5760},[112,14221,14222],{},"        i++; \u002F\u002F only advance when nothing was removed this iteration\n",[112,14224,14225],{"class":114,"line":5766},[112,14226,147],{},[112,14228,14229],{"class":114,"line":5772},[112,14230,153],{},[69,14232,14234],{"id":14233},"chaining-through-a-list-of-objects","Chaining Through a List of Objects",[104,14236,14238],{"className":106,"code":14237,"language":108,"meta":48,"style":48},"\u002F\u002F assume RobotPart exists, with getName() — Ch.17 builds it out fully\nArrayList\u003CRobotPart> parts = new ArrayList\u003CRobotPart>();\n\u002F\u002F chain: get the object, then call a method on it\nString firstName = parts.get(0).getName();\n",[95,14239,14240,14245,14250,14255],{"__ignoreMap":48},[112,14241,14242],{"class":114,"line":115},[112,14243,14244],{},"\u002F\u002F assume RobotPart exists, with getName() — Ch.17 builds it out fully\n",[112,14246,14247],{"class":114,"line":49},[112,14248,14249],{},"ArrayList\u003CRobotPart> parts = new ArrayList\u003CRobotPart>();\n",[112,14251,14252],{"class":114,"line":126},[112,14253,14254],{},"\u002F\u002F chain: get the object, then call a method on it\n",[112,14256,14257],{"class":114,"line":132},[112,14258,14259],{},"String firstName = parts.get(0).getName();\n",[69,14261,14263],{"id":14262},"removing-without-the-careful-index-dance","Removing Without the Careful Index Dance",[15,14265,14266,14267,14270,14271,14274,14275,14278],{},"Once interfaces and generics are covered (Ch.19), ",[95,14268,14269],{},"removeIf(condition)"," and the ",[95,14272,14273],{},"Iterator","'s own ",[95,14276,14277],{},"remove()"," do this same job in one call, without the manual index bookkeeping above — a preview worth knowing about, not required yet.",[69,14280,462],{"id":461},[19,14282,14283,14297,14309],{},[22,14284,14285,14288,14289,14291,14292,260,14294,14296],{},[25,14286,14287],{},"Adding\u002Fremoving inside a for-each loop."," Usually throws ",[95,14290,14150],{},", but can also silently skip an element instead — switch to an indexed ",[95,14293,5188],{},[95,14295,7977],{}," loop if the list's size needs to change mid-traversal.",[22,14298,14299,14304,14305,14308],{},[25,14300,14301,14302,79],{},"Incrementing the index unconditionally after a ",[95,14303,12729],{}," This skips the element that shifted into the just-vacated slot — only advance the index when you ",[494,14306,14307],{},"didn't"," remove anything that pass.",[22,14310,14311,14317,14318,79],{},[25,14312,6835,14313,9706,14315,79],{},[95,14314,5263],{},[95,14316,12758],{}," Same off-by-one risk as arrays — the last valid index is ",[95,14319,14320],{},"size() - 1",[69,14322,501],{"id":500},[19,14324,14325,14338,14344,14347],{},[22,14326,14327,14329,14330,176,14332,3181,14334,176,14336,79],{},[95,14328,12343],{}," supports the same loop shapes as arrays, using ",[95,14331,12744],{},[95,14333,12758],{},[95,14335,14108],{},[95,14337,12755],{},[22,14339,14340,14341,14343],{},"Never add or remove elements from an ",[95,14342,12343],{}," while traversing it with a for-each loop — it usually throws, but can also fail silently instead.",[22,14345,14346],{},"When removing elements in an indexed\u002Fwhile loop, only advance the index on iterations where nothing was removed.",[22,14348,14349,176,14352,14355],{},[95,14350,14351],{},"removeIf()",[95,14353,14354],{},"Iterator.remove()"," (Ch.19) do this more directly once interfaces are covered.",[15,14357,544,14358,548,14360,14363],{},[95,14359,547],{},[95,14361,14362],{},"unit-4-data-collections\u002F4.09-arraylist-traversals.md"," (CSA 4.9)",[554,14365,556],{},{"title":48,"searchDepth":49,"depth":49,"links":14367},[14368,14369,14370,14371,14372,14373,14374],{"id":14091,"depth":49,"text":14092},{"id":14140,"depth":49,"text":14141},{"id":14159,"depth":49,"text":14160},{"id":14233,"depth":49,"text":14234},{"id":14262,"depth":49,"text":14263},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":14376,"status":570},"9.6 — ArrayList Traversals (CSA 4.9)","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F6-arraylist-traversals",{"title":14083,"description":48},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.6-arraylist-traversals","Bq0rhPj2olgHVPskUW4e_rcB3ouGp39f_v9zqCh3vdk",{"id":14382,"title":14383,"body":14384,"description":14718,"extension":51,"meta":14719,"navigation":55,"path":14721,"seo":14722,"stem":14723,"__hash__":14724},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.7-implementing-arraylist-algorithms.md","Implementing ArrayList Algorithms",{"type":8,"value":14385,"toc":14708},[14386,14389,14403,14407,14453,14461,14472,14521,14529,14575,14579,14582,14602,14604,14655,14657,14698,14706],[11,14387,14383],{"id":14388},"implementing-arraylist-algorithms",[15,14390,14391,14392,14394,14395,176,14397,199,14399,176,14401,79],{},"Every pattern from Lesson 9.5 (sum\u002Faverage, min\u002Fmax, search, property checks, duplicates, reversing) applies to ",[95,14393,12343],{}," too — just swap ",[95,14396,14108],{},[95,14398,12755],{},[95,14400,12744],{},[95,14402,12758],{},[69,14404,14406],{"id":14405},"min-max-average","Min \u002F Max \u002F Average",[104,14408,14410],{"className":106,"code":14409,"language":108,"meta":48,"style":48},"public static double average(ArrayList\u003CDouble> nums)\n{\n    double sum = 0;\n    for (int i = 0; i \u003C nums.size(); i++)\n    {\n        sum += nums.get(i);\n    }\n    return sum \u002F nums.size();\n}\n",[95,14411,14412,14417,14421,14426,14431,14435,14440,14444,14449],{"__ignoreMap":48},[112,14413,14414],{"class":114,"line":115},[112,14415,14416],{},"public static double average(ArrayList\u003CDouble> nums)\n",[112,14418,14419],{"class":114,"line":49},[112,14420,123],{},[112,14422,14423],{"class":114,"line":126},[112,14424,14425],{},"    double sum = 0;\n",[112,14427,14428],{"class":114,"line":132},[112,14429,14430],{},"    for (int i = 0; i \u003C nums.size(); i++)\n",[112,14432,14433],{"class":114,"line":138},[112,14434,135],{},[112,14436,14437],{"class":114,"line":144},[112,14438,14439],{},"        sum += nums.get(i);\n",[112,14441,14442],{"class":114,"line":150},[112,14443,147],{},[112,14445,14446],{"class":114,"line":2276},[112,14447,14448],{},"    return sum \u002F nums.size();\n",[112,14450,14451],{"class":114,"line":2282},[112,14452,153],{},[69,14454,14456,14457,9248,14459],{"id":14455},"duplicates-use-equals-not","Duplicates — Use ",[95,14458,7836],{},[95,14460,1921],{},[15,14462,14463,14464,14466,14467,14469,14470,1114],{},"For ",[95,14465,12523],{}," (or any object type), comparing with ",[95,14468,1921],{}," checks identity, not value — use ",[95,14471,7836],{},[104,14473,14475],{"className":106,"code":14474,"language":108,"meta":48,"style":48},"for (int i = 0; i \u003C nums.size(); i++)\n{\n    for (int j = i + 1; j \u003C nums.size(); j++)\n    {\n        if (nums.get(i).equals(nums.get(j))) \u002F\u002F .equals(), not ==\n        {\n            return true;\n        }\n    }\n}\n",[95,14476,14477,14482,14486,14491,14495,14500,14504,14509,14513,14517],{"__ignoreMap":48},[112,14478,14479],{"class":114,"line":115},[112,14480,14481],{},"for (int i = 0; i \u003C nums.size(); i++)\n",[112,14483,14484],{"class":114,"line":49},[112,14485,123],{},[112,14487,14488],{"class":114,"line":126},[112,14489,14490],{},"    for (int j = i + 1; j \u003C nums.size(); j++)\n",[112,14492,14493],{"class":114,"line":132},[112,14494,135],{},[112,14496,14497],{"class":114,"line":138},[112,14498,14499],{},"        if (nums.get(i).equals(nums.get(j))) \u002F\u002F .equals(), not ==\n",[112,14501,14502],{"class":114,"line":144},[112,14503,11303],{},[112,14505,14506],{"class":114,"line":150},[112,14507,14508],{},"            return true;\n",[112,14510,14511],{"class":114,"line":2276},[112,14512,11313],{},[112,14514,14515],{"class":114,"line":2282},[112,14516,147],{},[112,14518,14519],{"class":114,"line":2288},[112,14520,153],{},[69,14522,14524,14525,176,14527,1282],{"id":14523},"rotating-in-place-with-getset","Rotating (In Place, with ",[95,14526,4956],{},[95,14528,2531],{},[104,14530,14532],{"className":106,"code":14531,"language":108,"meta":48,"style":48},"public static void rotateRight(ArrayList\u003CDouble> nums)\n{\n    double last = nums.get(nums.size() - 1);\n    for (int i = nums.size() - 1; i > 0; i--)\n    {\n        nums.set(i, nums.get(i - 1));\n    }\n    nums.set(0, last);\n}\n",[95,14533,14534,14539,14543,14548,14553,14557,14562,14566,14571],{"__ignoreMap":48},[112,14535,14536],{"class":114,"line":115},[112,14537,14538],{},"public static void rotateRight(ArrayList\u003CDouble> nums)\n",[112,14540,14541],{"class":114,"line":49},[112,14542,123],{},[112,14544,14545],{"class":114,"line":126},[112,14546,14547],{},"    double last = nums.get(nums.size() - 1);\n",[112,14549,14550],{"class":114,"line":132},[112,14551,14552],{},"    for (int i = nums.size() - 1; i > 0; i--)\n",[112,14554,14555],{"class":114,"line":138},[112,14556,135],{},[112,14558,14559],{"class":114,"line":144},[112,14560,14561],{},"        nums.set(i, nums.get(i - 1));\n",[112,14563,14564],{"class":114,"line":150},[112,14565,147],{},[112,14567,14568],{"class":114,"line":2276},[112,14569,14570],{},"    nums.set(0, last);\n",[112,14572,14573],{"class":114,"line":2282},[112,14574,153],{},[69,14576,14578],{"id":14577},"parallel-arraylists","Parallel ArrayLists",[15,14580,14581],{},"Same idea as parallel arrays (Ch.9.1) — two lists kept in sync by index:",[104,14583,14585],{"className":106,"code":14584,"language":108,"meta":48,"style":48},"ArrayList\u003CString> autoNames = new ArrayList\u003CString>();\nArrayList\u003CDouble> autoTimes = new ArrayList\u003CDouble>();\n\u002F\u002F autoTimes.get(i) is the recorded time for autoNames.get(i)\n",[95,14586,14587,14592,14597],{"__ignoreMap":48},[112,14588,14589],{"class":114,"line":115},[112,14590,14591],{},"ArrayList\u003CString> autoNames = new ArrayList\u003CString>();\n",[112,14593,14594],{"class":114,"line":49},[112,14595,14596],{},"ArrayList\u003CDouble> autoTimes = new ArrayList\u003CDouble>();\n",[112,14598,14599],{"class":114,"line":126},[112,14600,14601],{},"\u002F\u002F autoTimes.get(i) is the recorded time for autoNames.get(i)\n",[69,14603,462],{"id":461},[19,14605,14606,14628,14647],{},[22,14607,14608,14615,14616,14619,14620,14622,14623,12544,14625,14627],{},[25,14609,14610,14611,3181,14613,79],{},"Comparing objects with ",[95,14612,1921],{},[95,14614,7836],{}," This is the single most common ArrayList-specific mistake — ",[95,14617,14618],{},"nums.get(i) == nums.get(j)"," checks whether they're the same object, which is unreliable even for boxed ",[95,14621,1869],{},"s. It's especially deceptive here: Java caches small ",[95,14624,1869],{},[95,14626,1921],{}," can look like it \"works\" for small test values and then quietly fail once real data includes anything larger (Ch.9.2).",[22,14629,14630,476,14636,14639,14640,14642,14643,176,14645,79],{},[25,14631,14632,14633,14635],{},"Using array syntax (",[95,14634,12647],{},") out of habit.",[95,14637,14638],{},"nums[i]"," doesn't compile on an ",[95,14641,12343],{}," — it's always ",[95,14644,4956],{},[95,14646,2531],{},[22,14648,14649,14654],{},[25,14650,4719,14651,14653],{},[95,14652,12758],{}," changes as you add\u002Fremove."," A loop bound computed once before a series of removals can end up stale.",[69,14656,501],{"id":500},[19,14658,14659,14679,14692],{},[22,14660,14661,14662,14664,14665,176,14667,199,14669,176,14671,14673,14674,176,14676,14678],{},"Every array algorithm pattern from Lesson 9.5 (accumulator, min\u002Fmax, search, property checks, duplicates, reverse) transfers directly to ",[95,14663,12343],{}," — just swap ",[95,14666,14108],{},[95,14668,12755],{},[95,14670,12744],{},[95,14672,12758],{},". Rotating is new here, built the same way: ",[95,14675,4956],{},[95,14677,2531],{}," in a loop.",[22,14680,14681,14682,14684,14685,959,14687,14689,14690,4410],{},"Compare ",[95,14683,12343],{}," elements with ",[95,14686,7836],{},[95,14688,1921],{},", when the element type is an object (including boxed numbers like ",[95,14691,1869],{},[22,14693,14694,14695,14697],{},"Parallel ",[95,14696,12343],{},"s keep related data in sync by index, same as parallel arrays.",[15,14699,544,14700,548,14702,14705],{},[95,14701,547],{},[95,14703,14704],{},"unit-4-data-collections\u002F4.10-implementing-arraylist-algorithms.md"," (CSA 4.10)",[554,14707,556],{},{"title":48,"searchDepth":49,"depth":49,"links":14709},[14710,14711,14713,14715,14716,14717],{"id":14405,"depth":49,"text":14406},{"id":14455,"depth":49,"text":14712},"Duplicates — Use .equals(), Not ==",{"id":14523,"depth":49,"text":14714},"Rotating (In Place, with get\u002Fset)",{"id":14577,"depth":49,"text":14578},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},"Every pattern from Lesson 9.5 (sum\u002Faverage, min\u002Fmax, search, property checks, duplicates, reversing) applies to ArrayList too — just swap [i]\u002F.length for get(i)\u002F.size().",{"outlineRef":14720,"status":570},"9.7 — Implementing ArrayList Algorithms (CSA 4.10)","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F7-implementing-arraylist-algorithms",{"title":14383,"description":14718},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.7-implementing-arraylist-algorithms","3BPi5bH1WtJ9jziIOQZyyRJW8wo3Ik_sEhy2PwTu9lw",{"id":14726,"title":14727,"body":14728,"description":48,"extension":51,"meta":15173,"navigation":55,"path":15175,"seo":15176,"stem":15177,"__hash__":15178},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.8-using-text-files.md","Using Text Files",{"type":8,"value":14729,"toc":15163},[14730,14733,14737,14740,14744,14760,14789,14819,14843,14881,14885,14918,14926,14930,14943,14978,14992,14996,15002,15029,15033,15039,15071,15073,15112,15114,15153,15161],[11,14731,14727],{"id":14732},"using-text-files",[69,14734,14736],{"id":14735},"why-read-from-a-file","Why Read From a File",[15,14738,14739],{},"A file's data persists even when the program isn't running — useful for loading configuration or data that's too large (or too changeable) to hard-code into your source. A robot might load a table of autonomous starting positions from a file instead of hardcoding them.",[69,14741,14743],{"id":14742},"opening-a-file","Opening a File",[15,14745,14746,12217,14749,14752,14753,12217,14756,14759],{},[95,14747,14748],{},"File",[95,14750,14751],{},"java.io",") represents the file itself — really just a filename\u002Fpath, and building one never fails even if the file doesn't exist. ",[95,14754,14755],{},"Scanner",[95,14757,14758],{},"java.util",") is what actually reads from it:",[104,14761,14763],{"className":106,"code":14762,"language":108,"meta":48,"style":48},"import java.io.*;\nimport java.util.*;\n\nFile configFile = new File(\"auto_config.csv\"); \u002F\u002F just a name — this line can't fail\nScanner scan = new Scanner(configFile); \u002F\u002F this line can throw FileNotFoundException\n",[95,14764,14765,14770,14775,14779,14784],{"__ignoreMap":48},[112,14766,14767],{"class":114,"line":115},[112,14768,14769],{},"import java.io.*;\n",[112,14771,14772],{"class":114,"line":49},[112,14773,14774],{},"import java.util.*;\n",[112,14776,14777],{"class":114,"line":126},[112,14778,907],{"emptyLinePlaceholder":55},[112,14780,14781],{"class":114,"line":132},[112,14782,14783],{},"File configFile = new File(\"auto_config.csv\"); \u002F\u002F just a name — this line can't fail\n",[112,14785,14786],{"class":114,"line":138},[112,14787,14788],{},"Scanner scan = new Scanner(configFile); \u002F\u002F this line can throw FileNotFoundException\n",[15,14790,14791,537,14794,14797,14798,176,14800,14803,14804,7903,14806,14803,14808,14810,14811,14814,14815,14818],{},[95,14792,14793],{},"import java.io.*;",[95,14795,14796],{},"import java.util.*;"," are wildcard imports (Ch.3.3) — they pull in every class from that package (",[95,14799,14748],{},[95,14801,14802],{},"IOException"," from ",[95,14805,14751],{},[95,14807,14755],{},[95,14809,14758],{},") instead of naming each one individually. A relative filename like ",[95,14812,14813],{},"\"auto_config.csv\""," is looked up relative to wherever the program is ",[494,14816,14817],{},"run"," from, not where the source file lives.",[15,14820,14821,14822,14825,14826,176,14829,14832,14833,14836,14837,14839,14840,1566],{},"Since opening a file can fail (wrong name, missing file), Java requires you to acknowledge that. The simplest way: add ",[95,14823,14824],{},"throws IOException"," to the method's header — if the file genuinely can't be found, the program terminates with an error instead of continuing silently. (",[95,14827,14828],{},"try",[95,14830,14831],{},"catch",", the alternative to ",[95,14834,14835],{},"throws",", is Ch.12's subject — including ",[95,14838,14828],{},"-with-resources, which can close the scanner automatically instead of a manual ",[95,14841,14842],{},"scan.close()",[104,14844,14846],{"className":106,"code":14845,"language":108,"meta":48,"style":48},"public static void main(String[] args) throws IOException\n{\n    File configFile = new File(\"auto_config.csv\");\n    Scanner scan = new Scanner(configFile);\n    \u002F\u002F ...\n    scan.close();\n}\n",[95,14847,14848,14853,14857,14862,14867,14872,14877],{"__ignoreMap":48},[112,14849,14850],{"class":114,"line":115},[112,14851,14852],{},"public static void main(String[] args) throws IOException\n",[112,14854,14855],{"class":114,"line":49},[112,14856,123],{},[112,14858,14859],{"class":114,"line":126},[112,14860,14861],{},"    File configFile = new File(\"auto_config.csv\");\n",[112,14863,14864],{"class":114,"line":132},[112,14865,14866],{},"    Scanner scan = new Scanner(configFile);\n",[112,14868,14869],{"class":114,"line":138},[112,14870,14871],{},"    \u002F\u002F ...\n",[112,14873,14874],{"class":114,"line":144},[112,14875,14876],{},"    scan.close();\n",[112,14878,14879],{"class":114,"line":150},[112,14880,153],{},[69,14882,14884],{"id":14883},"reading-line-by-line","Reading Line by Line",[104,14886,14888],{"className":106,"code":14887,"language":108,"meta":48,"style":48},"while (scan.hasNextLine())\n{\n    String line = scan.nextLine();\n    \u002F\u002F process this line\n}\nscan.close(); \u002F\u002F always close when done\n",[95,14889,14890,14895,14899,14904,14909,14913],{"__ignoreMap":48},[112,14891,14892],{"class":114,"line":115},[112,14893,14894],{},"while (scan.hasNextLine())\n",[112,14896,14897],{"class":114,"line":49},[112,14898,123],{},[112,14900,14901],{"class":114,"line":126},[112,14902,14903],{},"    String line = scan.nextLine();\n",[112,14905,14906],{"class":114,"line":132},[112,14907,14908],{},"    \u002F\u002F process this line\n",[112,14910,14911],{"class":114,"line":138},[112,14912,153],{},[112,14914,14915],{"class":114,"line":144},[112,14916,14917],{},"scan.close(); \u002F\u002F always close when done\n",[15,14919,14920,1291,14923,14925],{},[95,14921,14922],{},"hasNextLine()",[95,14924,661],{}," as long as there's another line to read — the standard loop condition for \"read until the file ends.\"",[69,14927,14929],{"id":14928},"splitting-a-csv-line","Splitting a CSV Line",[15,14931,14932,14933,14935,14936,14939,14940,14942],{},"A CSV (comma-separated values) file packs several fields into one line. ",[95,14934,361],{},"'s ",[95,14937,14938],{},"split(\",\")"," breaks a line into a ",[95,14941,9142],{}," around the commas:",[104,14944,14946],{"className":106,"code":14945,"language":108,"meta":48,"style":48},"\u002F\u002F One line of auto_config.csv: \"3-Piece-Left,14.2,BlueAlliance\"\nString line = scan.nextLine();\nString[] fields = line.split(\",\");\nString routeName = fields[0];       \u002F\u002F \"3-Piece-Left\"\ndouble routeTime = Double.parseDouble(fields[1]); \u002F\u002F \"14.2\" -> 14.2\nString alliance = fields[2];        \u002F\u002F \"BlueAlliance\"\n",[95,14947,14948,14953,14958,14963,14968,14973],{"__ignoreMap":48},[112,14949,14950],{"class":114,"line":115},[112,14951,14952],{},"\u002F\u002F One line of auto_config.csv: \"3-Piece-Left,14.2,BlueAlliance\"\n",[112,14954,14955],{"class":114,"line":49},[112,14956,14957],{},"String line = scan.nextLine();\n",[112,14959,14960],{"class":114,"line":126},[112,14961,14962],{},"String[] fields = line.split(\",\");\n",[112,14964,14965],{"class":114,"line":132},[112,14966,14967],{},"String routeName = fields[0];       \u002F\u002F \"3-Piece-Left\"\n",[112,14969,14970],{"class":114,"line":138},[112,14971,14972],{},"double routeTime = Double.parseDouble(fields[1]); \u002F\u002F \"14.2\" -> 14.2\n",[112,14974,14975],{"class":114,"line":144},[112,14976,14977],{},"String alliance = fields[2];        \u002F\u002F \"BlueAlliance\"\n",[15,14979,14980,176,14983,14986,14987,322,14989,14991],{},[95,14981,14982],{},"Integer.parseInt",[95,14984,14985],{},"Double.parseDouble"," convert text into a number — Ch.9.2 covers the wrapper classes (",[95,14988,1869],{},[95,14990,8536],{},") these belong to.",[69,14993,14995],{"id":14994},"reading-into-an-array-or-arraylist","Reading Into an Array or ArrayList",[15,14997,14998,14999,15001],{},"If you know the line count in advance, an array works; otherwise, ",[95,15000,12343],{}," (Ch.9.2) avoids needing to know the size up front:",[104,15003,15005],{"className":106,"code":15004,"language":108,"meta":48,"style":48},"ArrayList\u003CString> configLines = new ArrayList\u003CString>();\nwhile (scan.hasNextLine())\n{\n    configLines.add(scan.nextLine());\n}\n",[95,15006,15007,15012,15016,15020,15025],{"__ignoreMap":48},[112,15008,15009],{"class":114,"line":115},[112,15010,15011],{},"ArrayList\u003CString> configLines = new ArrayList\u003CString>();\n",[112,15013,15014],{"class":114,"line":49},[112,15015,14894],{},[112,15017,15018],{"class":114,"line":126},[112,15019,123],{},[112,15021,15022],{"class":114,"line":132},[112,15023,15024],{},"    configLines.add(scan.nextLine());\n",[112,15026,15027],{"class":114,"line":138},[112,15028,153],{},[69,15030,15032],{"id":15031},"reading-into-objects","Reading Into Objects",[15,15034,15035,15036,15038],{},"Rather than working with raw ",[95,15037,9142],{}," rows, define a class matching the file's columns and build one object per row — the same has-a\u002Fobject-per-record idea from Ch.7:",[104,15040,15042],{"className":106,"code":15041,"language":108,"meta":48,"style":48},"ArrayList\u003CAutoRoute> routes = new ArrayList\u003CAutoRoute>();\nwhile (scan.hasNextLine())\n{\n    String[] fields = scan.nextLine().split(\",\");\n    routes.add(new AutoRoute(fields[0], Double.parseDouble(fields[1]), fields[2]));\n}\n",[95,15043,15044,15049,15053,15057,15062,15067],{"__ignoreMap":48},[112,15045,15046],{"class":114,"line":115},[112,15047,15048],{},"ArrayList\u003CAutoRoute> routes = new ArrayList\u003CAutoRoute>();\n",[112,15050,15051],{"class":114,"line":49},[112,15052,14894],{},[112,15054,15055],{"class":114,"line":126},[112,15056,123],{},[112,15058,15059],{"class":114,"line":132},[112,15060,15061],{},"    String[] fields = scan.nextLine().split(\",\");\n",[112,15063,15064],{"class":114,"line":138},[112,15065,15066],{},"    routes.add(new AutoRoute(fields[0], Double.parseDouble(fields[1]), fields[2]));\n",[112,15068,15069],{"class":114,"line":144},[112,15070,153],{},[69,15072,462],{"id":461},[19,15074,15075,15083,15093,15103],{},[22,15076,15077,15082],{},[25,15078,4719,15079,15081],{},[95,15080,14824],{}," (or a try\u002Fcatch)."," Java won't compile file-reading code unless you've acknowledged that opening the file might fail.",[22,15084,15085,15092],{},[25,15086,15087,15088,15091],{},"Forgetting to ",[95,15089,15090],{},"close()"," the scanner."," A small leak that adds up in a program that opens many files.",[22,15094,15095,15098,15099,15102],{},[25,15096,15097],{},"Trying to parse a header row as data."," The first line of a CSV is often column names, not values — call ",[95,15100,15101],{},"scan.nextLine()"," once before the loop starts to discard it, rather than checking for it on every pass.",[22,15104,15105,15108,15109,15111],{},[25,15106,15107],{},"Assuming a relative filename resolves next to the source file."," It resolves relative to wherever the program is actually ",[494,15110,14817],{}," from, which isn't always the same folder.",[69,15113,501],{"id":500},[19,15115,15116,15131,15139,15150],{},[22,15117,15118,15120,15121,15123,15124,15127,15128,15130],{},[95,15119,14748],{}," just represents a filename and never throws; ",[95,15122,14755],{}," is what can throw (",[95,15125,15126],{},"FileNotFoundException",") when it actually tries to open that file — Java requires you to acknowledge that (",[95,15129,14824],{},", or try\u002Fcatch).",[22,15132,15133,15135,15136,15138],{},[95,15134,14922],{}," combined with a ",[95,15137,7977],{}," loop is the standard pattern for reading an entire file, line by line.",[22,15140,15141,15144,15145,176,15147,15149],{},[95,15142,15143],{},"String.split(\",\")"," breaks a CSV line into fields; ",[95,15146,14982],{},[95,15148,14985],{}," (Ch.9.2) convert a field's text into a number.",[22,15151,15152],{},"Reading rows into custom objects (one object per line) is cleaner than working with raw split arrays once the data has real structure.",[15,15154,544,15155,548,15157,15160],{},[95,15156,547],{},[95,15158,15159],{},"unit-4-data-collections\u002F4.06-using-text-files.md"," (CSA 4.6)",[554,15162,556],{},{"title":48,"searchDepth":49,"depth":49,"links":15164},[15165,15166,15167,15168,15169,15170,15171,15172],{"id":14735,"depth":49,"text":14736},{"id":14742,"depth":49,"text":14743},{"id":14883,"depth":49,"text":14884},{"id":14928,"depth":49,"text":14929},{"id":14994,"depth":49,"text":14995},{"id":15031,"depth":49,"text":15032},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":15174,"status":570},"9.8 — Using Text Files (CSA 4.6)","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F8-using-text-files",{"title":14727,"description":48},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.8-using-text-files","L8x4wy75y5rtXfri7fsrNJoSp9nFjlIjP0o56-G_rKw",{"id":15180,"title":15181,"body":15182,"description":48,"extension":51,"meta":15481,"navigation":55,"path":15484,"seo":15485,"stem":15486,"__hash__":15487},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F10.1-2d-array-creation-and-access.md","2D Array Creation and Access",{"type":8,"value":15183,"toc":15471},[15184,15187,15191,15194,15209,15236,15240,15243,15281,15288,15291,15306,15313,15317,15323,15338,15355,15359,15381,15390,15392,15430,15432,15461,15469],[11,15185,15181],{"id":15186},"_2d-array-creation-and-access",[69,15188,15190],{"id":15189},"why-2d","Why 2D",[15,15192,15193],{},"Some data is naturally rows-and-columns, not just a flat list. Swerve drive telemetry is a good example: 4 modules (front-left, front-right, back-left, back-right), each logging several current-draw samples over time. That's a 2D array — one row per module, one column per sample.",[104,15195,15197],{"className":106,"code":15196,"language":108,"meta":48,"style":48},"\u002F\u002F datatype[][] variableName = new datatype[numberRows][numberCols];\ndouble[][] moduleCurrents = new double[4][5]; \u002F\u002F 4 modules, 5 samples each\n",[95,15198,15199,15204],{"__ignoreMap":48},[112,15200,15201],{"class":114,"line":115},[112,15202,15203],{},"\u002F\u002F datatype[][] variableName = new datatype[numberRows][numberCols];\n",[112,15205,15206],{"class":114,"line":49},[112,15207,15208],{},"double[][] moduleCurrents = new double[4][5]; \u002F\u002F 4 modules, 5 samples each\n",[15,15210,15211,15212,217,15215,2150,15217,15220,15221,15223,15224,15226,15227,15229,15230,15232,15233,15235],{},"A 2D array variable works like any other reference type: declared as a ",[25,15213,15214],{},"field",[95,15216,2504],{},[95,15218,15219],{},"double[][] moduleCurrents;","), it defaults to ",[95,15222,4645],{},". Declared as a ",[25,15225,795],{},", Java won't even let you read it before it's assigned — that's a compile error (\"variable moduleCurrents might not have been initialized\"), not a ",[95,15228,4645],{},". Once created with ",[95,15231,2504],{},", every element starts at that type's default (",[95,15234,1369],{}," here); how Java actually stores the rows is covered below.",[69,15237,15239],{"id":15238},"initializer-lists","Initializer Lists",[15,15241,15242],{},"An initializer list for a 2D array is a list of 1D initializer lists, one per row — size is inferred:",[104,15244,15246],{"className":106,"code":15245,"language":108,"meta":48,"style":48},"double[][] moduleCurrents =\n{\n    {12.1, 11.8, 40.2, 12.4, 11.9}, \u002F\u002F front-left\n    {12.0, 11.9, 12.1, 11.7, 12.2}, \u002F\u002F front-right\n    {11.9, 12.3, 12.0, 11.8, 12.1}, \u002F\u002F back-left\n    {12.2, 12.0, 11.9, 12.4, 11.9}, \u002F\u002F back-right\n};\n",[95,15247,15248,15253,15257,15262,15267,15272,15277],{"__ignoreMap":48},[112,15249,15250],{"class":114,"line":115},[112,15251,15252],{},"double[][] moduleCurrents =\n",[112,15254,15255],{"class":114,"line":49},[112,15256,123],{},[112,15258,15259],{"class":114,"line":126},[112,15260,15261],{},"    {12.1, 11.8, 40.2, 12.4, 11.9}, \u002F\u002F front-left\n",[112,15263,15264],{"class":114,"line":132},[112,15265,15266],{},"    {12.0, 11.9, 12.1, 11.7, 12.2}, \u002F\u002F front-right\n",[112,15268,15269],{"class":114,"line":138},[112,15270,15271],{},"    {11.9, 12.3, 12.0, 11.8, 12.1}, \u002F\u002F back-left\n",[112,15273,15274],{"class":114,"line":144},[112,15275,15276],{},"    {12.2, 12.0, 11.9, 12.4, 11.9}, \u002F\u002F back-right\n",[112,15278,15279],{"class":114,"line":150},[112,15280,6261],{},[69,15282,15284,15285],{"id":15283},"accessing-elements-arrrowcol","Accessing Elements: ",[95,15286,15287],{},"arr[row][col]",[15,15289,15290],{},"The first index is the row, the second is the column:",[104,15292,15294],{"className":106,"code":15293,"language":108,"meta":48,"style":48},"double spike = moduleCurrents[0][2]; \u002F\u002F front-left module, 3rd sample -> 40.2\nmoduleCurrents[0][2] = 0.0;          \u002F\u002F overwrite a bad reading\n",[95,15295,15296,15301],{"__ignoreMap":48},[112,15297,15298],{"class":114,"line":115},[112,15299,15300],{},"double spike = moduleCurrents[0][2]; \u002F\u002F front-left module, 3rd sample -> 40.2\n",[112,15302,15303],{"class":114,"line":49},[112,15304,15305],{},"moduleCurrents[0][2] = 0.0;          \u002F\u002F overwrite a bad reading\n",[15,15307,15308,15309,15312],{},"Printing a 2D array directly (",[95,15310,15311],{},"System.out.println(moduleCurrents)",") just prints its object reference, not its contents — printing every value takes nested loops (Lesson 10.2).",[69,15314,15316],{"id":15315},"row-and-column-counts","Row and Column Counts",[15,15318,15319,15320,15322],{},"The number of rows is ",[95,15321,12755],{},"; the number of columns is the length of any one row (AP CSA — and this curriculum — assumes every row has the same length, i.e. the array is rectangular, not \"ragged\"):",[104,15324,15326],{"className":106,"code":15325,"language":108,"meta":48,"style":48},"moduleCurrents.length     \u002F\u002F 4  (number of modules \u002F rows)\nmoduleCurrents[0].length  \u002F\u002F 5  (samples per module \u002F columns)\n",[95,15327,15328,15333],{"__ignoreMap":48},[112,15329,15330],{"class":114,"line":115},[112,15331,15332],{},"moduleCurrents.length     \u002F\u002F 4  (number of modules \u002F rows)\n",[112,15334,15335],{"class":114,"line":49},[112,15336,15337],{},"moduleCurrents[0].length  \u002F\u002F 5  (samples per module \u002F columns)\n",[15,15339,15340,15341,4029,15343,15345,15346,4029,15348,15351,15352,15354],{},"Valid row indices: ",[95,15342,1365],{},[95,15344,12099],{},". Valid column indices: ",[95,15347,1365],{},[95,15349,15350],{},"arr[0].length - 1",". An out-of-range index in either dimension throws ",[95,15353,12136],{},", same as a 1D array.",[69,15356,15358],{"id":15357},"java-stores-it-as-an-array-of-arrays","Java Stores It as an Array of Arrays",[15,15360,15361,15362,15365,15366,15368,15369,15372,15373,15376,15377,15380],{},"Internally, ",[95,15363,15364],{},"moduleCurrents"," is one 4-element outer array, where each element is a ",[494,15367,1475],{}," to its own separate 5-element inner array — not one giant contiguous block. That's why ",[95,15370,15371],{},"moduleCurrents[0]"," alone is a valid expression: it's a real, complete ",[95,15374,15375],{},"double[]"," (front-left's row), which is what makes ",[95,15378,15379],{},"moduleCurrents[0].length"," work.",[104,15382,15384],{"className":106,"code":15383,"language":108,"meta":48,"style":48},"double[] frontLeftRow = moduleCurrents[0]; \u002F\u002F a single row IS a real 1D array on its own\n",[95,15385,15386],{"__ignoreMap":48},[112,15387,15388],{"class":114,"line":115},[112,15389,15383],{},[69,15391,462],{"id":461},[19,15393,15394,15406,15415],{},[22,15395,15396,476,15399,15402,15403,15405],{},[25,15397,15398],{},"Swapping row and column.",[95,15400,15401],{},"moduleCurrents[2][0]"," is back-left's ",[494,15404,4161],{}," sample, not front-left's third — the first index is always the row.",[22,15407,15408,15414],{},[25,15409,1608,15410,15413],{},[95,15411,15412],{},"new double[4][5]"," gives usable data."," It gives 20 zeros, not real readings — same default-value rule as 1D arrays.",[22,15416,15417,15422,15423,15426,15427,79],{},[25,15418,15419,15420,79],{},"Off-by-one against ",[95,15421,12755],{}," The last valid row index is ",[95,15424,15425],{},"moduleCurrents.length - 1","; the last valid column index is ",[95,15428,15429],{},"moduleCurrents[0].length - 1",[69,15431,501],{"id":500},[19,15433,15434,15441,15446,15458],{},[22,15435,15436,15437,15440],{},"A 2D array is declared\u002Fcreated as ",[95,15438,15439],{},"datatype[][] name = new datatype[rows][cols];",", or filled in one step with a nested initializer list (one inner list per row).",[22,15442,15443,15445],{},[95,15444,15287],{}," reads or writes one element; the first index is always the row, the second the column.",[22,15447,15448,15450,15451,15453,15454,15457],{},[95,15449,12755],{}," gives the row count; ",[95,15452,12755],{}," on any one row (e.g. ",[95,15455,15456],{},"arr[0].length",") gives the column count.",[22,15459,15460],{},"Java implements a 2D array as an array of arrays — each row is itself a real, independent 1D array.",[15,15462,544,15463,548,15465,15468],{},[95,15464,547],{},[95,15466,15467],{},"unit-4-data-collections\u002F4.11-2d-array-creation-and-access.md"," (CSA 4.11)",[554,15470,556],{},{"title":48,"searchDepth":49,"depth":49,"links":15472},[15473,15474,15475,15477,15478,15479,15480],{"id":15189,"depth":49,"text":15190},{"id":15238,"depth":49,"text":15239},{"id":15283,"depth":49,"text":15476},"Accessing Elements: arr[row][col]",{"id":15315,"depth":49,"text":15316},{"id":15357,"depth":49,"text":15358},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":15482,"status":15483},"10.1 — 2D Array Creation and Access (CSA 4.11)","new — authored lesson","\u002Fshockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F1-2d-array-creation-and-access",{"title":15181,"description":48},"shockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F10.1-2d-array-creation-and-access","qCwrLez1EW2sKxmjO2NU3oudBHLgJJ5bJwfBCmjki0U",{"id":15489,"title":15490,"body":15491,"description":48,"extension":51,"meta":15841,"navigation":55,"path":15843,"seo":15844,"stem":15845,"__hash__":15846},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F10.2-2d-array-traversals-nested-loops.md","2D Array Traversals: Nested Loops",{"type":8,"value":15492,"toc":15833},[15493,15496,15500,15503,15544,15558,15562,15569,15651,15654,15658,15661,15697,15710,15714,15728,15769,15771,15805,15807,15823,15831],[11,15494,15490],{"id":15495},"_2d-array-traversals-nested-loops",[69,15497,15499],{"id":15498},"nested-loops","Nested Loops",[15,15501,15502],{},"Since a 2D array is really an array of arrays, traversing every element takes a loop inside a loop — the outer loop walks the rows, the inner loop walks the columns of whichever row the outer loop is currently on:",[104,15504,15506],{"className":106,"code":15505,"language":108,"meta":48,"style":48},"double[][] moduleCurrents = { {12.1, 11.8, 40.2}, {12.0, 11.9, 12.1} };\nfor (int row = 0; row \u003C moduleCurrents.length; row++)\n{\n    for (int col = 0; col \u003C moduleCurrents[0].length; col++)\n    {\n        System.out.println(moduleCurrents[row][col]);\n    }\n}\n",[95,15507,15508,15513,15518,15522,15527,15531,15536,15540],{"__ignoreMap":48},[112,15509,15510],{"class":114,"line":115},[112,15511,15512],{},"double[][] moduleCurrents = { {12.1, 11.8, 40.2}, {12.0, 11.9, 12.1} };\n",[112,15514,15515],{"class":114,"line":49},[112,15516,15517],{},"for (int row = 0; row \u003C moduleCurrents.length; row++)\n",[112,15519,15520],{"class":114,"line":126},[112,15521,123],{},[112,15523,15524],{"class":114,"line":132},[112,15525,15526],{},"    for (int col = 0; col \u003C moduleCurrents[0].length; col++)\n",[112,15528,15529],{"class":114,"line":138},[112,15530,135],{},[112,15532,15533],{"class":114,"line":144},[112,15534,15535],{},"        System.out.println(moduleCurrents[row][col]);\n",[112,15537,15538],{"class":114,"line":150},[112,15539,147],{},[112,15541,15542],{"class":114,"line":2276},[112,15543,153],{},[15,15545,15546,15547,15550,15551,15554,15555,15557],{},"The loop body runs ",[95,15548,15549],{},"rows × columns"," times total. ",[95,15552,15553],{},"moduleCurrents.length"," is the row bound; ",[95,15556,15379],{}," is the column bound (safe here because the array is rectangular — every row has the same length).",[69,15559,15561],{"id":15560},"row-major-vs-column-major","Row-Major vs. Column-Major",[15,15563,15564,15565,15568],{},"Which index changes in the ",[494,15566,15567],{},"outer"," loop decides the traversal order:",[104,15570,15572],{"className":106,"code":15571,"language":108,"meta":48,"style":48},"\u002F\u002F Row-major: finish one module's samples before moving to the next module\nfor (int row = 0; row \u003C moduleCurrents.length; row++)\n{\n    for (int col = 0; col \u003C moduleCurrents[0].length; col++)\n    {\n        \u002F\u002F stand-in for whatever this pass needs to do\n        System.out.println(moduleCurrents[row][col]);\n    }\n}\n\n\u002F\u002F Column-major: sample #0 across every module, then sample #1, and so on\nfor (int col = 0; col \u003C moduleCurrents[0].length; col++)\n{\n    for (int row = 0; row \u003C moduleCurrents.length; row++)\n    {\n        System.out.println(moduleCurrents[row][col]);\n    }\n}\n",[95,15573,15574,15579,15583,15587,15591,15595,15600,15604,15608,15612,15616,15621,15626,15630,15635,15639,15643,15647],{"__ignoreMap":48},[112,15575,15576],{"class":114,"line":115},[112,15577,15578],{},"\u002F\u002F Row-major: finish one module's samples before moving to the next module\n",[112,15580,15581],{"class":114,"line":49},[112,15582,15517],{},[112,15584,15585],{"class":114,"line":126},[112,15586,123],{},[112,15588,15589],{"class":114,"line":132},[112,15590,15526],{},[112,15592,15593],{"class":114,"line":138},[112,15594,135],{},[112,15596,15597],{"class":114,"line":144},[112,15598,15599],{},"        \u002F\u002F stand-in for whatever this pass needs to do\n",[112,15601,15602],{"class":114,"line":150},[112,15603,15535],{},[112,15605,15606],{"class":114,"line":2276},[112,15607,147],{},[112,15609,15610],{"class":114,"line":2282},[112,15611,153],{},[112,15613,15614],{"class":114,"line":2288},[112,15615,907],{"emptyLinePlaceholder":55},[112,15617,15618],{"class":114,"line":5760},[112,15619,15620],{},"\u002F\u002F Column-major: sample #0 across every module, then sample #1, and so on\n",[112,15622,15623],{"class":114,"line":5766},[112,15624,15625],{},"for (int col = 0; col \u003C moduleCurrents[0].length; col++)\n",[112,15627,15628],{"class":114,"line":5772},[112,15629,123],{},[112,15631,15632],{"class":114,"line":5777},[112,15633,15634],{},"    for (int row = 0; row \u003C moduleCurrents.length; row++)\n",[112,15636,15637],{"class":114,"line":5783},[112,15638,135],{},[112,15640,15641],{"class":114,"line":5789},[112,15642,15535],{},[112,15644,15645],{"class":114,"line":5794},[112,15646,147],{},[112,15648,15649],{"class":114,"line":10057},[112,15650,153],{},[15,15652,15653],{},"Row-major is the natural choice for \"how did this one module behave over time.\" Column-major is the natural choice for \"what was total robot current draw at this one instant\" — e.g. checking whether all 4 modules spiked simultaneously (a brownout risk), which row-major order would never surface directly.",[69,15655,15657],{"id":15656},"enhanced-for-each-nested","Enhanced For-Each, Nested",[15,15659,15660],{},"A nested for-each also traverses a 2D array, with no indices — but only when you don't need row\u002Fcolumn numbers or in-place modification of primitive values:",[104,15662,15664],{"className":106,"code":15663,"language":108,"meta":48,"style":48},"for (double[] moduleRow : moduleCurrents)  \u002F\u002F outer variable is a 1D array — one row\n{\n    for (double sample : moduleRow)        \u002F\u002F inner variable matches the element type\n    {\n        System.out.println(sample);\n    }\n}\n",[95,15665,15666,15671,15675,15680,15684,15689,15693],{"__ignoreMap":48},[112,15667,15668],{"class":114,"line":115},[112,15669,15670],{},"for (double[] moduleRow : moduleCurrents)  \u002F\u002F outer variable is a 1D array — one row\n",[112,15672,15673],{"class":114,"line":49},[112,15674,123],{},[112,15676,15677],{"class":114,"line":126},[112,15678,15679],{},"    for (double sample : moduleRow)        \u002F\u002F inner variable matches the element type\n",[112,15681,15682],{"class":114,"line":132},[112,15683,135],{},[112,15685,15686],{"class":114,"line":138},[112,15687,15688],{},"        System.out.println(sample);\n",[112,15690,15691],{"class":114,"line":144},[112,15692,147],{},[112,15694,15695],{"class":114,"line":150},[112,15696,153],{},[15,15698,15699,15700,15702,15703,15706,15707,15709],{},"Pattern to remember: the ",[25,15701,15567],{}," loop variable is typed as a 1D array (a whole row); the ",[25,15704,15705],{},"inner"," loop variable is typed as one element. As with 1D for-each (Lesson 9.4), reassigning ",[95,15708,8431],{}," inside the loop does not change what's stored in the array.",[69,15711,15713],{"id":15712},"_2d-arrays-of-objects-are-different","2D Arrays of Objects Are Different",[15,15715,15716,15717,15720,15721,15723,15724,15727],{},"The for-each modification limit above is about ",[494,15718,15719],{},"primitives",". A 2D array of objects — like a grid of ",[95,15722,4333],{}," objects (the team's own motor class, Lesson 4.4), or a vision system's ",[95,15725,15726],{},"Pixel[][]"," — can still have its objects mutated through a for-each loop, because you're calling a method on the object the loop variable refers to, not reassigning the array slot itself:",[104,15729,15731],{"className":106,"code":15730,"language":108,"meta":48,"style":48},"\u002F\u002F driveMotors is a DriveMotor[][], one row per swerve module\nfor (DriveMotor[] moduleRow : driveMotors)\n{\n    for (DriveMotor motor : moduleRow)\n    {\n        motor.setThrottle(0.0); \u002F\u002F mutates the real object — this works\n    }\n}\n",[95,15732,15733,15738,15743,15747,15752,15756,15761,15765],{"__ignoreMap":48},[112,15734,15735],{"class":114,"line":115},[112,15736,15737],{},"\u002F\u002F driveMotors is a DriveMotor[][], one row per swerve module\n",[112,15739,15740],{"class":114,"line":49},[112,15741,15742],{},"for (DriveMotor[] moduleRow : driveMotors)\n",[112,15744,15745],{"class":114,"line":126},[112,15746,123],{},[112,15748,15749],{"class":114,"line":132},[112,15750,15751],{},"    for (DriveMotor motor : moduleRow)\n",[112,15753,15754],{"class":114,"line":138},[112,15755,135],{},[112,15757,15758],{"class":114,"line":144},[112,15759,15760],{},"        motor.setThrottle(0.0); \u002F\u002F mutates the real object — this works\n",[112,15762,15763],{"class":114,"line":150},[112,15764,147],{},[112,15766,15767],{"class":114,"line":2276},[112,15768,153],{},[69,15770,462],{"id":461},[19,15772,15773,15790,15799],{},[22,15774,15775,15780,15781,15784,15785,959,15787,15789],{},[25,15776,6835,15777,15779],{},[95,15778,15553],{}," as the inner loop's bound."," The inner loop walks ",[494,15782,15783],{},"columns",", so its bound is ",[95,15786,15379],{},[95,15788,15553],{}," (the row count).",[22,15791,15792,476,15795,15798],{},[25,15793,15794],{},"Expecting for-each to let you assign into a primitive 2D array.",[95,15796,15797],{},"for (double sample : moduleRow) { sample = 0.0; }"," changes nothing — same rule as 1D arrays.",[22,15800,15801,15804],{},[25,15802,15803],{},"Confusing row-major and column-major with \"correct\" and \"incorrect.\""," Neither is wrong — pick whichever matches what the question actually asks (per-module trends vs. per-instant totals).",[69,15806,501],{"id":500},[19,15808,15809,15812,15815,15818],{},[22,15810,15811],{},"Traversing a full 2D array needs nested loops: outer for rows, inner for columns.",[22,15813,15814],{},"Row-major order finishes one row before moving to the next; column-major order finishes one column (across all rows) before moving to the next — which one to use depends on what you're computing.",[22,15816,15817],{},"A nested for-each loop traverses a 2D array with no indices; its outer variable is a 1D array (one row), its inner variable matches the element type.",[22,15819,15820,15821,4410],{},"For-each can't modify a primitive 2D array's stored values, but it can call mutator methods on objects the array holds (like ",[95,15822,4333],{},[15,15824,544,15825,548,15827,15830],{},[95,15826,547],{},[95,15828,15829],{},"unit-4-data-collections\u002F4.12-2d-array-traversals-nested-loops.md"," (CSA 4.12)",[554,15832,556],{},{"title":48,"searchDepth":49,"depth":49,"links":15834},[15835,15836,15837,15838,15839,15840],{"id":15498,"depth":49,"text":15499},{"id":15560,"depth":49,"text":15561},{"id":15656,"depth":49,"text":15657},{"id":15712,"depth":49,"text":15713},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":15842,"status":15483},"10.2 — 2D Array Traversals: Nested Loops (CSA 4.12)","\u002Fshockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F2-2d-array-traversals-nested-loops",{"title":15490,"description":48},"shockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F10.2-2d-array-traversals-nested-loops","oU5dJYfzE9a3ObYozu189vvr9glVKRFI5nanSKXW8_0",{"id":15848,"title":15849,"body":15850,"description":15857,"extension":51,"meta":16489,"navigation":55,"path":16491,"seo":16492,"stem":16493,"__hash__":16494},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F10.3-implementing-2d-array-algorithms.md","Implementing 2D Array Algorithms",{"type":8,"value":15851,"toc":16480},[15852,15855,15858,15862,15950,15960,15964,16037,16043,16047,16050,16127,16131,16140,16245,16255,16259,16265,16376,16378,16451,16453,16470,16478],[11,15853,15849],{"id":15854},"implementing-2d-array-algorithms",[15,15856,15857],{},"Every algorithm shape from Lesson 9.5 (sum\u002Faverage, min\u002Fmax, property checks, duplicates) extends to 2D arrays — applied to the whole grid, or to just one row, one column, or a subsection.",[69,15859,15861],{"id":15860},"sum-a-row-sum-a-column","Sum a Row, Sum a Column",[104,15863,15865],{"className":106,"code":15864,"language":108,"meta":48,"style":48},"public static double getTotalForModule(int row, double[][] a)\n{\n    double total = 0;\n    for (int col = 0; col \u003C a[0].length; col++)\n    {\n        total = total + a[row][col];\n    }\n    return total;\n}\n\npublic static double getTotalForSample(int col, double[][] a)\n{\n    double total = 0;\n    for (int row = 0; row \u003C a.length; row++)\n    {\n        total = total + a[row][col];\n    }\n    return total;\n}\n",[95,15866,15867,15872,15876,15881,15886,15890,15895,15899,15904,15908,15912,15917,15921,15925,15930,15934,15938,15942,15946],{"__ignoreMap":48},[112,15868,15869],{"class":114,"line":115},[112,15870,15871],{},"public static double getTotalForModule(int row, double[][] a)\n",[112,15873,15874],{"class":114,"line":49},[112,15875,123],{},[112,15877,15878],{"class":114,"line":126},[112,15879,15880],{},"    double total = 0;\n",[112,15882,15883],{"class":114,"line":132},[112,15884,15885],{},"    for (int col = 0; col \u003C a[0].length; col++)\n",[112,15887,15888],{"class":114,"line":138},[112,15889,135],{},[112,15891,15892],{"class":114,"line":144},[112,15893,15894],{},"        total = total + a[row][col];\n",[112,15896,15897],{"class":114,"line":150},[112,15898,147],{},[112,15900,15901],{"class":114,"line":2276},[112,15902,15903],{},"    return total;\n",[112,15905,15906],{"class":114,"line":2282},[112,15907,153],{},[112,15909,15910],{"class":114,"line":2288},[112,15911,907],{"emptyLinePlaceholder":55},[112,15913,15914],{"class":114,"line":5760},[112,15915,15916],{},"public static double getTotalForSample(int col, double[][] a)\n",[112,15918,15919],{"class":114,"line":5766},[112,15920,123],{},[112,15922,15923],{"class":114,"line":5772},[112,15924,15880],{},[112,15926,15927],{"class":114,"line":5777},[112,15928,15929],{},"    for (int row = 0; row \u003C a.length; row++)\n",[112,15931,15932],{"class":114,"line":5783},[112,15933,135],{},[112,15935,15936],{"class":114,"line":5789},[112,15937,15894],{},[112,15939,15940],{"class":114,"line":5794},[112,15941,147],{},[112,15943,15944],{"class":114,"line":10057},[112,15945,15903],{},[112,15947,15948],{"class":114,"line":10062},[112,15949,153],{},[15,15951,15952,15955,15956,15959],{},[95,15953,15954],{},"getTotalForModule"," sums one module's row across all samples; ",[95,15957,15958],{},"getTotalForSample"," sums one instant's column across all 4 modules (useful for spotting a simultaneous-spike brownout).",[69,15961,15963],{"id":15962},"max-across-the-whole-array","Max Across the Whole Array",[104,15965,15967],{"className":106,"code":15966,"language":108,"meta":48,"style":48},"public static double getPeakCurrent(double[][] a)\n{\n    double peak = a[0][0];\n    for (int row = 0; row \u003C a.length; row++)\n    {\n        for (int col = 0; col \u003C a[0].length; col++)\n        {\n            if (a[row][col] > peak)\n            {\n                peak = a[row][col];\n            }\n        }\n    }\n    return peak;\n}\n",[95,15968,15969,15974,15978,15983,15987,15991,15996,16000,16005,16010,16015,16020,16024,16028,16033],{"__ignoreMap":48},[112,15970,15971],{"class":114,"line":115},[112,15972,15973],{},"public static double getPeakCurrent(double[][] a)\n",[112,15975,15976],{"class":114,"line":49},[112,15977,123],{},[112,15979,15980],{"class":114,"line":126},[112,15981,15982],{},"    double peak = a[0][0];\n",[112,15984,15985],{"class":114,"line":132},[112,15986,15929],{},[112,15988,15989],{"class":114,"line":138},[112,15990,135],{},[112,15992,15993],{"class":114,"line":144},[112,15994,15995],{},"        for (int col = 0; col \u003C a[0].length; col++)\n",[112,15997,15998],{"class":114,"line":150},[112,15999,11303],{},[112,16001,16002],{"class":114,"line":2276},[112,16003,16004],{},"            if (a[row][col] > peak)\n",[112,16006,16007],{"class":114,"line":2282},[112,16008,16009],{},"            {\n",[112,16011,16012],{"class":114,"line":2288},[112,16013,16014],{},"                peak = a[row][col];\n",[112,16016,16017],{"class":114,"line":5760},[112,16018,16019],{},"            }\n",[112,16021,16022],{"class":114,"line":5766},[112,16023,11313],{},[112,16025,16026],{"class":114,"line":5772},[112,16027,147],{},[112,16029,16030],{"class":114,"line":5777},[112,16031,16032],{},"    return peak;\n",[112,16034,16035],{"class":114,"line":5783},[112,16036,153],{},[15,16038,16039,16040,16042],{},"Same seed-with-the-first-real-value rule from Lesson 9.5 — seeding with ",[95,16041,1365],{}," would be wrong if every reading happened to be negative.",[69,16044,16046],{"id":16045},"a-subsection-only","A Subsection Only",[15,16048,16049],{},"Loop bounds don't have to cover the whole array — narrowing them checks just a range of rows\u002Fcolumns, e.g. counting how many samples in a given module range exceeded a spike threshold:",[104,16051,16053],{"className":106,"code":16052,"language":108,"meta":48,"style":48},"public static int countSpikes(double threshold, double[][] a,\n                               int rowStart, int rowEnd, int colStart, int colEnd)\n{\n    int count = 0;\n    for (int row = rowStart; row \u003C= rowEnd; row++)\n    {\n        for (int col = colStart; col \u003C= colEnd; col++)\n        {\n            if (a[row][col] > threshold)\n            {\n                count++;\n            }\n        }\n    }\n    return count;\n}\n",[95,16054,16055,16060,16065,16069,16074,16079,16083,16088,16092,16097,16101,16106,16110,16114,16118,16123],{"__ignoreMap":48},[112,16056,16057],{"class":114,"line":115},[112,16058,16059],{},"public static int countSpikes(double threshold, double[][] a,\n",[112,16061,16062],{"class":114,"line":49},[112,16063,16064],{},"                               int rowStart, int rowEnd, int colStart, int colEnd)\n",[112,16066,16067],{"class":114,"line":126},[112,16068,123],{},[112,16070,16071],{"class":114,"line":132},[112,16072,16073],{},"    int count = 0;\n",[112,16075,16076],{"class":114,"line":138},[112,16077,16078],{},"    for (int row = rowStart; row \u003C= rowEnd; row++)\n",[112,16080,16081],{"class":114,"line":144},[112,16082,135],{},[112,16084,16085],{"class":114,"line":150},[112,16086,16087],{},"        for (int col = colStart; col \u003C= colEnd; col++)\n",[112,16089,16090],{"class":114,"line":2276},[112,16091,11303],{},[112,16093,16094],{"class":114,"line":2282},[112,16095,16096],{},"            if (a[row][col] > threshold)\n",[112,16098,16099],{"class":114,"line":2288},[112,16100,16009],{},[112,16102,16103],{"class":114,"line":5760},[112,16104,16105],{},"                count++;\n",[112,16107,16108],{"class":114,"line":5766},[112,16109,16019],{},[112,16111,16112],{"class":114,"line":5772},[112,16113,11313],{},[112,16115,16116],{"class":114,"line":5777},[112,16117,147],{},[112,16119,16120],{"class":114,"line":5783},[112,16121,16122],{},"    return count;\n",[112,16124,16125],{"class":114,"line":5789},[112,16126,153],{},[69,16128,16130],{"id":16129},"duplicates-need-4-nested-loops","Duplicates Need 4 Nested Loops",[15,16132,16133,16134,16136,16137,16139],{},"A 1D duplicate check needs 2 nested loops (Lesson 9.5). A full 2D duplicate check needs ",[25,16135,1757],{},": two to pick a starting cell (row, col), and two more to compare it against every cell that comes ",[494,16138,8135],{}," it — later columns in the same row, plus every cell in every later row:",[104,16141,16143],{"className":106,"code":16142,"language":108,"meta":48,"style":48},"public static boolean hasDuplicateReading(double[][] a)\n{\n    for (int row = 0; row \u003C a.length; row++)\n    {\n        for (int col = 0; col \u003C a[0].length; col++)\n        {\n            for (int row2 = row; row2 \u003C a.length; row2++)\n            {\n                \u002F\u002F ?: is the conditional operator, Lesson 5.5\n                int startCol = (row2 == row) ? col + 1 : 0;\n                for (int col2 = startCol; col2 \u003C a[0].length; col2++)\n                {\n                    if (a[row][col] == a[row2][col2])\n                    {\n                        return true;\n                    }\n                }\n            }\n        }\n    }\n    return false;\n}\n",[95,16144,16145,16150,16154,16158,16162,16166,16170,16175,16179,16184,16189,16194,16199,16204,16209,16214,16219,16224,16228,16232,16236,16241],{"__ignoreMap":48},[112,16146,16147],{"class":114,"line":115},[112,16148,16149],{},"public static boolean hasDuplicateReading(double[][] a)\n",[112,16151,16152],{"class":114,"line":49},[112,16153,123],{},[112,16155,16156],{"class":114,"line":126},[112,16157,15929],{},[112,16159,16160],{"class":114,"line":132},[112,16161,135],{},[112,16163,16164],{"class":114,"line":138},[112,16165,15995],{},[112,16167,16168],{"class":114,"line":144},[112,16169,11303],{},[112,16171,16172],{"class":114,"line":150},[112,16173,16174],{},"            for (int row2 = row; row2 \u003C a.length; row2++)\n",[112,16176,16177],{"class":114,"line":2276},[112,16178,16009],{},[112,16180,16181],{"class":114,"line":2282},[112,16182,16183],{},"                \u002F\u002F ?: is the conditional operator, Lesson 5.5\n",[112,16185,16186],{"class":114,"line":2288},[112,16187,16188],{},"                int startCol = (row2 == row) ? col + 1 : 0;\n",[112,16190,16191],{"class":114,"line":5760},[112,16192,16193],{},"                for (int col2 = startCol; col2 \u003C a[0].length; col2++)\n",[112,16195,16196],{"class":114,"line":5766},[112,16197,16198],{},"                {\n",[112,16200,16201],{"class":114,"line":5772},[112,16202,16203],{},"                    if (a[row][col] == a[row2][col2])\n",[112,16205,16206],{"class":114,"line":5777},[112,16207,16208],{},"                    {\n",[112,16210,16211],{"class":114,"line":5783},[112,16212,16213],{},"                        return true;\n",[112,16215,16216],{"class":114,"line":5789},[112,16217,16218],{},"                    }\n",[112,16220,16221],{"class":114,"line":5794},[112,16222,16223],{},"                }\n",[112,16225,16226],{"class":114,"line":10057},[112,16227,16019],{},[112,16229,16230],{"class":114,"line":10062},[112,16231,11313],{},[112,16233,16234],{"class":114,"line":13813},[112,16235,147],{},[112,16237,16238],{"class":114,"line":13818},[112,16239,16240],{},"    return false;\n",[112,16242,16243],{"class":114,"line":13824},[112,16244,153],{},[15,16246,2424,16247,16250,16251,16254],{},[95,16248,16249],{},"startCol"," trick avoids comparing a pair twice: within the same row (",[95,16252,16253],{},"row2 == row","), only look at columns after the candidate's own column; in a later row, every column is fair game.",[69,16256,16258],{"id":16257},"rotatereverse-a-single-row-or-column","Rotate\u002FReverse a Single Row or Column",[15,16260,16261,16262,16264],{},"Working on just one row (or one \"virtual column\" — a fixed column index across every row) really only touches one 1D array at a time, so the Ch.9 patterns carry over directly: rotating works like Lesson 9.7's ",[95,16263,12343],{}," rotate (shift each element into the next slot, then wrap the last one around to the front); reversing works like Lesson 9.5's swap-from-both-ends.",[104,16266,16268],{"className":106,"code":16267,"language":108,"meta":48,"style":48},"public static void rotateRowRight(double[][] a, int row)\n{\n    double last = a[row][a[0].length - 1];\n    for (int col = a[0].length - 1; col > 0; col--)\n    {\n        a[row][col] = a[row][col - 1];\n    }\n    a[row][0] = last;\n}\n\npublic static void reverseRow(double[][] a, int row)\n{\n    int left = 0;\n    int right = a[0].length - 1;\n    while (left \u003C right)\n    {\n        double temp = a[row][left];\n        a[row][left] = a[row][right];\n        a[row][right] = temp;\n        left++;\n        right--;\n    }\n}\n",[95,16269,16270,16275,16279,16284,16289,16293,16298,16302,16307,16311,16315,16320,16324,16329,16334,16339,16343,16348,16353,16358,16363,16368,16372],{"__ignoreMap":48},[112,16271,16272],{"class":114,"line":115},[112,16273,16274],{},"public static void rotateRowRight(double[][] a, int row)\n",[112,16276,16277],{"class":114,"line":49},[112,16278,123],{},[112,16280,16281],{"class":114,"line":126},[112,16282,16283],{},"    double last = a[row][a[0].length - 1];\n",[112,16285,16286],{"class":114,"line":132},[112,16287,16288],{},"    for (int col = a[0].length - 1; col > 0; col--)\n",[112,16290,16291],{"class":114,"line":138},[112,16292,135],{},[112,16294,16295],{"class":114,"line":144},[112,16296,16297],{},"        a[row][col] = a[row][col - 1];\n",[112,16299,16300],{"class":114,"line":150},[112,16301,147],{},[112,16303,16304],{"class":114,"line":2276},[112,16305,16306],{},"    a[row][0] = last;\n",[112,16308,16309],{"class":114,"line":2282},[112,16310,153],{},[112,16312,16313],{"class":114,"line":2288},[112,16314,907],{"emptyLinePlaceholder":55},[112,16316,16317],{"class":114,"line":5760},[112,16318,16319],{},"public static void reverseRow(double[][] a, int row)\n",[112,16321,16322],{"class":114,"line":5766},[112,16323,123],{},[112,16325,16326],{"class":114,"line":5772},[112,16327,16328],{},"    int left = 0;\n",[112,16330,16331],{"class":114,"line":5777},[112,16332,16333],{},"    int right = a[0].length - 1;\n",[112,16335,16336],{"class":114,"line":5783},[112,16337,16338],{},"    while (left \u003C right)\n",[112,16340,16341],{"class":114,"line":5789},[112,16342,135],{},[112,16344,16345],{"class":114,"line":5794},[112,16346,16347],{},"        double temp = a[row][left];\n",[112,16349,16350],{"class":114,"line":10057},[112,16351,16352],{},"        a[row][left] = a[row][right];\n",[112,16354,16355],{"class":114,"line":10062},[112,16356,16357],{},"        a[row][right] = temp;\n",[112,16359,16360],{"class":114,"line":13813},[112,16361,16362],{},"        left++;\n",[112,16364,16365],{"class":114,"line":13818},[112,16366,16367],{},"        right--;\n",[112,16369,16370],{"class":114,"line":13824},[112,16371,147],{},[112,16373,16374],{"class":114,"line":13830},[112,16375,153],{},[69,16377,462],{"id":461},[19,16379,16380,16397,16429],{},[22,16381,16382,16385,16386,16388,16389,16391,16392,16388,16394,16396],{},[25,16383,16384],{},"Confusing \"sum a row\" with \"sum a column.\""," Fixing ",[95,16387,5433],{}," and looping ",[95,16390,5437],{}," sums a row; fixing ",[95,16393,5437],{},[95,16395,5433],{}," sums a column — it's easy to write the wrong one by habit.",[22,16398,16399,16405,16406,16409,16410,16412,16413,16416,16417,537,16419,16422,16423,845,16425,16428],{},[25,16400,16401,16402,16404],{},"Forgetting the duplicate check's ",[95,16403,16249],{}," trick."," Without it, ",[95,16407,16408],{},"col2"," always starts at ",[95,16411,1365],{},", so the innermost comparison hits ",[95,16414,16415],{},"a[row][col] == a[row2][col2]"," with ",[95,16418,16253],{},[95,16420,16421],{},"col2 == col"," — a cell compared to itself — which is always ",[95,16424,661],{},[95,16426,16427],{},"hasDuplicateReading"," would report a duplicate on every array, even ones with none.",[22,16430,16431,476,16438,14935,16441,176,16444,16447,16448,16450],{},[25,16432,6835,16433,3181,16435,16437],{},[95,16434,5257],{},[95,16436,5263],{}," on subsection bounds that are meant to be inclusive.",[95,16439,16440],{},"countSpikes",[95,16442,16443],{},"rowEnd",[95,16445,16446],{},"colEnd"," are inclusive bounds by design — a ",[95,16449,5257],{}," would silently skip the last row\u002Fcolumn.",[69,16452,501],{"id":500},[19,16454,16455,16458,16461,16464],{},[22,16456,16457],{},"Every 1D array algorithm pattern (accumulator, min\u002Fmax, property count, duplicates, rotate) extends to 2D — applied to the whole array, one row, one column, or a bounded subsection.",[22,16459,16460],{},"Summing a row fixes the row index and loops columns; summing a column fixes the column index and loops rows.",[22,16462,16463],{},"A full 2D duplicate check needs 4 nested loops, not 2 — two to pick the candidate cell, two more to scan every cell that comes after it without re-checking any pair.",[22,16465,16466,16467,16469],{},"Rotating a single row (or a fixed-column \"column slice\") reuses Lesson 9.7's ",[95,16468,12343],{}," rotate pattern; reversing one reuses Lesson 9.5's swap-from-both-ends pattern.",[15,16471,544,16472,548,16474,16477],{},[95,16473,547],{},[95,16475,16476],{},"unit-4-data-collections\u002F4.13-implementing-2d-array-algorithms.md"," (CSA 4.13)",[554,16479,556],{},{"title":48,"searchDepth":49,"depth":49,"links":16481},[16482,16483,16484,16485,16486,16487,16488],{"id":15860,"depth":49,"text":15861},{"id":15962,"depth":49,"text":15963},{"id":16045,"depth":49,"text":16046},{"id":16129,"depth":49,"text":16130},{"id":16257,"depth":49,"text":16258},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":16490,"status":15483},"10.3 — Implementing 2D Array Algorithms (CSA 4.13)","\u002Fshockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F3-implementing-2d-array-algorithms",{"title":15849,"description":15857},"shockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F10.3-implementing-2d-array-algorithms","wFRnQk_kwkm1RWEBuXlJmpfbvveFFWvU4eMj4bBqJa8",{"id":16496,"title":16497,"body":16498,"description":48,"extension":51,"meta":17030,"navigation":55,"path":17032,"seo":17033,"stem":17034,"__hash__":17035},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch11-enums-named-choices\u002F11-enums-named-choices.md","Enums: Named Choices",{"type":8,"value":16499,"toc":17018},[16500,16503,16507,16517,16554,16560,16564,16576,16609,16626,16630,16633,16708,16740,16743,16752,16759,16765,16788,16792,16810,16845,16871,16875,16891,16895,16905,16907,16948,16950,17004,17016],[11,16501,16497],{"id":16502},"enums-named-choices",[69,16504,16506],{"id":16505},"why-enums-exist","Why Enums Exist",[15,16508,1851,16509,16512,16513,16516],{},[25,16510,16511],{},"enum"," (\"enumerated type\") is a type with a fixed, predefined set of named values — a variable of that type can only ever be one of those values, nothing else. Before enums, code often used plain integers or strings to represent a fixed set of states (",[95,16514,16515],{},"int armState = 2;","), which lets any number in — including ones that mean nothing. An enum makes invalid states impossible to even compile:",[104,16518,16520],{"className":106,"code":16519,"language":108,"meta":48,"style":48},"public enum ArmPosition\n{\n    STOWED, INTAKE, SCORE\n}\n\nArmPosition target = ArmPosition.INTAKE; \u002F\u002F legal\nArmPosition target2 = ArmPosition.CLIMB; \u002F\u002F compile error — CLIMB was never defined\n",[95,16521,16522,16527,16531,16536,16540,16544,16549],{"__ignoreMap":48},[112,16523,16524],{"class":114,"line":115},[112,16525,16526],{},"public enum ArmPosition\n",[112,16528,16529],{"class":114,"line":49},[112,16530,123],{},[112,16532,16533],{"class":114,"line":126},[112,16534,16535],{},"    STOWED, INTAKE, SCORE\n",[112,16537,16538],{"class":114,"line":132},[112,16539,153],{},[112,16541,16542],{"class":114,"line":138},[112,16543,907],{"emptyLinePlaceholder":55},[112,16545,16546],{"class":114,"line":144},[112,16547,16548],{},"ArmPosition target = ArmPosition.INTAKE; \u002F\u002F legal\n",[112,16550,16551],{"class":114,"line":150},[112,16552,16553],{},"ArmPosition target2 = ArmPosition.CLIMB; \u002F\u002F compile error — CLIMB was never defined\n",[15,16555,16556,16557,16559],{},"By convention, enum constants are written in ",[95,16558,370],{},", the same naming style used for other constants (Lesson 1.2).",[69,16561,16563],{"id":16562},"switching-over-an-enum","Switching Over an Enum",[15,16565,16566,16567,16569,16570,16572,16573,16575],{},"Lesson 5.12 covers ",[95,16568,5700],{}," itself — arrow form, colon form, ",[95,16571,5806],{},", and switch expressions. Enums are where ",[95,16574,5700],{}," is most at home, because the compiler already knows every possible value:",[104,16577,16579],{"className":106,"code":16578,"language":108,"meta":48,"style":48},"switch (target)\n{\n    case STOWED -> arm.setAngle(0);\n    case INTAKE -> arm.setAngle(35);\n    case SCORE  -> arm.setAngle(110);\n}\n",[95,16580,16581,16586,16590,16595,16600,16605],{"__ignoreMap":48},[112,16582,16583],{"class":114,"line":115},[112,16584,16585],{},"switch (target)\n",[112,16587,16588],{"class":114,"line":49},[112,16589,123],{},[112,16591,16592],{"class":114,"line":126},[112,16593,16594],{},"    case STOWED -> arm.setAngle(0);\n",[112,16596,16597],{"class":114,"line":132},[112,16598,16599],{},"    case INTAKE -> arm.setAngle(35);\n",[112,16601,16602],{"class":114,"line":138},[112,16603,16604],{},"    case SCORE  -> arm.setAngle(110);\n",[112,16606,16607],{"class":114,"line":144},[112,16608,153],{},[15,16610,16611,16612,959,16615,16618,16619,16622,16623,16625],{},"Notice the case labels are just ",[95,16613,16614],{},"STOWED",[95,16616,16617],{},"ArmPosition.STOWED"," — inside a switch over an ",[95,16620,16621],{},"ArmPosition",", Java already knows the type, so the prefix is optional and redundant; leave it off. (On Java 17–20, writing the qualified ",[95,16624,16617],{}," form is a compile error; Java 21+ allows it but this course still leaves it off for readability.)",[69,16627,16629],{"id":16628},"an-enum-is-really-a-class","An Enum Is Really a Class",[15,16631,16632],{},"An enum isn't just a fancier set of named integers — it's a full class. Its body can declare fields, a constructor, and methods, letting each constant carry its own data:",[104,16634,16636],{"className":106,"code":16635,"language":108,"meta":48,"style":48},"public enum ArmPosition\n{\n    STOWED(0), INTAKE(35), SCORE(110); \u002F\u002F constants, WITH constructor arguments\n\n    private final double angleDegrees;\n\n    ArmPosition(double angleDegrees)\n    {\n        this.angleDegrees = angleDegrees;\n    }\n\n    public double getAngleDegrees()\n    {\n        return angleDegrees;\n    }\n}\n",[95,16637,16638,16642,16646,16651,16655,16660,16664,16669,16673,16678,16682,16686,16691,16695,16700,16704],{"__ignoreMap":48},[112,16639,16640],{"class":114,"line":115},[112,16641,16526],{},[112,16643,16644],{"class":114,"line":49},[112,16645,123],{},[112,16647,16648],{"class":114,"line":126},[112,16649,16650],{},"    STOWED(0), INTAKE(35), SCORE(110); \u002F\u002F constants, WITH constructor arguments\n",[112,16652,16653],{"class":114,"line":132},[112,16654,907],{"emptyLinePlaceholder":55},[112,16656,16657],{"class":114,"line":138},[112,16658,16659],{},"    private final double angleDegrees;\n",[112,16661,16662],{"class":114,"line":144},[112,16663,907],{"emptyLinePlaceholder":55},[112,16665,16666],{"class":114,"line":150},[112,16667,16668],{},"    ArmPosition(double angleDegrees)\n",[112,16670,16671],{"class":114,"line":2276},[112,16672,135],{},[112,16674,16675],{"class":114,"line":2282},[112,16676,16677],{},"        this.angleDegrees = angleDegrees;\n",[112,16679,16680],{"class":114,"line":2288},[112,16681,147],{},[112,16683,16684],{"class":114,"line":5760},[112,16685,907],{"emptyLinePlaceholder":55},[112,16687,16688],{"class":114,"line":5766},[112,16689,16690],{},"    public double getAngleDegrees()\n",[112,16692,16693],{"class":114,"line":5772},[112,16694,135],{},[112,16696,16697],{"class":114,"line":5777},[112,16698,16699],{},"        return angleDegrees;\n",[112,16701,16702],{"class":114,"line":5783},[112,16703,147],{},[112,16705,16706],{"class":114,"line":5789},[112,16707,153],{},[15,16709,16710,16711,16713,16714,322,16717,322,16720,16723,16724,16726,16727,16730,16731,16733,16734,7740,16736,16739],{},"Two rules this pattern depends on: the list of constants must come ",[25,16712,4161],{}," in the enum body, and once there are fields or methods after it, that constant list must end with a semicolon. Each constant listed (",[95,16715,16716],{},"STOWED(0)",[95,16718,16719],{},"INTAKE(35)",[95,16721,16722],{},"SCORE(110)",") calls the constructor with its own arguments — an enum's constructor is implicitly ",[95,16725,9905],{},", since you're never allowed to write ",[95,16728,16729],{},"new ArmPosition(...)"," yourself; the only ",[95,16732,16621],{}," objects that will ever exist are the ones listed in the enum body. Writing ",[95,16735,175],{},[95,16737,16738],{},"protected",") on an enum constructor is a compile error (\"modifier public not allowed here\") — leave the modifier off entirely.",[15,16741,16742],{},"With this version, the earlier switch could be simplified — every position now carries its own target angle:",[104,16744,16746],{"className":106,"code":16745,"language":108,"meta":48,"style":48},"arm.setAngle(target.getAngleDegrees());\n",[95,16747,16748],{"__ignoreMap":48},[112,16749,16750],{"class":114,"line":115},[112,16751,16745],{},[69,16753,16755,16756],{"id":16754},"iterating-every-value-values","Iterating Every Value: ",[95,16757,16758],{},"values()",[15,16760,16761,16762,16764],{},"Every enum automatically gets a static ",[95,16763,16758],{}," method, returning an array of all its constants in declared order — handy for looping over every possibility:",[104,16766,16768],{"className":106,"code":16767,"language":108,"meta":48,"style":48},"for (ArmPosition position : ArmPosition.values())\n{\n    System.out.println(position + \" -> \" + position.getAngleDegrees() + \" degrees\");\n}\n",[95,16769,16770,16775,16779,16784],{"__ignoreMap":48},[112,16771,16772],{"class":114,"line":115},[112,16773,16774],{},"for (ArmPosition position : ArmPosition.values())\n",[112,16776,16777],{"class":114,"line":49},[112,16778,123],{},[112,16780,16781],{"class":114,"line":126},[112,16782,16783],{},"    System.out.println(position + \" -> \" + position.getAngleDegrees() + \" degrees\");\n",[112,16785,16786],{"class":114,"line":132},[112,16787,153],{},[69,16789,16791],{"id":16790},"built-in-methods-every-enum-gets","Built-In Methods Every Enum Gets",[15,16793,16794,16795,16797,16798,16801,16802,16805,16806,16809],{},"Besides ",[95,16796,16758],{},", every enum constant automatically has a few more methods, inherited from ",[95,16799,16800],{},"java.lang.Enum"," (inheritance and ",[95,16803,16804],{},"extends"," are covered in Ch.17; interfaces and ",[95,16807,16808],{},"implements"," in Ch.19 — you don't need those chapters to use these methods):",[104,16811,16813],{"className":106,"code":16812,"language":108,"meta":48,"style":48},"ArmPosition p = ArmPosition.INTAKE;\nSystem.out.println(p.name());     \u002F\u002F \"INTAKE\" — the constant's exact declared name\nSystem.out.println(p.ordinal());  \u002F\u002F 1 — its position in the declared order, 0-indexed\nSystem.out.println(p);            \u002F\u002F \"INTAKE\" — toString() defaults to name()\n\u002F\u002F text -> constant; throws IllegalArgumentException if no match\nArmPosition parsed = ArmPosition.valueOf(\"SCORE\");\n",[95,16814,16815,16820,16825,16830,16835,16840],{"__ignoreMap":48},[112,16816,16817],{"class":114,"line":115},[112,16818,16819],{},"ArmPosition p = ArmPosition.INTAKE;\n",[112,16821,16822],{"class":114,"line":49},[112,16823,16824],{},"System.out.println(p.name());     \u002F\u002F \"INTAKE\" — the constant's exact declared name\n",[112,16826,16827],{"class":114,"line":126},[112,16828,16829],{},"System.out.println(p.ordinal());  \u002F\u002F 1 — its position in the declared order, 0-indexed\n",[112,16831,16832],{"class":114,"line":132},[112,16833,16834],{},"System.out.println(p);            \u002F\u002F \"INTAKE\" — toString() defaults to name()\n",[112,16836,16837],{"class":114,"line":138},[112,16838,16839],{},"\u002F\u002F text -> constant; throws IllegalArgumentException if no match\n",[112,16841,16842],{"class":114,"line":144},[112,16843,16844],{},"ArmPosition parsed = ArmPosition.valueOf(\"SCORE\");\n",[15,16846,16847,16848,16850,16851,4238,16853,16855,16856,537,16858,16860,16861,16863,16864,260,16866,16868,16869,4748],{},"Comparing two enum values with ",[95,16849,1921],{}," is safe and preferred (unlike ",[95,16852,361],{},[95,16854,1921],{}," is a pitfall) — there is only ever one object per constant, so ",[95,16857,1921],{},[95,16859,7836],{}," always agree. An enum variable can still be ",[95,16862,4645],{}," (it's a reference type), so a ",[95,16865,5700],{},[95,16867,1921],{}," check on an unassigned enum variable can still throw or misbehave like any other ",[95,16870,4645],{},[69,16872,16874],{"id":16873},"what-enums-cant-do","What Enums Can't Do",[15,16876,16877,16878,16880,16881,16883,16884,16886,16887,16890],{},"Every enum implicitly extends ",[95,16879,16800],{}," behind the scenes. Since Java only allows extending one parent class, an enum can never ",[95,16882,16804],{}," anything else of its own (Ch.17 covers ",[95,16885,16804],{}," in full) — though it can still ",[95,16888,16889],{},"implement"," interfaces (Ch.19).",[69,16892,16894],{"id":16893},"looking-ahead","Looking Ahead",[15,16896,16897,16898,16900,16901,16904],{},"This chapter's ideas — a fixed set of named states, plus a ",[95,16899,5700],{}," that reacts to whichever one is currently active — are exactly the foundation the ",[25,16902,16903],{},"State Machine"," pattern (Java II) builds on, where a subsystem tracks \"which named state am I in right now\" and transitions between them over time.",[69,16906,462],{"id":461},[19,16908,16909,16922,16937],{},[22,16910,16911,476,16916,16918,16919,16921],{},[25,16912,16913,16914,79],{},"Writing the enum type prefix inside a ",[95,16915,5700],{},[95,16917,6398],{}," is optional and redundant — just ",[95,16920,6394],{},". (On Java 17–20 the qualified form is a compile error.)",[22,16923,16924,476,16927,16930,16931,1401,16933,16936],{},[25,16925,16926],{},"Forgetting the semicolon after the constant list once fields\u002Fmethods follow.",[95,16928,16929],{},"STOWED(0), INTAKE(35), SCORE(110)"," with no trailing ",[95,16932,238],{},[95,16934,16935],{},"private final double angleDegrees;"," fails to compile.",[22,16938,16939,476,16945,16947],{},[25,16940,16941,16942,16944],{},"Trying to ",[95,16943,2504],{}," an enum constant.",[95,16946,16729],{}," is illegal — the only instances that will ever exist are the constants declared in the enum body itself.",[69,16949,501],{"id":500},[19,16951,16952,16955,16966,16969,16988,16998],{},[22,16953,16954],{},"An enum defines a fixed, named set of legal values for a type — the compiler rejects anything not in that list.",[22,16956,16957,16958,16960,16961,16963,16964,79],{},"Enum constant names use ",[95,16959,370],{},"; a ",[95,16962,5700],{}," over an enum omits the type prefix on each ",[95,16965,5802],{},[22,16967,16968],{},"An enum is a real class — it can have its own fields, a constructor, and methods, letting each constant carry its own data.",[22,16970,16971,16974,16975,322,16978,322,16981,325,16984,16987],{},[95,16972,16973],{},"EnumType.values()"," returns every constant, in order, for looping; ",[95,16976,16977],{},"name()",[95,16979,16980],{},"ordinal()",[95,16982,16983],{},"toString()",[95,16985,16986],{},"valueOf(String)"," are also built in.",[22,16989,16990,16992,16993,16995,16996,79],{},[95,16991,1921],{}," is safe (and preferred) for comparing enum values — unlike ",[95,16994,361],{},". An enum variable can still be ",[95,16997,4645],{},[22,16999,17000,17001,17003],{},"An enum implicitly extends ",[95,17002,16800],{},", so it can't extend any other class (interfaces are still fine).",[15,17005,544,17006,548,17009,17012,17013,17015],{},[95,17007,17008],{},"other-reference-repo",[95,17010,17011],{},"oracle-java-tutorials\u002Fenums\u002Fenum-types.md"," (ORACLE 10.1)\n",[25,17014,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-1.js, slide 9 (\"Enums: Named Choices\")",[554,17017,556],{},{"title":48,"searchDepth":49,"depth":49,"links":17019},[17020,17021,17022,17023,17025,17026,17027,17028,17029],{"id":16505,"depth":49,"text":16506},{"id":16562,"depth":49,"text":16563},{"id":16628,"depth":49,"text":16629},{"id":16754,"depth":49,"text":17024},"Iterating Every Value: values()",{"id":16790,"depth":49,"text":16791},{"id":16873,"depth":49,"text":16874},{"id":16893,"depth":49,"text":16894},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":17031,"status":570},"11 — Enums: Named Choices (ORACLE 10.1)","\u002Fshockwave-curriculum\u002Flessons\u002Fch11-enums-named-choices\u002F11-enums-named-choices",{"title":16497,"description":48},"shockwave-curriculum\u002Flessons\u002Fch11-enums-named-choices\u002F11-enums-named-choices","ZfhzXBstaAJawaJgAyBe0EwJnN0lE9ERrGfJa5bJ_XU",{"id":17037,"title":17038,"body":17039,"description":48,"extension":51,"meta":17891,"navigation":55,"path":17893,"seo":17894,"stem":17895,"__hash__":17896},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch12-exceptions-and-try-catch\u002F12-exceptions-and-try-catch.md","Exceptions & try\u002Fcatch",{"type":8,"value":17040,"toc":17877},[17041,17044,17048,17061,17079,17083,17091,17142,17160,17168,17226,17239,17249,17271,17290,17293,17305,17386,17389,17413,17451,17466,17470,17473,17514,17526,17532,17545,17581,17600,17607,17617,17658,17680,17684,17687,17710,17728,17734,17741,17750,17752,17799,17801,17852,17875],[11,17042,17038],{"id":17043},"exceptions-trycatch",[69,17045,17047],{"id":17046},"what-an-exception-is","What an Exception Is",[15,17049,1851,17050,17052,17053,17056,17057,17060],{},[25,17051,2839],{}," is an \"exceptional event\" — something that disrupts a program's normal flow while it runs (a file that doesn't exist, an array index that's out of range, dividing by zero). When an error occurs, the method creates an ",[25,17054,17055],{},"exception object"," describing what went wrong and hands it to the Java runtime — this is called ",[25,17058,17059],{},"throwing"," the exception.",[15,17062,17063,17064,17067,17068,17071,17072,17074,17075,17078],{},"The runtime then searches back up the ",[25,17065,17066],{},"call stack"," (the chain of methods that led to this point) looking for an ",[25,17069,17070],{},"exception handler"," — a block of code able to deal with that type of exception. The first matching handler it finds is said to ",[25,17073,14831],{}," the exception. If nothing on the whole call stack can handle it, the runtime terminates the program: on a robot, an uncaught exception in ",[95,17076,17077],{},"periodic()"," is exactly what turns the Driver Station's \"Robot Code\" indicator red.",[69,17080,17082],{"id":17081},"try-catch","try \u002F catch",[15,17084,405,17085,17087,17088,17090],{},[95,17086,14828],{}," block wraps code that might throw; a ",[95,17089,14831],{}," block that follows it handles a specific exception type if one occurs:",[104,17092,17094],{"className":106,"code":17093,"language":108,"meta":48,"style":48},"try\n{\n    config = loadFromFile(\"tuning.json\");\n}\ncatch (IOException e)\n{\n    \u002F\u002F Recover: fall back to defaults\n    config = Config.defaults();\n    reportWarning(\"Using default tuning\");\n}\n",[95,17095,17096,17101,17105,17110,17114,17119,17123,17128,17133,17138],{"__ignoreMap":48},[112,17097,17098],{"class":114,"line":115},[112,17099,17100],{},"try\n",[112,17102,17103],{"class":114,"line":49},[112,17104,123],{},[112,17106,17107],{"class":114,"line":126},[112,17108,17109],{},"    config = loadFromFile(\"tuning.json\");\n",[112,17111,17112],{"class":114,"line":132},[112,17113,153],{},[112,17115,17116],{"class":114,"line":138},[112,17117,17118],{},"catch (IOException e)\n",[112,17120,17121],{"class":114,"line":144},[112,17122,123],{},[112,17124,17125],{"class":114,"line":150},[112,17126,17127],{},"    \u002F\u002F Recover: fall back to defaults\n",[112,17129,17130],{"class":114,"line":2276},[112,17131,17132],{},"    config = Config.defaults();\n",[112,17134,17135],{"class":114,"line":2282},[112,17136,17137],{},"    reportWarning(\"Using default tuning\");\n",[112,17139,17140],{"class":114,"line":2288},[112,17141,153],{},[15,17143,7566,17144,17147,17148,17150,17151,17153,17154,17156,17157,17159],{},[95,17145,17146],{},"loadFromFile"," throws an ",[95,17149,14802],{},", execution jumps straight into the matching ",[95,17152,14831],{}," block — the rest of the ",[95,17155,14828],{}," block is skipped. If no exception occurs, the ",[95,17158,14831],{}," block never runs at all.",[15,17161,405,17162,17164,17165,17167],{},[95,17163,14828],{}," can have multiple ",[95,17166,14831],{}," blocks, checked in order, for handling different exception types differently:",[104,17169,17171],{"className":106,"code":17170,"language":108,"meta":48,"style":48},"try\n{\n    camera = new UsbCamera(\"Camera 1\", 0);\n}\ncatch (VideoException e)\n{\n    reportWarning(\"Camera unavailable — skipping vision this match\");\n}\ncatch (NullPointerException e)\n{\n    reportWarning(\"Camera name was null\");\n}\n",[95,17172,17173,17177,17181,17186,17190,17195,17199,17204,17208,17213,17217,17222],{"__ignoreMap":48},[112,17174,17175],{"class":114,"line":115},[112,17176,17100],{},[112,17178,17179],{"class":114,"line":49},[112,17180,123],{},[112,17182,17183],{"class":114,"line":126},[112,17184,17185],{},"    camera = new UsbCamera(\"Camera 1\", 0);\n",[112,17187,17188],{"class":114,"line":132},[112,17189,153],{},[112,17191,17192],{"class":114,"line":138},[112,17193,17194],{},"catch (VideoException e)\n",[112,17196,17197],{"class":114,"line":144},[112,17198,123],{},[112,17200,17201],{"class":114,"line":150},[112,17202,17203],{},"    reportWarning(\"Camera unavailable — skipping vision this match\");\n",[112,17205,17206],{"class":114,"line":2276},[112,17207,153],{},[112,17209,17210],{"class":114,"line":2282},[112,17211,17212],{},"catch (NullPointerException e)\n",[112,17214,17215],{"class":114,"line":2288},[112,17216,123],{},[112,17218,17219],{"class":114,"line":5760},[112,17220,17221],{},"    reportWarning(\"Camera name was null\");\n",[112,17223,17224],{"class":114,"line":5766},[112,17225,153],{},[15,17227,17228,1291,17231,17234,17235,17238],{},[95,17229,17230],{},"VideoException",[494,17232,17233],{},"unchecked"," — it extends ",[95,17236,17237],{},"RuntimeException"," — so catching it here is optional, not compiler-required. Catching it anyway lets the robot keep running with vision disabled instead of crashing outright.",[15,17240,17241,17242,17244,17245,17248],{},"Two ",[95,17243,14831],{}," blocks for exception types that share no inheritance relationship can be combined into one with ",[95,17246,17247],{},"|"," (multi-catch), when they should be handled identically:",[104,17250,17252],{"className":106,"code":17251,"language":108,"meta":48,"style":48},"catch (VideoException | NullPointerException e)\n{\n    reportWarning(\"Camera unavailable — skipping vision this match\");\n}\n",[95,17253,17254,17259,17263,17267],{"__ignoreMap":48},[112,17255,17256],{"class":114,"line":115},[112,17257,17258],{},"catch (VideoException | NullPointerException e)\n",[112,17260,17261],{"class":114,"line":49},[112,17262,123],{},[112,17264,17265],{"class":114,"line":126},[112,17266,17203],{},[112,17268,17269],{"class":114,"line":132},[112,17270,153],{},[15,17272,17273,17274,17276,17277,17279,17280,17283,17284,17286,17287,17289],{},"Order matters when the types ",[494,17275,7327],{}," relate: a ",[95,17278,14831],{}," for a more general type (like ",[95,17281,17282],{},"Exception",") must come ",[494,17285,8135],{}," every more specific ",[95,17288,14831],{}," for one of its subclasses — putting the general one first makes the specific one unreachable, which is a compile error (\"exception X has already been caught\").",[69,17291,17292],{"id":17292},"finally",[15,17294,17295,17296,17298,17299,17301,17302,17304],{},"An optional ",[95,17297,17292],{}," block, after all the ",[95,17300,14831],{}," blocks, always runs — whether an exception was thrown or not, and even if the ",[95,17303,14831],{}," block itself returns early. It's the right place for cleanup that must happen no matter what (closing a file, releasing a resource):",[104,17306,17308],{"className":106,"code":17307,"language":108,"meta":48,"style":48},"Scanner scan = null;\ntry\n{\n    scan = new Scanner(new File(\"auto_config.csv\"));\n    \u002F\u002F ... read the file ...\n}\ncatch (FileNotFoundException e)\n{\n    reportWarning(\"Missing auto_config.csv — using default route\");\n}\nfinally\n{\n    if (scan != null)\n    {\n        scan.close(); \u002F\u002F runs whether the try succeeded, failed, or even returned early\n    }\n}\n",[95,17309,17310,17315,17319,17323,17328,17333,17337,17342,17346,17351,17355,17360,17364,17369,17373,17378,17382],{"__ignoreMap":48},[112,17311,17312],{"class":114,"line":115},[112,17313,17314],{},"Scanner scan = null;\n",[112,17316,17317],{"class":114,"line":49},[112,17318,17100],{},[112,17320,17321],{"class":114,"line":126},[112,17322,123],{},[112,17324,17325],{"class":114,"line":132},[112,17326,17327],{},"    scan = new Scanner(new File(\"auto_config.csv\"));\n",[112,17329,17330],{"class":114,"line":138},[112,17331,17332],{},"    \u002F\u002F ... read the file ...\n",[112,17334,17335],{"class":114,"line":144},[112,17336,153],{},[112,17338,17339],{"class":114,"line":150},[112,17340,17341],{},"catch (FileNotFoundException e)\n",[112,17343,17344],{"class":114,"line":2276},[112,17345,123],{},[112,17347,17348],{"class":114,"line":2282},[112,17349,17350],{},"    reportWarning(\"Missing auto_config.csv — using default route\");\n",[112,17352,17353],{"class":114,"line":2288},[112,17354,153],{},[112,17356,17357],{"class":114,"line":5760},[112,17358,17359],{},"finally\n",[112,17361,17362],{"class":114,"line":5766},[112,17363,123],{},[112,17365,17366],{"class":114,"line":5772},[112,17367,17368],{},"    if (scan != null)\n",[112,17370,17371],{"class":114,"line":5777},[112,17372,135],{},[112,17374,17375],{"class":114,"line":5783},[112,17376,17377],{},"        scan.close(); \u002F\u002F runs whether the try succeeded, failed, or even returned early\n",[112,17379,17380],{"class":114,"line":5789},[112,17381,147],{},[112,17383,17384],{"class":114,"line":5794},[112,17385,153],{},[69,17387,17388],{"id":17388},"try-with-resources",[15,17390,2424,17391,17393,17394,17396,17397,17400,17401,17403,17404,17406,17407,17409,17410,17412],{},[95,17392,17292],{},"-based cleanup above is exactly the case ",[25,17395,17388],{}," exists to replace. Any resource that implements ",[95,17398,17399],{},"AutoCloseable"," (like ",[95,17402,14755],{},") can be declared inside parentheses right after ",[95,17405,14828],{},"; Java then calls its ",[95,17408,15090],{}," automatically, in every case, without a ",[95,17411,17292],{}," block at all:",[104,17414,17416],{"className":106,"code":17415,"language":108,"meta":48,"style":48},"try (Scanner scan = new Scanner(new File(\"auto_config.csv\")))\n{\n    \u002F\u002F ... read the file ...\n}\ncatch (FileNotFoundException e)\n{\n    reportWarning(\"Missing auto_config.csv — using default route\");\n}\n",[95,17417,17418,17423,17427,17431,17435,17439,17443,17447],{"__ignoreMap":48},[112,17419,17420],{"class":114,"line":115},[112,17421,17422],{},"try (Scanner scan = new Scanner(new File(\"auto_config.csv\")))\n",[112,17424,17425],{"class":114,"line":49},[112,17426,123],{},[112,17428,17429],{"class":114,"line":126},[112,17430,17332],{},[112,17432,17433],{"class":114,"line":132},[112,17434,153],{},[112,17436,17437],{"class":114,"line":138},[112,17438,17341],{},[112,17440,17441],{"class":114,"line":144},[112,17442,123],{},[112,17444,17445],{"class":114,"line":150},[112,17446,17350],{},[112,17448,17449],{"class":114,"line":2276},[112,17450,153],{},[15,17452,17453,17456,17457,17459,17460,17462,17463,17465],{},[95,17454,17455],{},"scan"," is closed the moment the ",[95,17458,14828],{}," block ends — normally or via an exception — and it only exists inside that ",[95,17461,14828],{},". Prefer this form over a manual ",[95,17464,17292],{}," whenever the resource type supports it.",[69,17467,17469],{"id":17468},"checked-vs-unchecked-exceptions","Checked vs. Unchecked Exceptions",[15,17471,17472],{},"Java splits exceptions into two kinds, and the difference matters for what the compiler demands of you:",[19,17474,17475,17489],{},[22,17476,17477,17400,17480,17482,17483,17485,17486,17488],{},[25,17478,17479],{},"Checked exceptions",[95,17481,14802],{},") — the compiler forces you to either ",[95,17484,14831],{}," them or declare them with a ",[95,17487,14835],{}," clause. They represent problems a caller could reasonably be expected to recover from.",[22,17490,17491,2150,17494,322,17496,17499,17500,322,17502,322,17504,17507,17508,17510,17511,17513],{},[25,17492,17493],{},"Unchecked exceptions",[95,17495,17237],{},[95,17497,17498],{},"Error",", and their subclasses — ",[95,17501,4678],{},[95,17503,12136],{},[95,17505,17506],{},"ArithmeticException",") — the compiler does not require handling them at all, though you're always allowed to. ",[95,17509,17237],{}," subclasses almost always represent a genuine programming bug (a null you forgot to check, an index you miscalculated) rather than something the caller can meaningfully recover from at runtime; ",[95,17512,17498],{}," and its subclasses represent serious JVM-level failures ordinary code doesn't catch or throw.",[15,17515,17516,17517,17520,17521,176,17523,17525],{},"Guideline from the language's own designers: ",[494,17518,17519],{},"if a client can reasonably be expected to recover from a problem, make it checked; if a client can't do anything useful about it, make it unchecked."," CSA covers unchecked-exception concepts (NullPointerException, ArrayIndexOutOfBoundsException) as topics in their own right, without teaching the ",[95,17522,14828],{},[95,17524,14831],{}," mechanism itself — the AP exam doesn't test it.",[69,17527,2424,17529,17531],{"id":17528},"the-throws-clause",[95,17530,14835],{}," Clause",[15,17533,17534,17535,176,17538,17541,17542,17544],{},"If a method doesn't want to handle a checked exception itself, it can instead declare that it might throw one, pushing the decision up to whoever calls it. ",[95,17536,17537],{},"PrintWriter",[95,17539,17540],{},"FileWriter"," write text to a file — the counterpart to ",[95,17543,14755],{},", which Lesson 9.8 uses to read one:",[104,17546,17548],{"className":106,"code":17547,"language":108,"meta":48,"style":48},"public void writeList() throws IOException\n{\n    try (PrintWriter out = new PrintWriter(new FileWriter(\"OutFile.txt\")))\n    {\n        \u002F\u002F ...\n    }\n}\n",[95,17549,17550,17555,17559,17564,17568,17573,17577],{"__ignoreMap":48},[112,17551,17552],{"class":114,"line":115},[112,17553,17554],{},"public void writeList() throws IOException\n",[112,17556,17557],{"class":114,"line":49},[112,17558,123],{},[112,17560,17561],{"class":114,"line":126},[112,17562,17563],{},"    try (PrintWriter out = new PrintWriter(new FileWriter(\"OutFile.txt\")))\n",[112,17565,17566],{"class":114,"line":132},[112,17567,135],{},[112,17569,17570],{"class":114,"line":138},[112,17571,17572],{},"        \u002F\u002F ...\n",[112,17574,17575],{"class":114,"line":144},[112,17576,147],{},[112,17578,17579],{"class":114,"line":150},[112,17580,153],{},[15,17582,17583,17585,17586,17588,17589,17591,17592,17595,17596,17599],{},[95,17584,14835],{}," goes after the parameter list, before the method body's opening brace. Unchecked exceptions never need to appear in a ",[95,17587,14835],{}," clause (though nothing stops you from listing one). Note the ",[95,17590,14828],{},"-with-resources here too: without it, an exception thrown between opening ",[95,17593,17594],{},"out"," and calling ",[95,17597,17598],{},"out.close()"," would skip the close and leak the file handle.",[69,17601,2424,17603,17606],{"id":17602},"the-throw-statement",[95,17604,17605],{},"throw"," Statement",[15,17608,17609,17610,17612,17613,17616],{},"Any code — yours, a library's, or the Java runtime itself — can trigger an exception with the ",[95,17611,17605],{}," statement, given any object that's a ",[95,17614,17615],{},"Throwable"," (or a subclass):",[104,17618,17620],{"className":106,"code":17619,"language":108,"meta":48,"style":48},"public void setTargetAngle(double degrees)\n{\n    if (degrees \u003C 0 || degrees > 180)\n    {\n        throw new IllegalArgumentException(\"Angle out of range: \" + degrees);\n    }\n    this.targetAngle = degrees;\n}\n",[95,17621,17622,17627,17631,17636,17640,17645,17649,17654],{"__ignoreMap":48},[112,17623,17624],{"class":114,"line":115},[112,17625,17626],{},"public void setTargetAngle(double degrees)\n",[112,17628,17629],{"class":114,"line":49},[112,17630,123],{},[112,17632,17633],{"class":114,"line":126},[112,17634,17635],{},"    if (degrees \u003C 0 || degrees > 180)\n",[112,17637,17638],{"class":114,"line":132},[112,17639,135],{},[112,17641,17642],{"class":114,"line":138},[112,17643,17644],{},"        throw new IllegalArgumentException(\"Angle out of range: \" + degrees);\n",[112,17646,17647],{"class":114,"line":144},[112,17648,147],{},[112,17650,17651],{"class":114,"line":150},[112,17652,17653],{},"    this.targetAngle = degrees;\n",[112,17655,17656],{"class":114,"line":2276},[112,17657,153],{},[15,17659,17660,17661,17663,17664,17667,17668,17670,17671,17673,17674,17676,17677,17679],{},"Every exception type in Java descends from ",[95,17662,17615],{}," — each one is a ",[25,17665,17666],{},"subclass"," of it (built on top of it, inheriting its behavior; Ch.17 covers what that means in full). Its two direct children are ",[95,17669,17498],{}," (serious JVM-level failures — not something ordinary code catches or throws) and ",[95,17672,17282],{}," (everything an ordinary program throws and catches), and ",[95,17675,17237],{}," is the branch of ",[95,17678,17282],{}," reserved for unchecked exceptions.",[69,17681,17683],{"id":17682},"reading-what-went-wrong","Reading What Went Wrong",[15,17685,17686],{},"Every exception carries a message, and a caught one doesn't have to be handled blind:",[104,17688,17690],{"className":106,"code":17689,"language":108,"meta":48,"style":48},"catch (IllegalArgumentException e)\n{\n    reportWarning(\"Rejected: \" + e.getMessage()); \u002F\u002F \"Angle out of range: 240.0\"\n}\n",[95,17691,17692,17697,17701,17706],{"__ignoreMap":48},[112,17693,17694],{"class":114,"line":115},[112,17695,17696],{},"catch (IllegalArgumentException e)\n",[112,17698,17699],{"class":114,"line":49},[112,17700,123],{},[112,17702,17703],{"class":114,"line":126},[112,17704,17705],{},"    reportWarning(\"Rejected: \" + e.getMessage()); \u002F\u002F \"Angle out of range: 240.0\"\n",[112,17707,17708],{"class":114,"line":132},[112,17709,153],{},[15,17711,17712,17715,17716,17719,17720,17723,17724,17727],{},[95,17713,17714],{},"e.getMessage()"," returns the text passed to the exception's constructor (",[95,17717,17718],{},"\"Angle out of range: \" + degrees"," above) — use it in a log message instead of guessing what failed. An ",[494,17721,17722],{},"uncaught"," exception prints a ",[25,17725,17726],{},"stack trace",": the exception type and message, followed by the chain of method calls (most recent first) that led to it —",[104,17729,17732],{"className":17730,"code":17731,"language":6629},[6627],"java.lang.IllegalArgumentException: Angle out of range: 240.0\n    at Arm.setTargetAngle(Arm.java:107)\n    at Robot.teleopPeriodic(Robot.java:42)\n",[95,17733,17731],{"__ignoreMap":48},[15,17735,17736,17737,17740],{},"— which is exactly what shows up when robot code crashes: read from the top down, the first line is the problem, and the first ",[95,17738,17739],{},"at"," line naming your own class (not a library's) is usually where to start looking.",[15,17742,17743,17744,17746,17747,17749],{},"Writing your ",[25,17745,4420],{}," exception types (for errors specific to your robot code, not covered by a built-in class) needs ",[95,17748,16804],{},", which isn't taught until Ch.17 — Lesson 17.2 covers it.",[69,17751,462],{"id":461},[19,17753,17754,17767,17781],{},[22,17755,17756,17759,17760,17762,17763,17766],{},[25,17757,17758],{},"Catch-and-ignore."," An empty ",[95,17761,14831],{}," block silently swallows a real problem — at minimum, log or report it (",[95,17764,17765],{},"reportWarning(...)"," above), even if there's nothing more to do.",[22,17768,17769,17772,17773,176,17775,17777,17778,17780],{},[25,17770,17771],{},"Catching to \"fix\" a bug instead of fixing it."," Wrapping buggy code in ",[95,17774,14828],{},[95,17776,14831],{}," to suppress a ",[95,17779,4678],{}," hides the actual mistake instead of correcting it — reserve catching for genuinely recoverable situations (a missing file, an unreachable camera), not programming errors.",[22,17782,17783,17795,17796,17798],{},[25,17784,4719,17785,17787,17788,17790,17791,176,17793,79],{},[95,17786,17292],{}," runs even on an early ",[95,17789,3632],{}," inside ",[95,17792,14828],{},[95,17794,14831],{}," Cleanup code that must always run belongs in ",[95,17797,17292],{},", not duplicated at the end of every branch.",[69,17800,501],{"id":500},[19,17802,17803,17806,17822,17836,17844,17849],{},[22,17804,17805],{},"Throwing an exception creates an object describing the problem and hands it to the runtime, which searches the call stack for a matching handler; an unhandled exception crashes the program (a red \"Robot Code\" indicator, on a robot).",[22,17807,17808,17810,17811,17813,17814,17816,17817,17819,17820,79],{},[95,17809,14828],{}," wraps risky code; one or more ",[95,17812,14831],{}," blocks (in order, general after specific, or combined with ",[95,17815,17247],{},") handle specific exception types; an optional ",[95,17818,17292],{}," block always runs, for cleanup — or use try-with-resources for anything ",[95,17821,17399],{},[22,17823,17824,17825,17827,17828,17830,17831,322,17833,17835],{},"Checked exceptions (like ",[95,17826,14802],{},") must be caught or declared with ",[95,17829,14835],{},"; unchecked exceptions (",[95,17832,17237],{},[95,17834,17498],{},", and their subclasses) don't require either, since they usually signal a real bug rather than a recoverable situation.",[22,17837,17838,17841,17842,79],{},[95,17839,17840],{},"throw someObject;"," triggers an exception yourself, given any ",[95,17843,17615],{},[22,17845,17846,17848],{},[95,17847,17714],{}," reports what went wrong; an uncaught exception prints a stack trace, read top-down.",[22,17850,17851],{},"Never catch-and-ignore — recover meaningfully, or at least report the problem.",[15,17853,544,17854,548,17856,322,17859,322,17862,322,17865,322,17868,17871,17872,17874],{},[95,17855,17008],{},[95,17857,17858],{},"oracle-java-tutorials\u002Fexceptions\u002F01-what-is-an-exception.md",[95,17860,17861],{},"03-catching-and-handling-exceptions.md",[95,17863,17864],{},"09-specifying-the-exceptions-thrown-by-a-method.md",[95,17866,17867],{},"10-how-to-throw-exceptions.md",[95,17869,17870],{},"13-unchecked-exceptions-the-controversy.md"," (ORACLE 11.1-16)\n",[25,17873,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-1.js, slide 11 (\"Exceptions & try\u002Fcatch\")",[554,17876,556],{},{"title":48,"searchDepth":49,"depth":49,"links":17878},[17879,17880,17881,17882,17883,17884,17886,17888,17889,17890],{"id":17046,"depth":49,"text":17047},{"id":17081,"depth":49,"text":17082},{"id":17292,"depth":49,"text":17292},{"id":17388,"depth":49,"text":17388},{"id":17468,"depth":49,"text":17469},{"id":17528,"depth":49,"text":17885},"The throws Clause",{"id":17602,"depth":49,"text":17887},"The throw Statement",{"id":17682,"depth":49,"text":17683},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":17892,"status":570},"12 — Exceptions & try\u002Fcatch (ORACLE 11.1-16)","\u002Fshockwave-curriculum\u002Flessons\u002Fch12-exceptions-and-try-catch\u002F12-exceptions-and-try-catch",{"title":17038,"description":48},"shockwave-curriculum\u002Flessons\u002Fch12-exceptions-and-try-catch\u002F12-exceptions-and-try-catch","ut608Pyuwq3-Z3fmE7cQd3rBsZJLsucLzq1FqP9wjLI",{"id":17898,"title":17899,"body":17900,"description":18448,"extension":51,"meta":18449,"navigation":55,"path":18451,"seo":18452,"stem":18453,"__hash__":18454},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch13-common-gotchas\u002F13-common-gotchas.md","Common Gotchas",{"type":8,"value":17901,"toc":18438},[17902,17905,17912,17916,17937,17962,17982,17988,18056,18060,18069,18084,18097,18099,18108,18123,18143,18157,18161,18178,18198,18208,18212,18231,18251,18254,18258,18272,18337,18344,18346,18367,18369,18427,18436],[11,17903,17899],{"id":17904},"common-gotchas",[15,17906,17907,17908,17911],{},"This chapter is a quick-reference checklist, not new material — each item below is taught in full elsewhere in this curriculum. Its job is to put the most common real mistakes side by side, since they tend to resurface long after the lesson that first covered them. ",[25,17909,17910],{},"Note:"," this list is expected to grow once real code-review and exercise practice surfaces more of the mistakes people actually make — it currently only covers what the original deck flagged.",[69,17913,17915],{"id":17914},"vs-equals","== vs. .equals()",[15,17917,17918,17920,17921,322,17923,322,17925,17927,17928,195,17930,17932,17933,17936],{},[95,17919,1921],{}," compares primitives (",[95,17922,603],{},[95,17924,631],{},[95,17926,657],{},") by value, which is correct and sufficient for them. For objects — including ",[95,17929,361],{},[95,17931,1921],{}," instead checks whether two variables point at the ",[494,17934,17935],{},"exact same object in memory",", which is almost never what you actually want to ask:",[104,17938,17940],{"className":106,"code":17939,"language":108,"meta":48,"style":48},"String a = new String(\"BlueAlliance-Left\");\nString b = new String(\"BlueAlliance-Left\");\nSystem.out.println(a == b);        \u002F\u002F false — two different objects, same text\nSystem.out.println(a.equals(b));   \u002F\u002F true — compares the actual characters\n",[95,17941,17942,17947,17952,17957],{"__ignoreMap":48},[112,17943,17944],{"class":114,"line":115},[112,17945,17946],{},"String a = new String(\"BlueAlliance-Left\");\n",[112,17948,17949],{"class":114,"line":49},[112,17950,17951],{},"String b = new String(\"BlueAlliance-Left\");\n",[112,17953,17954],{"class":114,"line":126},[112,17955,17956],{},"System.out.println(a == b);        \u002F\u002F false — two different objects, same text\n",[112,17958,17959],{"class":114,"line":132},[112,17960,17961],{},"System.out.println(a.equals(b));   \u002F\u002F true — compares the actual characters\n",[15,17963,1396,17964,17966,17967,322,17970,3283,17973,17976,17977,537,17979,17981],{},[95,17965,7836],{}," — or a purpose-built comparison method like ",[95,17968,17969],{},".equalsIgnoreCase()",[95,17971,17972],{},".compareTo()",[95,17974,17975],{},".contains()"," — for any object type, including boxed numbers like ",[95,17978,1869],{},[95,17980,8536],{},". See Lesson 6.1 for the full explanation.",[15,17983,17984,17985,17987],{},"A few ",[95,17986,1921],{}," special cases worth knowing by heart:",[19,17989,17990,18007,18041],{},[22,17991,17992,17997,17998,1291,18000,18002,18003,18006],{},[25,17993,17994,79],{},[95,17995,17996],{},"double =="," Even without boxing, ",[95,17999,6778],{},[95,18001,664],{}," — floating-point math rarely lands on an exact value. Compare with a tolerance instead (",[95,18004,18005],{},"Math.abs(a - b) \u003C 0.0001","), as covered in Lesson 2.4.",[22,18008,18009,18014,18015,18017,18018,4029,18021,18024,18025,18028,18029,18031,18032,1291,18035,18037,18038,18040],{},[25,18010,18011,79],{},[95,18012,18013],{},"Integer =="," Java caches small boxed ",[95,18016,1869],{}," values (",[95,18019,18020],{},"-128",[95,18022,18023],{},"127","), so ",[95,18026,18027],{},"Integer x = 100, y = 100; x == y"," happens to be ",[95,18030,661],{}," — but ",[95,18033,18034],{},"Integer p = 1000, q = 1000; p == q",[95,18036,664],{},". Never rely on this; always use ",[95,18039,7836],{}," for boxed numbers.",[22,18042,18043,476,18046,476,18048,18050,18051,537,18053,18055],{},[25,18044,18045],{},"Enums are the exception.",[95,18047,1921],{},[494,18049,844],{}," safe (and preferred) for comparing enum constants (Lesson 11) — there's only ever one object per constant, so ",[95,18052,1921],{},[95,18054,7836],{}," always agree.",[69,18057,18059],{"id":18058},"integer-division","Integer Division",[15,18061,18062,18063,18065,18066,18068],{},"Dividing two ",[95,18064,603],{},"s produces an ",[95,18067,603],{}," — the fractional part is silently discarded (truncated), not rounded:",[104,18070,18072],{"className":106,"code":18071,"language":108,"meta":48,"style":48},"int result = 5 \u002F 2;       \u002F\u002F 2, not 2.5 — the .5 is thrown away, not rounded\ndouble result2 = 5.0 \u002F 2.0; \u002F\u002F 2.5 — at least one operand must be a floating-point type\n",[95,18073,18074,18079],{"__ignoreMap":48},[112,18075,18076],{"class":114,"line":115},[112,18077,18078],{},"int result = 5 \u002F 2;       \u002F\u002F 2, not 2.5 — the .5 is thrown away, not rounded\n",[112,18080,18081],{"class":114,"line":49},[112,18082,18083],{},"double result2 = 5.0 \u002F 2.0; \u002F\u002F 2.5 — at least one operand must be a floating-point type\n",[15,18085,18086,18087,18090,18091,18093,18094,18096],{},"This bites often when averaging (",[95,18088,18089],{},"total \u002F count"," where both are ",[95,18092,603],{},") — cast at least one operand to ",[95,18095,631],{}," first. See Lesson 2.4 for casting rules in full.",[69,18098,4678],{"id":4881},[15,18100,18101,18102,18104,18105,18107],{},"Calling a method or accessing a field on a variable that's ",[95,18103,4645],{}," (declared but never assigned a real object) throws ",[95,18106,4678],{}," — one of the most common runtime crashes in any Java program, robot code included:",[104,18109,18111],{"className":106,"code":18110,"language":108,"meta":48,"style":48},"Drivetrain drivetrain = null; \u002F\u002F explicitly assigned null — no real object yet\ndrivetrain.stop();            \u002F\u002F NullPointerException — nothing to call stop() on\n",[95,18112,18113,18118],{"__ignoreMap":48},[112,18114,18115],{"class":114,"line":115},[112,18116,18117],{},"Drivetrain drivetrain = null; \u002F\u002F explicitly assigned null — no real object yet\n",[112,18119,18120],{"class":114,"line":49},[112,18121,18122],{},"drivetrain.stop();            \u002F\u002F NullPointerException — nothing to call stop() on\n",[15,18124,18125,18126,18129,18130,217,18133,18136,18137,18139,18140,18142],{},"(A ",[494,18127,18128],{},"local"," variable left truly unassigned — just ",[95,18131,18132],{},"Drivetrain drivetrain;",[95,18134,18135],{},"= null"," — is a different, compile-time error: Java refuses to compile code that reads it before it's given a value, reporting \"variable drivetrain might not have been initialized.\" Only a ",[494,18138,15214],{}," defaults to ",[95,18141,4645],{}," automatically.)",[15,18144,18145,18146,18149,18150,18152,18153,18156],{},"The fix is always the same shape: make sure every object is actually constructed (",[95,18147,18148],{},"new Drivetrain(...)",") before anything calls a method on it, and check for ",[95,18151,4645],{}," explicitly at any point where a value might legitimately be missing (e.g., a ",[95,18154,18155],{},"HashMap.get()"," that found no match — see Lesson 9.3).",[69,18158,18160],{"id":18159},"off-by-one","Off-by-One",[15,18162,18163,18164,18166,18167,18169,18170,7740,18172,18174,18175,18177],{},"Arrays (and ",[95,18165,12343],{},") are indexed starting at ",[95,18168,1365],{}," — the last valid index is always ",[95,18171,12099],{},[95,18173,14320],{},"), never ",[95,18176,12255],{}," itself:",[104,18179,18181],{"className":106,"code":18180,"language":108,"meta":48,"style":48},"int[] canBusIds = new int[10]; \u002F\u002F valid indices: 0 through 9\n\u002F\u002F ArrayIndexOutOfBoundsException — 10 is one past the end\nSystem.out.println(canBusIds[10]);\n",[95,18182,18183,18188,18193],{"__ignoreMap":48},[112,18184,18185],{"class":114,"line":115},[112,18186,18187],{},"int[] canBusIds = new int[10]; \u002F\u002F valid indices: 0 through 9\n",[112,18189,18190],{"class":114,"line":49},[112,18191,18192],{},"\u002F\u002F ArrayIndexOutOfBoundsException — 10 is one past the end\n",[112,18194,18195],{"class":114,"line":126},[112,18196,18197],{},"System.out.println(canBusIds[10]);\n",[15,18199,18200,18201,3181,18204,18207],{},"This is the single most common loop-bound mistake — writing ",[95,18202,18203],{},"i \u003C= array.length",[95,18205,18206],{},"i \u003C array.length",". See Lesson 9.1 (arrays) and 9.2 (ArrayList) for the full indexing rules.",[69,18209,18211],{"id":18210},"ignoring-a-return-value","Ignoring a Return Value",[15,18213,18214,18215,322,18218,325,18221,18224,18225,18227,18228,18230],{},"Methods like ",[95,18216,18217],{},"String.toUpperCase()",[95,18219,18220],{},".trim()",[95,18222,18223],{},".replace()"," don't modify the object they're called on — ",[95,18226,361],{}," is immutable — they ",[494,18229,3632],{}," a new value. Calling one and throwing away the result does nothing:",[104,18232,18234],{"className":106,"code":18233,"language":108,"meta":48,"style":48},"String teamName = \"shockwave\";\nteamName.toUpperCase();               \u002F\u002F return value discarded — teamName is unchanged\nteamName = teamName.toUpperCase();    \u002F\u002F correct — reassign the result\n",[95,18235,18236,18241,18246],{"__ignoreMap":48},[112,18237,18238],{"class":114,"line":115},[112,18239,18240],{},"String teamName = \"shockwave\";\n",[112,18242,18243],{"class":114,"line":49},[112,18244,18245],{},"teamName.toUpperCase();               \u002F\u002F return value discarded — teamName is unchanged\n",[112,18247,18248],{"class":114,"line":126},[112,18249,18250],{},"teamName = teamName.toUpperCase();    \u002F\u002F correct — reassign the result\n",[15,18252,18253],{},"See Lesson 6.1 for the full list of String methods that work this way.",[69,18255,18257],{"id":18256},"switch-fall-through","switch Fall-Through",[15,18259,18260,18261,18263,18264,476,18266,18268,18269,18271],{},"A colon-style ",[95,18262,5700],{}," (Lesson 5.12) keeps running into the ",[494,18265,9617],{},[95,18267,5802],{}," once one matches, unless a ",[95,18270,5806],{}," stops it — forgetting one is a classic bug:",[104,18273,18275],{"className":106,"code":18274,"language":108,"meta":48,"style":48},"switch (day)\n{\n    case 1:\n        System.out.println(\"Mon\");\n    case 2:                          \u002F\u002F day == 2 starts here...\n        System.out.println(\"Tue\");\n    case 3:                          \u002F\u002F ...and falls through to here too\n        System.out.println(\"Wed\");\n        break;\n    default:\n        System.out.println(\"other\");\n}\n\u002F\u002F day == 2 prints both \"Tue\" and \"Wed\" — not just \"Tue\"\n",[95,18276,18277,18282,18286,18290,18295,18300,18305,18310,18315,18319,18323,18328,18332],{"__ignoreMap":48},[112,18278,18279],{"class":114,"line":115},[112,18280,18281],{},"switch (day)\n",[112,18283,18284],{"class":114,"line":49},[112,18285,123],{},[112,18287,18288],{"class":114,"line":126},[112,18289,5733],{},[112,18291,18292],{"class":114,"line":132},[112,18293,18294],{},"        System.out.println(\"Mon\");\n",[112,18296,18297],{"class":114,"line":138},[112,18298,18299],{},"    case 2:                          \u002F\u002F day == 2 starts here...\n",[112,18301,18302],{"class":114,"line":144},[112,18303,18304],{},"        System.out.println(\"Tue\");\n",[112,18306,18307],{"class":114,"line":150},[112,18308,18309],{},"    case 3:                          \u002F\u002F ...and falls through to here too\n",[112,18311,18312],{"class":114,"line":2276},[112,18313,18314],{},"        System.out.println(\"Wed\");\n",[112,18316,18317],{"class":114,"line":2282},[112,18318,5743],{},[112,18320,18321],{"class":114,"line":2288},[112,18322,5780],{},[112,18324,18325],{"class":114,"line":5760},[112,18326,18327],{},"        System.out.println(\"other\");\n",[112,18329,18330],{"class":114,"line":5766},[112,18331,153],{},[112,18333,18334],{"class":114,"line":5772},[112,18335,18336],{},"\u002F\u002F day == 2 prints both \"Tue\" and \"Wed\" — not just \"Tue\"\n",[15,18338,18339,18340,18343],{},"Arrow-style ",[95,18341,18342],{},"case ->"," (also Lesson 5.12) never falls through, which is why this course defaults to it.",[69,18345,462],{"id":461},[19,18347,18348,18354],{},[22,18349,18350,18353],{},[25,18351,18352],{},"Treating this chapter as the complete list of Java mistakes."," It isn't — it's the handful the original deck happened to flag. Real practice will surface plenty more (this chapter is expected to grow).",[22,18355,18356,18359,18360,6439,18362,176,18364,18366],{},[25,18357,18358],{},"Fixing the symptom instead of the cause."," E.g., wrapping a ",[95,18361,4678],{},[95,18363,14828],{},[95,18365,14831],{}," (Lesson 12) instead of fixing why the object was never constructed in the first place.",[69,18368,501],{"id":500},[19,18370,18371,18387,18393,18398,18411,18424],{},[22,18372,1396,18373,18375,18376,18378,18379,18381,18382,14270,18384,18386],{},[95,18374,1921],{}," for primitives, ",[95,18377,7836],{}," for objects (Lesson 6.1) — except enums, where ",[95,18380,1921],{}," is safe. Watch ",[95,18383,17996],{},[95,18385,1869],{}," cache.",[22,18388,18389,18392],{},[95,18390,18391],{},"int \u002F int"," truncates; make at least one operand a floating-point type to keep the fractional part (Lesson 2.4).",[22,18394,18395,18397],{},[95,18396,4678],{}," means something was used before it was actually constructed — always initialize before use (Lessons 4.4–4.6, 9.1).",[22,18399,18400,18401,4029,18403,7740,18405,18407,18408,18410],{},"Valid indices run from ",[95,18402,1365],{},[95,18404,12099],{},[95,18406,14320],{},") — never ",[95,18409,12255],{}," itself (Lessons 9.1, 9.2).",[22,18412,18413,18414,18416,18417,12778,18419,18421,18422,79],{},"A discarded ",[95,18415,361],{}," method return value does nothing; a colon-style ",[95,18418,5700],{},[95,18420,5806],{}," falls through to the next ",[95,18423,5802],{},[22,18425,18426],{},"This is a living checklist, not a finished one — expect it to grow as more real gotchas surface through practice.",[15,18428,544,18429,548,18432,18435],{},[95,18430,18431],{},"mechacoder-test",[95,18433,18434],{},"src\u002Flessons\u002Fjava-1.js",", slide 13 (\"Common Gotchas\") — original deck content, no external citation",[554,18437,556],{},{"title":48,"searchDepth":49,"depth":49,"links":18439},[18440,18441,18442,18443,18444,18445,18446,18447],{"id":17914,"depth":49,"text":17915},{"id":18058,"depth":49,"text":18059},{"id":4881,"depth":49,"text":4678},{"id":18159,"depth":49,"text":18160},{"id":18210,"depth":49,"text":18211},{"id":18256,"depth":49,"text":18257},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},"This chapter is a quick-reference checklist, not new material — each item below is taught in full elsewhere in this curriculum. Its job is to put the most common real mistakes side by side, since they tend to resurface long after the lesson that first covered them. Note: this list is expected to grow once real code-review and exercise practice surfaces more of the mistakes people actually make — it currently only covers what the original deck flagged.",{"outlineRef":18450,"status":570},"13 — Common Gotchas (no citation — deck-original content)","\u002Fshockwave-curriculum\u002Flessons\u002Fch13-common-gotchas\u002F13-common-gotchas",{"title":17899,"description":18448},"shockwave-curriculum\u002Flessons\u002Fch13-common-gotchas\u002F13-common-gotchas","DgF-Uy1JCYxfyYXyoXyPMb1IRo4hAx5K5H3SbD9BwhA",{"id":18456,"title":18457,"body":18458,"description":48,"extension":51,"meta":18596,"navigation":55,"path":18598,"seo":18599,"stem":18600,"__hash__":18601},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch14-why-design-patterns\u002F14-why-design-patterns.md","Why Design Patterns?",{"type":8,"value":18459,"toc":18589},[18460,18463,18467,18479,18493,18498,18505,18509,18519,18525,18535,18539,18549,18551,18565,18567,18581],[11,18461,18457],{"id":18462},"why-design-patterns",[69,18464,18466],{"id":18465},"what-this-chapter-starts","What This Chapter Starts",[15,18468,18469,18470,537,18472,18474,18475,18478],{},"Everything up to Ch.13 was mostly one class at a time, with a few interacting helper classes along the way (7.3's ",[95,18471,10627],{},[95,18473,10623],{},", for instance) — variables, control flow, arrays, a class with a few methods. From here on (\"Java II\"), the curriculum shifts to how ",[494,18476,18477],{},"multiple"," classes work together as a codebase grows — the concerns become organization, reuse, and change over time, not just \"does this one method work.\"",[15,18480,405,18481,18484,18485,18488,18489,18492],{},[25,18482,18483],{},"design pattern"," is a named, reusable solution to a problem that keeps showing up across different programs — not a specific piece of code to copy-paste, but a ",[494,18486,18487],{},"shape"," of solution (which classes exist, how they relate) that's been proven to work well for that kind of problem. The chapters that follow first build the ",[25,18490,18491],{},"language tools"," patterns depend on — collections (Ch.15), generics (Ch.16), inheritance and polymorphism (Ch.17–18), and interfaces (Ch.19) — then walk through the real patterns used in FRC codebases, in chapter order: the IO-Layer Pattern (Ch.20), Static Factories (Ch.21), the Builder Pattern (Ch.22), and eventually the biggest one, Command-Based Programming itself (Ch.25).",[10690,18494,18495],{},[15,18496,18497],{},"\"Code is read much more often than it is written.\" — Guido van Rossum (adapted)",[15,18499,18500,18501,18504],{},"That quote is the real motivation for this whole unit. A robot's codebase gets read by every teammate who touches it, every mentor reviewing it, and by ",[494,18502,18503],{},"you"," again in six months — far more often than it gets freshly written. Patterns exist because they make code easier to read and change later, not just easier to write once.",[69,18506,18508],{"id":18507},"why-bother","Why Bother",[15,18510,18511,18514,18515,18518],{},[25,18512,18513],{},"Scalability."," A single ",[95,18516,18517],{},"Robot.java"," file with everything crammed inside works fine for a \"blink an LED\" program. It stops working once a robot has a drivetrain, an intake, a shooter, vision processing, and autonomous routines all interacting — patterns are how experienced teams keep that complexity organized instead of it collapsing into an unmaintainable mess.",[15,18520,18521,18524],{},[25,18522,18523],{},"A common language."," Telling another mentor \"I'm using a Factory here\" or \"this is a Builder\" communicates an entire shape of design in a few words — they immediately know how the pieces relate, without you having to walk through every class. Patterns are shared vocabulary across the whole FRC (and broader software) community, not something invented per-team.",[15,18526,18527,18530,18531,18534],{},[25,18528,18529],{},"Testability."," Code built around patterns tends to be more ",[25,18532,18533],{},"decoupled"," — pieces don't reach directly into each other's internals, so they can be swapped, simulated, or tested independently. A drivetrain built with a clean pattern can be tested in simulation, with no real motors or robot required; one where every class directly depends on every other class often can't be tested at all without the physical hardware present.",[69,18536,18538],{"id":18537},"what-this-chapter-is-not","What This Chapter Is Not",[15,18540,18541,18542,18544,18545,18548],{},"This chapter doesn't teach a specific pattern — the chapters immediately following it do that one at a time. Its only job is to answer \"why does any of this matter,\" before two kinds of chapters begin: language tools (Advanced Collections Ch.15, Generics Ch.16, Inheritance and Polymorphism Ch.17–18, Interfaces Ch.19, and later Encapsulation & ",[95,18543,381],{}," Ch.23, ",[95,18546,18547],{},"Optional"," Ch.24) and the named patterns themselves (Ch.20–22 and Ch.25).",[69,18550,462],{"id":461},[19,18552,18553,18559],{},[22,18554,18555,18558],{},[25,18556,18557],{},"Reaching for a pattern before there's a real problem it solves."," Patterns exist to manage genuine complexity — forcing one onto a two-class program just because \"patterns are good practice\" usually adds complexity instead of removing it.",[22,18560,18561,18564],{},[25,18562,18563],{},"Treating pattern names as a vocabulary test rather than a design tool."," The value of saying \"this is a Factory\" is that it communicates real structure to a teammate — not that it sounds impressive.",[69,18566,501],{"id":500},[19,18568,18569,18575,18578],{},[22,18570,18571,18572,18574],{},"A design pattern is a reusable ",[494,18573,18487],{}," of solution to a recurring design problem, not a snippet of code to copy.",[22,18576,18577],{},"Patterns matter for three concrete reasons: keeping a growing codebase organized (scalability), giving the team shared vocabulary (common language), and making code easier to test in isolation (decoupling).",[22,18579,18580],{},"The chapters that follow each teach one specific, real pattern used in actual FRC codebases.",[15,18582,544,18583,548,18585,18588],{},[95,18584,18431],{},[95,18586,18587],{},"src\u002Flessons\u002Fjava-2.js",", slide 1 (\"Why Design Patterns?\") — original deck content, no external citation",{"title":48,"searchDepth":49,"depth":49,"links":18590},[18591,18592,18593,18594,18595],{"id":18465,"depth":49,"text":18466},{"id":18507,"depth":49,"text":18508},{"id":18537,"depth":49,"text":18538},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":18597,"status":570,"noWorkedExample":55},"14 — Why Design Patterns? (no citation — deck-original content)","\u002Fshockwave-curriculum\u002Flessons\u002Fch14-why-design-patterns\u002F14-why-design-patterns",{"title":18457,"description":48},"shockwave-curriculum\u002Flessons\u002Fch14-why-design-patterns\u002F14-why-design-patterns","1Vbjf94Z4cQ3Y7UgE-Nqyk4G9BjH2AEzhOo5D5brubA",{"id":18603,"title":18604,"body":18605,"description":19714,"extension":51,"meta":19715,"navigation":55,"path":19717,"seo":19718,"stem":19719,"__hash__":19720},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch15-advanced-collections\u002F15-advanced-collections.md","Advanced Collections (Set\u002FQueue\u002FMap)",{"type":8,"value":18606,"toc":19705},[18607,18610,18642,18683,18687,18698,18718,18724,18765,18774,18791,18848,18852,18861,18929,18976,19011,19015,19029,19106,19109,19143,19204,19208,19252,19293,19337,19371,19400,19404,19429,19449,19462,19464,19568,19570,19686,19703],[11,18608,18604],{"id":18609},"advanced-collections-setqueuemap",[15,18611,18612,18613,18615,18616,18618,18619,18624,18625,176,18630,18635,18636,18641],{},"Ch.9 covered ",[95,18614,12343],{}," and a basic ",[95,18617,12950],{},". Three more collection types round out the toolbox, each solving a problem the others don't: ",[25,18620,18621],{},[95,18622,18623],{},"Set"," (no duplicates, ever), ",[25,18626,18627],{},[95,18628,18629],{},"Queue",[25,18631,18632],{},[95,18633,18634],{},"Deque"," (order of processing matters more than random access), and a deeper look at ",[25,18637,18638],{},[95,18639,18640],{},"Map"," (iterating both keys and values together, and choosing an ordering).",[15,18643,18644,18645,18647,18648,18651,18652,322,18654,322,18656,325,18658,18660,18661,18664,18665,18668,18669,322,18672,18675,18676,176,18678,176,18680,18682],{},"Quick vocabulary note before diving in: just like ",[95,18646,12343],{}," (Ch.9) is really an implementation of the ",[95,18649,18650],{},"List"," interface, ",[95,18653,18623],{},[95,18655,18629],{},[95,18657,18634],{},[95,18659,18640],{}," are themselves ",[25,18662,18663],{},"interfaces",", not classes — you never write ",[95,18666,18667],{},"new Set\u003CInteger>()"," (that doesn't compile), only ",[95,18670,18671],{},"new HashSet\u003CInteger>()",[95,18673,18674],{},"new TreeSet\u003CInteger>()",", and so on, stored in a variable declared by the interface type. Ch.19 covers what an interface actually is; for now, read ",[95,18677,18623],{},[95,18679,18629],{},[95,18681,18640],{}," as \"the name for a family of collection classes that all support this common set of operations.\"",[69,18684,18686],{"id":18685},"set-no-duplicates-ever","Set: No Duplicates, Ever",[15,18688,405,18689,18691,18692,18694,18695,18697],{},[95,18690,18623],{}," is a collection that flatly refuses duplicate elements — calling ",[95,18693,12726],{}," with something already present just does nothing (and returns ",[95,18696,664],{},"), rather than adding a second copy:",[104,18699,18701],{"className":106,"code":18700,"language":108,"meta":48,"style":48},"Set\u003CInteger> usedCanIds = new HashSet\u003CInteger>();\nusedCanIds.add(5);  \u002F\u002F true — added\nusedCanIds.add(5);  \u002F\u002F false — already present, nothing changed\n",[95,18702,18703,18708,18713],{"__ignoreMap":48},[112,18704,18705],{"class":114,"line":115},[112,18706,18707],{},"Set\u003CInteger> usedCanIds = new HashSet\u003CInteger>();\n",[112,18709,18710],{"class":114,"line":49},[112,18711,18712],{},"usedCanIds.add(5);  \u002F\u002F true — added\n",[112,18714,18715],{"class":114,"line":126},[112,18716,18717],{},"usedCanIds.add(5);  \u002F\u002F false — already present, nothing changed\n",[15,18719,18720,18721,18723],{},"That makes ",[95,18722,18623],{}," the natural tool for catching configuration conflicts — e.g. verifying no two devices on the robot were accidentally wired to the same CAN ID:",[104,18725,18727],{"className":106,"code":18726,"language":108,"meta":48,"style":48},"Set\u003CInteger> seenIds = new HashSet\u003CInteger>();\nfor (int id : allConfiguredCanIds)\n{\n    if (!seenIds.add(id)) \u002F\u002F add() returns false if it was already there\n    {\n        reportWarning(\"Duplicate CAN ID detected: \" + id);\n    }\n}\n",[95,18728,18729,18734,18739,18743,18748,18752,18757,18761],{"__ignoreMap":48},[112,18730,18731],{"class":114,"line":115},[112,18732,18733],{},"Set\u003CInteger> seenIds = new HashSet\u003CInteger>();\n",[112,18735,18736],{"class":114,"line":49},[112,18737,18738],{},"for (int id : allConfiguredCanIds)\n",[112,18740,18741],{"class":114,"line":126},[112,18742,123],{},[112,18744,18745],{"class":114,"line":132},[112,18746,18747],{},"    if (!seenIds.add(id)) \u002F\u002F add() returns false if it was already there\n",[112,18749,18750],{"class":114,"line":138},[112,18751,135],{},[112,18753,18754],{"class":114,"line":144},[112,18755,18756],{},"        reportWarning(\"Duplicate CAN ID detected: \" + id);\n",[112,18758,18759],{"class":114,"line":150},[112,18760,147],{},[112,18762,18763],{"class":114,"line":2276},[112,18764,153],{},[15,18766,1866,18767,537,18770,18773],{},[95,18768,18769],{},"allConfiguredCanIds",[95,18771,18772],{},"reportWarning"," stand in for this team's own array and logging method — this snippet is a fragment, not a complete program.)",[15,18775,18776,18779,18780,18783,18784,18787,18788,18790],{},[95,18777,18778],{},"HashSet"," (fastest, no ordering guarantee) is the usual default; ",[95,18781,18782],{},"LinkedHashSet"," remembers insertion order; ",[95,18785,18786],{},"TreeSet"," keeps elements sorted. All three still refuse duplicates — they mainly differ in iteration order (and, for ",[95,18789,18786],{},", in one extra requirement covered in the pitfalls below).",[15,18792,18793,18795,18796,18799,18800,18803,18804,18807,18808,18811,18812,18815,18816,18819,18820,18822,18823,176,18826,176,18829,476,18832,18838,18839,18841,18842,18844,18845],{},[95,18794,18623],{}," also supports set algebra directly as methods: ",[95,18797,18798],{},"s1.containsAll(s2)"," (is ",[95,18801,18802],{},"s2"," a subset of ",[95,18805,18806],{},"s1","?), ",[95,18809,18810],{},"s1.addAll(s2)"," (union), ",[95,18813,18814],{},"s1.retainAll(s2)"," (intersection — keep only what's in both), ",[95,18817,18818],{},"s1.removeAll(s2)"," (difference — remove anything also in ",[95,18821,18802],{},"). All three of ",[95,18824,18825],{},"addAll",[95,18827,18828],{},"retainAll",[95,18830,18831],{},"removeAll",[25,18833,18834,18835,18837],{},"change ",[95,18836,18806],{}," in place"," and return a ",[95,18840,657],{}," (whether ",[95,18843,18806],{}," actually changed) — none of them returns a new set. To keep the originals untouched, copy first: ",[95,18846,18847],{},"Set\u003CInteger> intersection = new HashSet\u003CInteger>(s1); intersection.retainAll(s2);",[69,18849,18851],{"id":18850},"queue-first-in-first-out","Queue: First-In, First-Out",[15,18853,405,18854,18856,18857,18860],{},[95,18855,18629],{}," holds elements for later processing, normally in ",[25,18858,18859],{},"FIFO"," order (first-in-first-out) — think of a queue of autonomous routine steps waiting to run in the order they were scheduled. Every operation comes in two flavors: one throws an exception on failure, the other returns a safe placeholder value instead.",[3819,18862,18863,18875],{},[3822,18864,18865],{},[3825,18866,18867,18869,18872],{},[3828,18868,12661],{},[3828,18870,18871],{},"Throws on failure",[3828,18873,18874],{},"Returns a placeholder",[3838,18876,18877,18895,18912],{},[3825,18878,18879,18882,18887],{},[3843,18880,18881],{},"Insert",[3843,18883,18884],{},[95,18885,18886],{},"add(e)",[3843,18888,18889,18892,18893,1282],{},[95,18890,18891],{},"offer(e)"," (returns ",[95,18894,664],{},[3825,18896,18897,18900,18904],{},[3843,18898,18899],{},"Remove",[3843,18901,18902],{},[95,18903,14277],{},[3843,18905,18906,18892,18909,18911],{},[95,18907,18908],{},"poll()",[95,18910,4645],{}," if empty)",[3825,18913,18914,18917,18922],{},[3843,18915,18916],{},"Peek (don't remove)",[3843,18918,18919],{},[95,18920,18921],{},"element()",[3843,18923,18924,18892,18927,18911],{},[95,18925,18926],{},"peek()",[95,18928,4645],{},[104,18930,18932],{"className":106,"code":18931,"language":108,"meta":48,"style":48},"Queue\u003CString> pendingFaults = new LinkedList\u003CString>();\npendingFaults.add(\"Camera 1 disconnected\");\npendingFaults.add(\"Low battery voltage\");\n\nwhile (!pendingFaults.isEmpty())\n{\n    \u002F\u002F poll() removes and returns the oldest fault first\n    System.out.println(\"Handling: \" + pendingFaults.poll());\n}\n",[95,18933,18934,18939,18944,18949,18953,18958,18962,18967,18972],{"__ignoreMap":48},[112,18935,18936],{"class":114,"line":115},[112,18937,18938],{},"Queue\u003CString> pendingFaults = new LinkedList\u003CString>();\n",[112,18940,18941],{"class":114,"line":49},[112,18942,18943],{},"pendingFaults.add(\"Camera 1 disconnected\");\n",[112,18945,18946],{"class":114,"line":126},[112,18947,18948],{},"pendingFaults.add(\"Low battery voltage\");\n",[112,18950,18951],{"class":114,"line":132},[112,18952,907],{"emptyLinePlaceholder":55},[112,18954,18955],{"class":114,"line":138},[112,18956,18957],{},"while (!pendingFaults.isEmpty())\n",[112,18959,18960],{"class":114,"line":144},[112,18961,123],{},[112,18963,18964],{"class":114,"line":150},[112,18965,18966],{},"    \u002F\u002F poll() removes and returns the oldest fault first\n",[112,18968,18969],{"class":114,"line":2276},[112,18970,18971],{},"    System.out.println(\"Handling: \" + pendingFaults.poll());\n",[112,18973,18974],{"class":114,"line":2282},[112,18975,153],{},[15,18977,18978,176,18980,18982,18983,18985,18986,18989,18990,18993,18994,18996,18997,14935,18999,19001,19002,19004,19005,19007,19008,19010],{},[95,18979,18908],{},[95,18981,18926],{}," are usually the safer default in real code — they hand back ",[95,18984,4645],{}," instead of throwing when the queue happens to be empty, which is often a completely normal state (no faults right now) rather than an error. Watch out with a ",[95,18987,18988],{},"Queue\u003CInteger>"," (or any primitive wrapper) though: ",[95,18991,18992],{},"int x = intQueue.poll();"," on an empty queue throws ",[95,18995,4678],{},", because assigning ",[95,18998,18908],{},[95,19000,4645],{}," into a primitive ",[95,19003,603],{}," unboxes it immediately (Ch.9.2). Check ",[95,19006,9092],{}," first, or keep the result as ",[95,19009,1869],{}," instead of unboxing right away.",[69,19012,19014],{"id":19013},"deque-both-ends-at-once","Deque: Both Ends at Once",[15,19016,405,19017,19021,19022,19025,19026,19028],{},[25,19018,19019],{},[95,19020,18634],{}," (\"deck,\" double-ended queue) supports inserting and removing from ",[494,19023,19024],{},"either"," end, which means a single ",[95,19027,18634],{}," can act as a FIFO queue, a LIFO stack, or both:",[3819,19030,19031,19043],{},[3822,19032,19033],{},[3825,19034,19035,19037,19040],{},[3828,19036,12661],{},[3828,19038,19039],{},"First (front)",[3828,19041,19042],{},"Last (back)",[3838,19044,19045,19065,19085],{},[3825,19046,19047,19049,19057],{},[3843,19048,18881],{},[3843,19050,19051,3848,19054],{},[95,19052,19053],{},"addFirst(e)",[95,19055,19056],{},"offerFirst(e)",[3843,19058,19059,3848,19062],{},[95,19060,19061],{},"addLast(e)",[95,19063,19064],{},"offerLast(e)",[3825,19066,19067,19069,19077],{},[3843,19068,18899],{},[3843,19070,19071,3848,19074],{},[95,19072,19073],{},"removeFirst()",[95,19075,19076],{},"pollFirst()",[3843,19078,19079,3848,19082],{},[95,19080,19081],{},"removeLast()",[95,19083,19084],{},"pollLast()",[3825,19086,19087,19090,19098],{},[3843,19088,19089],{},"Examine",[3843,19091,19092,3848,19095],{},[95,19093,19094],{},"getFirst()",[95,19096,19097],{},"peekFirst()",[3843,19099,19100,3848,19103],{},[95,19101,19102],{},"getLast()",[95,19104,19105],{},"peekLast()",[15,19107,19108],{},"A common use: an undo stack for the last few climb-sequence steps, where you only ever add\u002Fremove from one end (LIFO — last one added is the first one undone):",[104,19110,19112],{"className":106,"code":19111,"language":108,"meta":48,"style":48},"Deque\u003CString> climbSteps = new ArrayDeque\u003CString>();\nclimbSteps.addLast(\"Extend to high bar\");\nclimbSteps.addLast(\"Release from mid bar\");\n\n\u002F\u002F \"Release from mid bar\" — undo the most recent step\nString lastStep = climbSteps.removeLast();\n",[95,19113,19114,19119,19124,19129,19133,19138],{"__ignoreMap":48},[112,19115,19116],{"class":114,"line":115},[112,19117,19118],{},"Deque\u003CString> climbSteps = new ArrayDeque\u003CString>();\n",[112,19120,19121],{"class":114,"line":49},[112,19122,19123],{},"climbSteps.addLast(\"Extend to high bar\");\n",[112,19125,19126],{"class":114,"line":126},[112,19127,19128],{},"climbSteps.addLast(\"Release from mid bar\");\n",[112,19130,19131],{"class":114,"line":132},[112,19132,907],{"emptyLinePlaceholder":55},[112,19134,19135],{"class":114,"line":138},[112,19136,19137],{},"\u002F\u002F \"Release from mid bar\" — undo the most recent step\n",[112,19139,19140],{"class":114,"line":144},[112,19141,19142],{},"String lastStep = climbSteps.removeLast();\n",[15,19144,19145,19148,19149,19151,19152,19155,19156,19158,19159,176,19162,176,19165,19167,19168,19171,19172,322,19175,19171,19178,19181,19182,19184,19185,19188,19189,19192,19193,19196,19197,19199,19200,19203],{},[95,19146,19147],{},"ArrayDeque"," is the standard general-purpose ",[95,19150,18634],{}," implementation — generally faster than ",[95,19153,19154],{},"LinkedList"," for this purpose, with no capacity limit. A ",[95,19157,18634],{}," also has stack-flavored ",[95,19160,19161],{},"push(e)",[95,19163,19164],{},"pop()",[95,19166,18926],{}," methods, which just work on the front (",[95,19169,19170],{},"push"," = ",[95,19173,19174],{},"addFirst",[95,19176,19177],{},"pop",[95,19179,19180],{},"removeFirst","). Prefer ",[95,19183,19147],{}," over the old ",[95,19186,19187],{},"java.util.Stack"," class — ",[95,19190,19191],{},"Stack"," is a legacy holdover with locking overhead this course never needs. (A ",[95,19194,19195],{},"PriorityQueue"," is a different ",[95,19198,18629],{}," implementation worth knowing the name of: it always polls back the ",[494,19201,19202],{},"smallest"," element first, rather than the oldest — outside what this lesson covers.)",[69,19205,19207],{"id":19206},"map-revisited-iterating-both-keys-and-values","Map, Revisited: Iterating Both Keys and Values",[15,19209,19210,19211,176,19214,322,19216,176,19219,176,19222,176,19224,19227,19228,19230,19231,19234,19235,19238,19239,19241,19242,19245,19246,537,19249,738],{},"Ch.9.3 covered ",[95,19212,19213],{},"put",[95,19215,4956],{},[95,19217,19218],{},"containsKey",[95,19220,19221],{},"getOrDefault",[95,19223,12729],{},[95,19225,19226],{},"size",", and looping over ",[95,19229,13048],{}," — all of that still applies here. ",[95,19232,19233],{},"Map.entrySet()"," gives every key ",[494,19236,19237],{},"and"," value together in one pass, avoiding a repeated ",[95,19240,13052],{}," call for each key. Each item it hands back is a ",[95,19243,19244],{},"Map.Entry\u003CK, V>"," — a small read-only key\u002Fvalue pair object, with ",[95,19247,19248],{},"getKey()",[95,19250,19251],{},"getValue()",[104,19253,19255],{"className":106,"code":19254,"language":108,"meta":48,"style":48},"Map\u003CInteger, Double> motorOffsets = new HashMap\u003CInteger, Double>();\nmotorOffsets.put(5, 0.02);\nmotorOffsets.put(6, -0.01);\n\nfor (Map.Entry\u003CInteger, Double> entry : motorOffsets.entrySet())\n{\n    System.out.println(\"CAN ID \" + entry.getKey() + \" -> offset \" + entry.getValue());\n}\n",[95,19256,19257,19262,19267,19271,19275,19280,19284,19289],{"__ignoreMap":48},[112,19258,19259],{"class":114,"line":115},[112,19260,19261],{},"Map\u003CInteger, Double> motorOffsets = new HashMap\u003CInteger, Double>();\n",[112,19263,19264],{"class":114,"line":49},[112,19265,19266],{},"motorOffsets.put(5, 0.02);\n",[112,19268,19269],{"class":114,"line":126},[112,19270,12987],{},[112,19272,19273],{"class":114,"line":132},[112,19274,907],{"emptyLinePlaceholder":55},[112,19276,19277],{"class":114,"line":138},[112,19278,19279],{},"for (Map.Entry\u003CInteger, Double> entry : motorOffsets.entrySet())\n",[112,19281,19282],{"class":114,"line":144},[112,19283,123],{},[112,19285,19286],{"class":114,"line":150},[112,19287,19288],{},"    System.out.println(\"CAN ID \" + entry.getKey() + \" -> offset \" + entry.getValue());\n",[112,19290,19291],{"class":114,"line":2276},[112,19292,153],{},[15,19294,19295,19296,19298,19299,19301,19302,19305,19306,19309,19310,13173,19312,19315,19316,19318,19319,13173,19321,19324,19325,19327,19328,19330,19331,19333,19334,19336],{},"Just like ",[95,19297,18623],{},", a plain ",[95,19300,12950],{}," gives no ordering guarantee. Swapping the implementation type is enough to change that, with no other code changes needed to the lines that ",[494,19303,19304],{},"use"," the map — but a copy constructor only ever preserves the ",[494,19307,19308],{},"source"," map's own iteration order. Copying a ",[95,19311,12950],{},[95,19313,19314],{},"TreeMap"," is fine, because a ",[95,19317,19314],{}," re-sorts by key regardless of where the entries came from. Copying a ",[95,19320,12950],{},[95,19322,19323],{},"LinkedHashMap",", though, just keeps the ",[95,19326,12950],{},"'s unpredictable order — the original ",[95,19329,19213],{}," order was never recorded anywhere, so there's nothing to preserve. To actually get insertion order, build the ",[95,19332,19323],{}," from empty and ",[95,19335,19213],{}," into it directly:",[104,19338,19340],{"className":106,"code":19339,"language":108,"meta":48,"style":48},"\u002F\u002F sorted by key — copying in is fine here, TreeMap always re-sorts\nMap\u003CInteger, Double> sorted = new TreeMap\u003CInteger, Double>(motorOffsets);\n\nMap\u003CInteger, Double> byInsertOrder = new LinkedHashMap\u003CInteger, Double>();\nbyInsertOrder.put(5, 0.02);\nbyInsertOrder.put(6, -0.01); \u002F\u002F LinkedHashMap remembers put order, starting from empty\n",[95,19341,19342,19347,19352,19356,19361,19366],{"__ignoreMap":48},[112,19343,19344],{"class":114,"line":115},[112,19345,19346],{},"\u002F\u002F sorted by key — copying in is fine here, TreeMap always re-sorts\n",[112,19348,19349],{"class":114,"line":49},[112,19350,19351],{},"Map\u003CInteger, Double> sorted = new TreeMap\u003CInteger, Double>(motorOffsets);\n",[112,19353,19354],{"class":114,"line":126},[112,19355,907],{"emptyLinePlaceholder":55},[112,19357,19358],{"class":114,"line":132},[112,19359,19360],{},"Map\u003CInteger, Double> byInsertOrder = new LinkedHashMap\u003CInteger, Double>();\n",[112,19362,19363],{"class":114,"line":138},[112,19364,19365],{},"byInsertOrder.put(5, 0.02);\n",[112,19367,19368],{"class":114,"line":144},[112,19369,19370],{},"byInsertOrder.put(6, -0.01); \u002F\u002F LinkedHashMap remembers put order, starting from empty\n",[15,19372,19373,19374,322,19377,322,19380,322,19383,19386,19387,322,19389,322,19391,322,19393,19395,19396,19399],{},"This is the payoff of always declaring a variable by its interface type (",[95,19375,19376],{},"List\u003CE>",[95,19378,19379],{},"Map\u003CK, V>",[95,19381,19382],{},"Set\u003CE>",[95,19384,19385],{},"Queue\u003CE>",") rather than its concrete implementation (",[95,19388,12343],{},[95,19390,12950],{},[95,19392,18778],{},[95,19394,19154],{},") — changing which concrete class gets constructed is a one-line change, because every line that ",[494,19397,19398],{},"uses"," the collection only ever depends on the interface.",[69,19401,19403],{"id":19402},"fixed-collections-listof-setof-mapof","Fixed Collections: List.of, Set.of, Map.of",[15,19405,19406,19407,322,19410,325,19413,19416,19417,19420,19421,19423,19424,176,19426,19428],{},"For data that's fixed once created — a small lookup table, a set of valid states — ",[95,19408,19409],{},"List.of(...)",[95,19411,19412],{},"Set.of(...)",[95,19414,19415],{},"Map.of(...)"," build an ",[25,19418,19419],{},"immutable"," collection in one line, with no ",[95,19422,2504],{}," and no separate ",[95,19425,12726],{},[95,19427,19213],{}," calls:",[104,19430,19432],{"className":106,"code":19431,"language":108,"meta":48,"style":48},"List\u003CString> allianceColors = List.of(\"Red\", \"Blue\");\nSet\u003CInteger> validPracticeFields = Set.of(1, 2, 3);\nMap\u003CString, Integer> startingSlots = Map.of(\"Left\", 1, \"Center\", 2, \"Right\", 3);\n",[95,19433,19434,19439,19444],{"__ignoreMap":48},[112,19435,19436],{"class":114,"line":115},[112,19437,19438],{},"List\u003CString> allianceColors = List.of(\"Red\", \"Blue\");\n",[112,19440,19441],{"class":114,"line":49},[112,19442,19443],{},"Set\u003CInteger> validPracticeFields = Set.of(1, 2, 3);\n",[112,19445,19446],{"class":114,"line":126},[112,19447,19448],{},"Map\u003CString, Integer> startingSlots = Map.of(\"Left\", 1, \"Center\", 2, \"Right\", 3);\n",[15,19450,13153,19451,322,19453,3283,19455,19457,19458,19461],{},[95,19452,12726],{},[95,19454,19213],{},[95,19456,12729],{}," on any of these throws ",[95,19459,19460],{},"UnsupportedOperationException"," — they're meant to be built once and only read afterward.",[69,19463,462],{"id":461},[19,19465,19466,19485,19500,19518,19535],{},[22,19467,19468,19474,19475,176,19477,19479,19480,176,19482,19484],{},[25,19469,13139,19470,260,19472,13142],{},[95,19471,18778],{},[95,19473,12950],{}," Neither does — reach for ",[95,19476,18782],{},[95,19478,19323],{}," if insertion order actually matters, or ",[95,19481,18786],{},[95,19483,19314],{}," if sorted order does.",[22,19486,19487,19494,19495,176,19497,19499],{},[25,19488,6835,19489,176,19491,19493],{},[95,19490,14277],{},[95,19492,18921],{}," on a queue that might be empty."," Both throw when empty — prefer ",[95,19496,18908],{},[95,19498,18926],{}," unless an empty queue genuinely represents a bug that should crash loudly.",[22,19501,19502,476,19505,19508,19509,4029,19511,19513,19514,19517],{},[25,19503,19504],{},"Declaring a collection variable by its concrete type instead of its interface.",[95,19506,19507],{},"HashMap\u003CK,V> m = new HashMap\u003CK,V>();"," locks every line that touches ",[95,19510,4766],{},[95,19512,12950],{},"'s specific behavior — declare it ",[95,19515,19516],{},"Map\u003CK,V> m = new HashMap\u003CK,V>();"," instead, so the implementation can change later without touching anything else.",[22,19519,19520,19534],{},[25,19521,19522,19523,176,19525,19527,19528,537,19531,79],{},"Putting your own class into a ",[95,19524,18778],{},[95,19526,12950],{}," without overriding both ",[95,19529,19530],{},"equals",[95,19532,19533],{},"hashCode"," Two objects that \"look equal\" still count as different keys\u002Felements unless both methods are overridden together — covered in full in Lesson 17.4.",[22,19536,19537,19544,19545,19548,19549,176,19552,19555,19556,176,19558,19560,19561,322,19563,322,19565,19567],{},[25,19538,19522,19539,176,19541,19543],{},[95,19540,18786],{},[95,19542,19314],{}," without teaching Java how to compare it."," Both need elements\u002Fkeys that can be compared to each other; a class with no defined ordering throws ",[95,19546,19547],{},"ClassCastException"," the first time one gets added. ",[95,19550,19551],{},"Comparable",[95,19553,19554],{},"Comparator",", the tools for that, are covered in Ch.19 — until then, only use ",[95,19557,18786],{},[95,19559,19314],{}," with types Java already knows how to order (",[95,19562,1869],{},[95,19564,361],{},[95,19566,8536],{},", ...).",[69,19569,501],{"id":500},[19,19571,19572,19604,19618,19641,19655,19671,19683],{},[22,19573,19574,322,19576,322,19578,322,19580,325,19582,19584,19585,322,19587,176,19589,176,19591,322,19593,176,19595,325,19597,176,19599,176,19601,19603],{},[95,19575,18650],{},[95,19577,18623],{},[95,19579,18629],{},[95,19581,18634],{},[95,19583,18640],{}," are interfaces, not classes — ",[95,19586,12343],{},[95,19588,18778],{},[95,19590,18786],{},[95,19592,18782],{},[95,19594,19154],{},[95,19596,19147],{},[95,19598,12950],{},[95,19600,19314],{},[95,19602,19323],{}," are the classes that implement them (Ch.19 covers interfaces in full).",[22,19605,19606,19608,19609,19611,19612,19614,19615,19617],{},[95,19607,18623],{}," guarantees no duplicates; ",[95,19610,18778],{}," is fastest with no ordering, ",[95,19613,18782],{}," keeps insertion order, ",[95,19616,18786],{}," keeps sorted order (and needs comparable elements).",[22,19619,19620,19622,19623,176,19625,176,19627,19630,19631,176,19634,176,19637,19640],{},[95,19621,18629],{}," processes elements FIFO by default; every operation has a throwing form (",[95,19624,12726],{},[95,19626,12729],{},[95,19628,19629],{},"element",") and a safe form (",[95,19632,19633],{},"offer",[95,19635,19636],{},"poll",[95,19638,19639],{},"peek",") that returns a placeholder instead of throwing.",[22,19642,19643,19645,19646,176,19648,176,19650,9388,19652,19654],{},[95,19644,18634],{}," supports both ends at once, letting one type serve as either a queue or a stack (",[95,19647,19170],{},[95,19649,19177],{},[95,19651,19639],{},[95,19653,19147],{}," is the standard general-purpose implementation.",[22,19656,19657,19659,19660,19663,19664,19667,19668,19670],{},[95,19658,19233],{}," iterates keys and values together as ",[95,19661,19662],{},"Map.Entry"," pairs; a copy constructor only preserves the ",[494,19665,19666],{},"source's"," iteration order, so build a ",[95,19669,19323],{}," from empty to get true insertion order.",[22,19672,19673,176,19676,176,19679,19682],{},[95,19674,19675],{},"List.of",[95,19677,19678],{},"Set.of",[95,19680,19681],{},"Map.of"," build small, fixed, immutable collections in one line.",[22,19684,19685],{},"Always declare collection variables by their interface type, not their concrete implementation — it's what makes swapping implementations a one-line change.",[15,19687,544,19688,548,19690,322,19693,322,19696,322,19699,19702],{},[95,19689,17008],{},[95,19691,19692],{},"oracle-java-tutorials\u002Fcollections-interfaces\u002F01-the-set-interface.md",[95,19694,19695],{},"02-the-queue-interface.md",[95,19697,19698],{},"03-the-deque-interface.md",[95,19700,19701],{},"04-the-map-interface.md"," (ORACLE 13.1-4)",[554,19704,556],{},{"title":48,"searchDepth":49,"depth":49,"links":19706},[19707,19708,19709,19710,19711,19712,19713],{"id":18685,"depth":49,"text":18686},{"id":18850,"depth":49,"text":18851},{"id":19013,"depth":49,"text":19014},{"id":19206,"depth":49,"text":19207},{"id":19402,"depth":49,"text":19403},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},"Ch.9 covered ArrayList and a basic HashMap. Three more collection types round out the toolbox, each solving a problem the others don't: Set (no duplicates, ever), Queue\u002FDeque (order of processing matters more than random access), and a deeper look at Map (iterating both keys and values together, and choosing an ordering).",{"outlineRef":19716,"status":15483},"15 — Advanced Collections (Set\u002FQueue\u002FMap) (ORACLE 13.1-4)","\u002Fshockwave-curriculum\u002Flessons\u002Fch15-advanced-collections\u002F15-advanced-collections",{"title":18604,"description":19714},"shockwave-curriculum\u002Flessons\u002Fch15-advanced-collections\u002F15-advanced-collections","lqvGgznmLjsbQE9jNTeDC0TREMXtwbvGnk5Km3KT_BE",{"id":19722,"title":19723,"body":19724,"description":20408,"extension":51,"meta":20409,"navigation":55,"path":20411,"seo":20412,"stem":20413,"__hash__":20414},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch16-writing-your-own-generics\u002F16-writing-your-own-generics.md","Writing Your Own Generics",{"type":8,"value":19725,"toc":20398},[19726,19729,19744,19748,19755,19775,19790,19796,19820,19824,19836,19873,19883,19913,19937,19943,20021,20025,20028,20064,20075,20079,20100,20118,20156,20180,20184,20204,20208,20215,20238,20249,20251,20327,20329,20373,20396],[11,19727,19723],{"id":19728},"writing-your-own-generics",[15,19730,19731,322,19734,322,19737,19740,19741,19743],{},[95,19732,19733],{},"List\u003CString>",[95,19735,19736],{},"Map\u003CInteger, Double>",[95,19738,19739],{},"ArrayList\u003CDouble>"," — every collection since Ch.9 has ",[494,19742,10432],{}," a generic type someone else wrote. This chapter is about writing your own.",[69,19745,19747],{"id":19746},"why-generics-exist","Why Generics Exist",[15,19749,19750,19751,19754],{},"Before generics, a reusable container had to work with the generic ",[95,19752,19753],{},"Object"," type, requiring an explicit cast every time you got something back out — and nothing stopped the wrong type from going in in the first place:",[104,19756,19758],{"className":106,"code":19757,"language":108,"meta":48,"style":48},"List list = new ArrayList();         \u002F\u002F no generics\nlist.add(\"hello\");\nString s = (String) list.get(0);     \u002F\u002F cast required, and could fail at runtime\n",[95,19759,19760,19765,19770],{"__ignoreMap":48},[112,19761,19762],{"class":114,"line":115},[112,19763,19764],{},"List list = new ArrayList();         \u002F\u002F no generics\n",[112,19766,19767],{"class":114,"line":49},[112,19768,19769],{},"list.add(\"hello\");\n",[112,19771,19772],{"class":114,"line":126},[112,19773,19774],{},"String s = (String) list.get(0);     \u002F\u002F cast required, and could fail at runtime\n",[15,19776,2424,19777,4875,19780,19783,19784,19786,19787,19789],{},[95,19778,19779],{},"(String)",[25,19781,19782],{},"cast",": it forces the compiler to treat the value as that type. If the object handed back weren't actually a ",[95,19785,361],{},", this line would compile fine and then throw ",[95,19788,19547],{}," at runtime instead of failing to compile.",[15,19791,19792,19793,19795],{},"With a type parameter, the compiler enforces correctness ",[494,19794,1814],{}," the program ever runs, and the cast disappears entirely:",[104,19797,19799],{"className":106,"code":19798,"language":108,"meta":48,"style":48},"List\u003CString> list = new ArrayList\u003CString>();\nlist.add(\"hello\");\n\u002F\u002F no cast — the compiler already knows it's a String\nString s = list.get(0);\n",[95,19800,19801,19806,19810,19815],{"__ignoreMap":48},[112,19802,19803],{"class":114,"line":115},[112,19804,19805],{},"List\u003CString> list = new ArrayList\u003CString>();\n",[112,19807,19808],{"class":114,"line":49},[112,19809,19769],{},[112,19811,19812],{"class":114,"line":126},[112,19813,19814],{},"\u002F\u002F no cast — the compiler already knows it's a String\n",[112,19816,19817],{"class":114,"line":132},[112,19818,19819],{},"String s = list.get(0);\n",[69,19821,19823],{"id":19822},"writing-a-generic-class","Writing a Generic Class",[15,19825,19826,19827,19830,19831,260,19833,19835],{},"A generic class introduces one or more ",[25,19828,19829],{},"type parameters"," in angle brackets after the class name. Here's a value wrapper — a natural fit for logging one tunable robot value (a setpoint, a gain, a mode name) without having to commit to ",[95,19832,631],{},[95,19834,361],{}," up front, using a placeholder type instead:",[104,19837,19839],{"className":106,"code":19838,"language":108,"meta":48,"style":48},"public class LoggedValue\u003CT>\n{\n    private T value;\n\n    public void set(T v) { value = v; }\n    public T get() { return value; }\n}\n",[95,19840,19841,19846,19850,19855,19859,19864,19869],{"__ignoreMap":48},[112,19842,19843],{"class":114,"line":115},[112,19844,19845],{},"public class LoggedValue\u003CT>\n",[112,19847,19848],{"class":114,"line":49},[112,19849,123],{},[112,19851,19852],{"class":114,"line":126},[112,19853,19854],{},"    private T value;\n",[112,19856,19857],{"class":114,"line":132},[112,19858,907],{"emptyLinePlaceholder":55},[112,19860,19861],{"class":114,"line":138},[112,19862,19863],{},"    public void set(T v) { value = v; }\n",[112,19865,19866],{"class":114,"line":144},[112,19867,19868],{},"    public T get() { return value; }\n",[112,19870,19871],{"class":114,"line":150},[112,19872,153],{},[15,19874,19875,19878,19879,19882],{},[95,19876,19877],{},"T"," isn't a real type — it's a ",[25,19880,19881],{},"type variable",", a placeholder standing in for whatever concrete type gets supplied when the class is actually used:",[104,19884,19886],{"className":106,"code":19885,"language":108,"meta":48,"style":48},"\u002F\u002F the \"diamond\" \u003C> — compiler infers Double from the left side\nLoggedValue\u003CDouble> setpoint = new LoggedValue\u003C>();\nsetpoint.set(3.5);    \u002F\u002F OK\n\u002F\u002F compile error — a String doesn't belong in a LoggedValue\u003CDouble>\nsetpoint.set(\"fast\");\n",[95,19887,19888,19893,19898,19903,19908],{"__ignoreMap":48},[112,19889,19890],{"class":114,"line":115},[112,19891,19892],{},"\u002F\u002F the \"diamond\" \u003C> — compiler infers Double from the left side\n",[112,19894,19895],{"class":114,"line":49},[112,19896,19897],{},"LoggedValue\u003CDouble> setpoint = new LoggedValue\u003C>();\n",[112,19899,19900],{"class":114,"line":126},[112,19901,19902],{},"setpoint.set(3.5);    \u002F\u002F OK\n",[112,19904,19905],{"class":114,"line":132},[112,19906,19907],{},"\u002F\u002F compile error — a String doesn't belong in a LoggedValue\u003CDouble>\n",[112,19909,19910],{"class":114,"line":138},[112,19911,19912],{},"setpoint.set(\"fast\");\n",[15,19914,19915,19916,19918,19919,19922,19923,176,19926,19929,19930,19932,19933,19936],{},"By convention, type parameters are single uppercase letters — ",[95,19917,19877],{}," (Type), ",[95,19920,19921],{},"E"," (Element, used throughout the collections you already know), ",[95,19924,19925],{},"K",[95,19927,19928],{},"V"," (Key\u002FValue, as in ",[95,19931,19379],{},"), ",[95,19934,19935],{},"N"," (Number). This convention exists specifically so a type variable is instantly recognizable and never confused with a real class name.",[15,19938,19939,19940,19942],{},"A generic class can take more than one type parameter, exactly like ",[95,19941,19379],{}," does:",[104,19944,19946],{"className":106,"code":19945,"language":108,"meta":48,"style":48},"public class Pair\u003CK, V>\n{\n    private K key;\n    private V value;\n\n    public Pair(K key, V value)\n    {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey()   { return key; }\n    public V getValue() { return value; }\n}\n\nPair\u003CString, Double> reading = new Pair\u003C>(\"Front-Left Current\", 12.4);\n",[95,19947,19948,19953,19957,19962,19967,19971,19976,19980,19985,19990,19994,19998,20003,20008,20012,20016],{"__ignoreMap":48},[112,19949,19950],{"class":114,"line":115},[112,19951,19952],{},"public class Pair\u003CK, V>\n",[112,19954,19955],{"class":114,"line":49},[112,19956,123],{},[112,19958,19959],{"class":114,"line":126},[112,19960,19961],{},"    private K key;\n",[112,19963,19964],{"class":114,"line":132},[112,19965,19966],{},"    private V value;\n",[112,19968,19969],{"class":114,"line":138},[112,19970,907],{"emptyLinePlaceholder":55},[112,19972,19973],{"class":114,"line":144},[112,19974,19975],{},"    public Pair(K key, V value)\n",[112,19977,19978],{"class":114,"line":150},[112,19979,135],{},[112,19981,19982],{"class":114,"line":2276},[112,19983,19984],{},"        this.key = key;\n",[112,19986,19987],{"class":114,"line":2282},[112,19988,19989],{},"        this.value = value;\n",[112,19991,19992],{"class":114,"line":2288},[112,19993,147],{},[112,19995,19996],{"class":114,"line":5760},[112,19997,907],{"emptyLinePlaceholder":55},[112,19999,20000],{"class":114,"line":5766},[112,20001,20002],{},"    public K getKey()   { return key; }\n",[112,20004,20005],{"class":114,"line":5772},[112,20006,20007],{},"    public V getValue() { return value; }\n",[112,20009,20010],{"class":114,"line":5777},[112,20011,153],{},[112,20013,20014],{"class":114,"line":5783},[112,20015,907],{"emptyLinePlaceholder":55},[112,20017,20018],{"class":114,"line":5789},[112,20019,20020],{},"Pair\u003CString, Double> reading = new Pair\u003C>(\"Front-Left Current\", 12.4);\n",[69,20022,20024],{"id":20023},"generic-methods","Generic Methods",[15,20026,20027],{},"A single method — even inside an otherwise non-generic class — can introduce its own type parameter, written in angle brackets right before the return type. Its scope is limited to that one method:",[104,20029,20031],{"className":106,"code":20030,"language":108,"meta":48,"style":48},"public class Util\n{\n    public static \u003CK, V> boolean sameEntry(Pair\u003CK, V> p1, Pair\u003CK, V> p2)\n    {\n        return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue());\n    }\n}\n",[95,20032,20033,20038,20042,20047,20051,20056,20060],{"__ignoreMap":48},[112,20034,20035],{"class":114,"line":115},[112,20036,20037],{},"public class Util\n",[112,20039,20040],{"class":114,"line":49},[112,20041,123],{},[112,20043,20044],{"class":114,"line":126},[112,20045,20046],{},"    public static \u003CK, V> boolean sameEntry(Pair\u003CK, V> p1, Pair\u003CK, V> p2)\n",[112,20048,20049],{"class":114,"line":132},[112,20050,135],{},[112,20052,20053],{"class":114,"line":138},[112,20054,20055],{},"        return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue());\n",[112,20057,20058],{"class":114,"line":144},[112,20059,147],{},[112,20061,20062],{"class":114,"line":150},[112,20063,153],{},[15,20065,20066,20067,20070,20071,20074],{},"Almost always, the compiler figures out the type on its own from how you call it — this is ",[25,20068,20069],{},"type inference"," — so you can call ",[95,20072,20073],{},"Util.sameEntry(p1, p2)"," directly, without ever writing the type parameter yourself.",[69,20076,20078],{"id":20077},"bounded-type-parameters","Bounded Type Parameters",[15,20080,20081,20082,20085,20086,20088,20089,322,20091,20093,20094,20096,20097,20099],{},"A quick primer before this section's example: ",[95,20083,20084],{},"Number"," is a Java class — like ",[95,20087,19753],{},", the ultimate parent of every class in Java (Ch.17 covers what that relationship means for classes you write yourself) — that ",[95,20090,1869],{},[95,20092,8536],{},", and the other numeric wrapper classes all ",[95,20095,16804],{},". That's what makes \"any subtype of ",[95,20098,20084],{},"\" a meaningful thing to say, and it's the same \"is a more specific kind of\" relationship Ch.17 covers in full.",[15,20101,20102,20103,20106,20107,20109,20110,20112,20113,322,20115,20117],{},"Sometimes a generic type shouldn't accept ",[494,20104,20105],{},"just anything"," — a method built around numeric comparisons only makes sense for actual numbers. ",[95,20108,16804],{}," restricts a type parameter to a specific type (or subtype of it) — here meaning \"any subtype of ",[95,20111,20084],{},",\" which covers ",[95,20114,1869],{},[95,20116,8536],{},", and the rest:",[104,20119,20121],{"className":106,"code":20120,"language":108,"meta":48,"style":48},"public static \u003CT extends Number> double clampedValue(T value, double min, double max)\n{\n    double v = value.doubleValue(); \u002F\u002F legal — Number guarantees a doubleValue() method\n    if (v \u003C min) return min;\n    if (v > max) return max;\n    return v;\n}\n",[95,20122,20123,20128,20132,20137,20142,20147,20152],{"__ignoreMap":48},[112,20124,20125],{"class":114,"line":115},[112,20126,20127],{},"public static \u003CT extends Number> double clampedValue(T value, double min, double max)\n",[112,20129,20130],{"class":114,"line":49},[112,20131,123],{},[112,20133,20134],{"class":114,"line":126},[112,20135,20136],{},"    double v = value.doubleValue(); \u002F\u002F legal — Number guarantees a doubleValue() method\n",[112,20138,20139],{"class":114,"line":132},[112,20140,20141],{},"    if (v \u003C min) return min;\n",[112,20143,20144],{"class":114,"line":138},[112,20145,20146],{},"    if (v > max) return max;\n",[112,20148,20149],{"class":114,"line":144},[112,20150,20151],{},"    return v;\n",[112,20153,20154],{"class":114,"line":150},[112,20155,153],{},[15,20157,20158,20159,20162,20163,20166,20167,1291,20169,20172,20173,20176,20177,20179],{},"Without the ",[95,20160,20161],{},"extends Number"," bound, ",[95,20164,20165],{},"value.doubleValue()"," wouldn't compile at all — the compiler would only know ",[95,20168,4024],{},[494,20170,20171],{},"some"," type, with no guarantee it has a ",[95,20174,20175],{},"doubleValue()"," method to call. The bound is what unlocks calling methods that only ",[95,20178,20084],{}," (and its subtypes) actually have.",[69,20181,20183],{"id":20182},"wildcards-a-quick-preview","Wildcards: A Quick Preview",[15,20185,2424,20186,20189,20190,20192,20193,20195,20196,20199,20200,20203],{},[95,20187,20188],{},"?"," wildcard represents an unknown type, mostly useful for parameters and fields where you want to accept \"a ",[95,20191,18650],{}," of anything\" without pinning down exactly what. Wildcard variations (upper-bounded, lower-bounded) go beyond what this chapter covers — the short version to remember for now is: ",[95,20194,20188],{}," is never used when ",[494,20197,20198],{},"creating"," a generic type (",[95,20201,20202],{},"new Box\u003C?>()"," isn't a thing) — only when referring to one you don't need to be specific about.",[69,20205,20207],{"id":20206},"what-generics-cant-do","What Generics Can't Do",[15,20209,20210,20211,20214],{},"Generics only exist at compile time — the compiler checks everything, then largely erases the type information before the program runs (this is called ",[25,20212,20213],{},"type erasure","). That limits what a generic class can do with its own type parameter:",[19,20216,20217,20224,20230],{},[22,20218,20219,20220,20223],{},"No ",[95,20221,20222],{},"new T()"," — the compiler doesn't know at runtime which constructor to call.",[22,20225,20219,20226,20229],{},[95,20227,20228],{},"new T[10]"," — creating an array of the type parameter doesn't compile, for the same reason.",[22,20231,20219,20232,20234,20235,20237],{},[95,20233,179],{}," field or method of type ",[95,20236,19877],{}," — a type parameter belongs to each individual object, not to the class itself.",[15,20239,20240,20241,20244,20245,20248],{},"Skipping the type argument entirely (",[95,20242,20243],{},"List list = new ArrayList();",", this lesson's very first snippet) is called a ",[25,20246,20247],{},"raw type"," — it compiles, but with an \"unchecked\" warning, not a hard error. Java kept raw types working only so pre-generics code (written before Java 5) wouldn't break; never write one on purpose in new code.",[69,20250,462],{"id":461},[19,20252,20253,20273,20289,20311],{},[22,20254,20255,476,20262,20265,20266,20268,20269,20272],{},[25,20256,20257,20258,20261],{},"Forgetting the ",[95,20259,20260],{},"\u003CT>"," on the class declaration itself.",[95,20263,20264],{},"public class Box { private T t; }"," doesn't compile — ",[95,20267,19877],{}," has to be introduced with ",[95,20270,20271],{},"public class Box\u003CT>"," before it can be used anywhere inside the class.",[22,20274,20275,476,20278,20281,20282,20285,20286,20288],{},[25,20276,20277],{},"Using a primitive as a type argument.",[95,20279,20280],{},"LoggedValue\u003Cdouble>"," doesn't compile — type arguments must be reference types, so use the wrapper (",[95,20283,20284],{},"LoggedValue\u003CDouble>",") instead, same rule as ",[95,20287,12343],{}," (Lesson 9.2).",[22,20290,20291,476,20294,20296,20297,20299,20300,20302,20303,1291,20305,20307,20308,20310],{},[25,20292,20293],{},"Calling a bound-specific method without the bound.",[95,20295,20165],{}," only compiles once ",[95,20298,19877],{}," is declared ",[95,20301,20161],{}," — without the bound, the compiler only knows ",[95,20304,19877],{},[494,20306,20171],{}," type, with no guaranteed methods beyond what every ",[95,20309,19753],{}," has.",[22,20312,20313,20326],{},[25,20314,20315,20316,322,20318,20321,20322,20325],{},"Expecting ",[95,20317,20222],{},[95,20319,20320],{},"new T[]",", or a ",[95,20323,20324],{},"static T"," to work."," Type erasure means none of them compile — see \"What Generics Can't Do\" above.",[69,20328,501],{"id":500},[19,20330,20331,20338,20344,20347,20357,20368],{},[22,20332,20333,20334,20337],{},"A generic class introduces type parameters in angle brackets after its name (",[95,20335,20336],{},"class LoggedValue\u003CT>","); the type variable then stands in for a real type anywhere in the class.",[22,20339,20340,20341,20343],{},"Generic types replace the old cast-from-",[95,20342,19753],{}," pattern with compile-time type safety — a wrong type is now a compile error, not a runtime surprise.",[22,20345,20346],{},"A generic method can introduce its own type parameter, scoped to just that method; the compiler usually infers the type automatically.",[22,20348,20349,20352,20353,20356],{},[95,20350,20351],{},"\u003CT extends SomeType>"," restricts what a type parameter can be, and unlocks calling ",[95,20354,20355],{},"SomeType","'s own methods on values of that type.",[22,20358,20359,20360,322,20362,20364,20365,20367],{},"Type erasure means a generic class can't ",[95,20361,20222],{},[95,20363,20320],{},", or use ",[95,20366,19877],{}," statically; skipping the type argument entirely compiles as a raw type, with an unchecked warning.",[22,20369,2424,20370,20372],{},[95,20371,20188],{}," wildcard represents an unknown type for referring to a generic type generically — it's never used when constructing one.",[15,20374,544,20375,548,20377,322,20380,322,20383,322,20386,322,20389,20392,20393,20395],{},[95,20376,17008],{},[95,20378,20379],{},"oracle-java-tutorials\u002Fgenerics\u002F01-why-use-generics.md",[95,20381,20382],{},"02-generic-types.md",[95,20384,20385],{},"03-generic-methods.md",[95,20387,20388],{},"04-bounded-type-parameters.md",[95,20390,20391],{},"05-wildcards.md"," (ORACLE 14.1-5)\n",[25,20394,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 2 (\"Writing Your Own Generics\")",[554,20397,556],{},{"title":48,"searchDepth":49,"depth":49,"links":20399},[20400,20401,20402,20403,20404,20405,20406,20407],{"id":19746,"depth":49,"text":19747},{"id":19822,"depth":49,"text":19823},{"id":20023,"depth":49,"text":20024},{"id":20077,"depth":49,"text":20078},{"id":20182,"depth":49,"text":20183},{"id":20206,"depth":49,"text":20207},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},"List\u003CString>, Map\u003CInteger, Double>, ArrayList\u003CDouble> — every collection since Ch.9 has used a generic type someone else wrote. This chapter is about writing your own.",{"outlineRef":20410,"status":570},"16 — Writing Your Own Generics (ORACLE 14.1-5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch16-writing-your-own-generics\u002F16-writing-your-own-generics",{"title":19723,"description":20408},"shockwave-curriculum\u002Flessons\u002Fch16-writing-your-own-generics\u002F16-writing-your-own-generics","CC9y_sDKKbHDlNMUNn4jxParJWIItoEX5NhCRF0udqE",{"id":20416,"title":20417,"body":20418,"description":48,"extension":51,"meta":20812,"navigation":55,"path":20814,"seo":20815,"stem":20816,"__hash__":20817},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.1-inheritance-superclass-subclass.md","Inheritance, Superclass, Subclass",{"type":8,"value":20419,"toc":20804},[20420,20423,20427,20448,20530,20535,20561,20565,20614,20618,20641,20669,20682,20684,20687,20726,20728,20765,20767,20791,20802],[11,20421,20417],{"id":20422},"inheritance-superclass-subclass",[69,20424,20426],{"id":20425},"what-inheritance-does","What Inheritance Does",[15,20428,20429,20432,20433,20436,20437,20439,20440,20443,20444,20447],{},[25,20430,20431],{},"Inheritance"," lets one class inherit fields and methods from another. The class being inherited from is the ",[25,20434,20435],{},"superclass"," (or parent class); the class doing the inheriting is the ",[25,20438,17666],{}," (or child class). The parts of an FRC robot — an intake, a shooter, a climber — share real structure: each has a name for logging, a way to print a labeled message, and a ",[95,20441,20442],{},"stop()"," method. That makes them a natural fit for a shared superclass. Chapters 17 and 18 use one such superclass, ",[95,20445,20446],{},"RobotPart",", throughout:",[104,20449,20451],{"className":106,"code":20450,"language":108,"meta":48,"style":48},"public class RobotPart\n{\n    private String name;\n\n    public RobotPart(String name) { this.name = name; }\n    public String getName() { return name; }\n    public void log(String msg) { System.out.println(\"[\" + name + \"] \" + msg); }\n    public void stop() { log(\"stopped\"); }\n}\n\npublic class Intake extends RobotPart\n{\n    \u002F\u002F passes the name up to RobotPart's constructor (Lesson 17.2)\n    public Intake(String name) { super(name); }\n\n    \u002F\u002F inherits getName(), log(), and stop() for free\n}\n",[95,20452,20453,20458,20462,20466,20470,20475,20480,20485,20490,20494,20498,20503,20507,20512,20517,20521,20526],{"__ignoreMap":48},[112,20454,20455],{"class":114,"line":115},[112,20456,20457],{},"public class RobotPart\n",[112,20459,20460],{"class":114,"line":49},[112,20461,123],{},[112,20463,20464],{"class":114,"line":126},[112,20465,10679],{},[112,20467,20468],{"class":114,"line":132},[112,20469,907],{"emptyLinePlaceholder":55},[112,20471,20472],{"class":114,"line":138},[112,20473,20474],{},"    public RobotPart(String name) { this.name = name; }\n",[112,20476,20477],{"class":114,"line":144},[112,20478,20479],{},"    public String getName() { return name; }\n",[112,20481,20482],{"class":114,"line":150},[112,20483,20484],{},"    public void log(String msg) { System.out.println(\"[\" + name + \"] \" + msg); }\n",[112,20486,20487],{"class":114,"line":2276},[112,20488,20489],{},"    public void stop() { log(\"stopped\"); }\n",[112,20491,20492],{"class":114,"line":2282},[112,20493,153],{},[112,20495,20496],{"class":114,"line":2288},[112,20497,907],{"emptyLinePlaceholder":55},[112,20499,20500],{"class":114,"line":5760},[112,20501,20502],{},"public class Intake extends RobotPart\n",[112,20504,20505],{"class":114,"line":5766},[112,20506,123],{},[112,20508,20509],{"class":114,"line":5772},[112,20510,20511],{},"    \u002F\u002F passes the name up to RobotPart's constructor (Lesson 17.2)\n",[112,20513,20514],{"class":114,"line":5777},[112,20515,20516],{},"    public Intake(String name) { super(name); }\n",[112,20518,20519],{"class":114,"line":5783},[112,20520,907],{"emptyLinePlaceholder":55},[112,20522,20523],{"class":114,"line":5789},[112,20524,20525],{},"    \u002F\u002F inherits getName(), log(), and stop() for free\n",[112,20527,20528],{"class":114,"line":5794},[112,20529,153],{},[15,20531,20532,20534],{},[95,20533,20446],{}," is the team's own class, written for this course — it isn't part of WPILib. This is its one full definition: later lessons show only what they add to it.",[15,20536,20537,20539,20540,20542,20543,16416,20545,20548,20549,476,20551,20554,20555,20557,20558,20560],{},[95,20538,16804],{}," is the keyword that sets up inheritance. ",[95,20541,9838],{},"'s one line of its own, the constructor, hands the name up to ",[95,20544,20446],{},[95,20546,20547],{},"super(name)"," — Lesson 17.2 explains exactly how that works. A Java class can only ",[95,20550,16804],{},[25,20552,20553],{},"one"," superclass — unlike a person with two biological parents, there's no multiple inheritance of this kind in Java. Omitting ",[95,20556,16804],{}," entirely doesn't mean \"no parent\" — it means the class implicitly inherits from Java's built-in ",[95,20559,19753],{}," class (Lesson 17.4).",[69,20562,20564],{"id":20563},"the-is-a-relationship","The is-a Relationship",[15,20566,20567,20568,20571,20572,476,20574,476,20577,5847,20579,476,20581,476,20583,20585,20586,20589,20590,20592,20593,20596,20597,20599,20600,20603,20604,20607,20608,476,20611,20613],{},"Inheritance should only model a genuine ",[25,20569,20570],{},"is-a"," relationship: an ",[95,20573,9838],{},[494,20575,20576],{},"is a",[95,20578,20446],{},[95,20580,11675],{},[494,20582,20576],{},[95,20584,20446],{},". The test to apply: could you substitute the subclass anywhere the superclass is expected, and have it still make sense? A ",[95,20587,20588],{},"Vision"," processor being asked to ",[95,20591,20442],{}," and get ",[95,20594,20595],{},"log()","ed makes sense as a ",[95,20598,20446],{}," — but a ",[95,20601,20602],{},"Robot"," class itself, or a ",[95,20605,20606],{},"Controller"," wrapping a joystick, isn't a ",[494,20609,20610],{},"kind of",[95,20612,20446],{},", even if it happens to interact with one.",[69,20615,20617],{"id":20616},"is-a-vs-has-a","is-a vs. has-a",[15,20619,2424,20620,20622,20623,20626,20627,476,20629,476,20632,20634,20635,515,20637,20640],{},[25,20621,10619],{}," relationship (also called ",[25,20624,20625],{},"association",") is different: it's when one class simply holds a reference to another, without being a specialized kind of it. A ",[95,20628,20602],{},[494,20630,20631],{},"has a",[95,20633,365],{},", an ",[95,20636,9838],{},[95,20638,20639],{},"Shooter"," — it isn't a subclass of any of them:",[104,20642,20644],{"className":106,"code":20643,"language":108,"meta":48,"style":48},"public class Robot\n{\n    private Drivetrain drivetrain;  \u002F\u002F has-a: Robot holds a Drivetrain, isn't one\n    private Intake intake;          \u002F\u002F has-a\n}\n",[95,20645,20646,20651,20655,20660,20665],{"__ignoreMap":48},[112,20647,20648],{"class":114,"line":115},[112,20649,20650],{},"public class Robot\n",[112,20652,20653],{"class":114,"line":49},[112,20654,123],{},[112,20656,20657],{"class":114,"line":126},[112,20658,20659],{},"    private Drivetrain drivetrain;  \u002F\u002F has-a: Robot holds a Drivetrain, isn't one\n",[112,20661,20662],{"class":114,"line":132},[112,20663,20664],{},"    private Intake intake;          \u002F\u002F has-a\n",[112,20666,20667],{"class":114,"line":138},[112,20668,153],{},[15,20670,20671,20672,20675,20676,20678,20679,20681],{},"Compare that to ",[95,20673,20674],{},"Intake extends RobotPart"," — that's is-a: an ",[95,20677,9838],{}," really is a specialized kind of ",[95,20680,20446],{},", not just something that happens to reference one.",[69,20683,18508],{"id":18507},[15,20685,20686],{},"Two forces motivate reaching for a superclass:",[19,20688,20689,20711],{},[22,20690,20691,20694,20695,322,20697,325,20699,20701,20702,20704,20705,20707,20708,20710],{},[25,20692,20693],{},"Generalization"," — several classes already share data\u002Fbehavior, so pull the shared parts up into one common parent. ",[95,20696,9838],{},[95,20698,20639],{},[95,20700,11675],{}," all need a name, a ",[95,20703,20595],{}," method, and a ",[95,20706,20442],{}," method — that's exactly what ",[95,20709,20446],{}," is for.",[22,20712,20713,20716,20717,20719,20720,20722,20723,20725],{},[25,20714,20715],{},"Specialization"," — a class wants most of a parent's behavior, but needs to add something of its own or do one thing differently. ",[95,20718,9838],{}," inherits ",[95,20721,20595],{}," unchanged, but will eventually want its own ",[95,20724,20442],{}," that's specific to its own rollers — replacing an inherited method like that is called overriding (Lesson 18.1).",[69,20727,462],{"id":461},[19,20729,20730,20738,20750],{},[22,20731,20732,20735,20736,79],{},[25,20733,20734],{},"Using inheritance purely to reuse code, without a real is-a relationship."," If the substitution test fails — the subclass wouldn't actually make sense wherever the superclass is expected — model it as has-a (a field) instead of ",[95,20737,16804],{},[22,20739,20740,20743,20744,20746,20747,20749],{},[25,20741,20742],{},"Forgetting a class always has exactly one superclass."," Omitting ",[95,20745,16804],{}," doesn't mean \"no parent\" — it means the implicit parent is ",[95,20748,19753],{}," (Lesson 17.4).",[22,20751,20752,476,20755,20758,20759,20761,20762,20764],{},[25,20753,20754],{},"Assuming a class can extend more than one class.",[95,20756,20757],{},"class Intake extends RobotPart, Loggable"," doesn't compile — Java allows only one ",[95,20760,16804],{},", though a class can ",[95,20763,16808],{}," multiple interfaces (Ch.19).",[69,20766,501],{"id":500},[19,20768,20769,20774,20785,20788],{},[22,20770,20771,20773],{},[95,20772,16804],{}," declares inheritance: the subclass gains the superclass's fields and methods.",[22,20775,20776,20777,20779,20780,20782,20783,79],{},"A class can only ",[95,20778,16804],{}," one superclass; omitting ",[95,20781,16804],{}," implicitly means extending ",[95,20784,19753],{},[22,20786,20787],{},"Use inheritance only for a genuine is-a relationship — verify with the substitution test (does the subclass make sense wherever the superclass is expected?).",[22,20789,20790],{},"has-a (association: one class simply holding a reference to another) is the right model when is-a doesn't genuinely apply.",[15,20792,544,20793,548,20795,20798,20799,20801],{},[95,20794,547],{},[95,20796,20797],{},"unit-5-inheritance-optional\u002F5.01-inheritance-superclass-subclass.md"," (CSA 5.1)\n",[25,20800,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 4 (\"Inheritance & Abstractions\")",[554,20803,556],{},{"title":48,"searchDepth":49,"depth":49,"links":20805},[20806,20807,20808,20809,20810,20811],{"id":20425,"depth":49,"text":20426},{"id":20563,"depth":49,"text":20564},{"id":20616,"depth":49,"text":20617},{"id":18507,"depth":49,"text":18508},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":20813,"status":570},"17.1 — Inheritance, Superclass, Subclass (CSA 5.1)","\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F1-inheritance-superclass-subclass",{"title":20417,"description":48},"shockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.1-inheritance-superclass-subclass","ABF96I-98kuwHjoec599nF7Bt1Us45KzrcESmh0PA_Q",{"id":20819,"title":20820,"body":20821,"description":48,"extension":51,"meta":21326,"navigation":55,"path":21328,"seo":21329,"stem":21330,"__hash__":21331},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.2-inheritance-and-constructors.md","Inheritance and Constructors",{"type":8,"value":20822,"toc":21312},[20823,20826,20830,20853,20860,20873,20959,20973,20980,21006,21013,21021,21054,21077,21081,21094,21109,21113,21139,21143,21157,21193,21206,21208,21258,21260,21302,21310],[11,20824,20820],{"id":20825},"inheritance-and-constructors",[69,20827,20829],{"id":20828},"constructors-are-never-inherited","Constructors Are Never Inherited",[15,20831,20832,20833,20835,20836,20838,20839,20841,20842,20844,20845,476,20847,20849,20850,20852],{},"A subclass inherits its superclass's ",[95,20834,175],{}," methods and fields, but it does ",[25,20837,3360],{}," inherit constructors, and it can't directly touch the superclass's ",[95,20840,9905],{}," fields. Yet every ",[95,20843,9838],{}," object still ",[494,20846,9402],{},[95,20848,20446],{},"'s private ",[95,20851,9621],{}," field, and that field needs to be properly set up before anything uses it — so how does a subclass initialize state that belongs to its superclass?",[69,20854,2424,20856,20859],{"id":20855},"the-super-call",[95,20857,20858],{},"super(...)"," Call",[15,20861,20862,20863,20866,20867,20869,20870,20872],{},"The keyword ",[95,20864,20865],{},"super",", used like a method call, runs the superclass's constructor code in the context of the object already being built. Here's the part of ",[95,20868,20446],{}," (Lesson 17.1) that matters for construction, and an ",[95,20871,9838],{}," that adds a field of its own:",[104,20874,20876],{"className":106,"code":20875,"language":108,"meta":48,"style":48},"public class RobotPart\n{\n    private String name;\n\n    public RobotPart(String name) { this.name = name; }\n    \u002F\u002F ...getName(), log(), and stop() as in Lesson 17.1\n}\n\npublic class Intake extends RobotPart\n{\n    private boolean hasGamePiece;\n\n    public Intake(String name)\n    {\n        \u002F\u002F runs RobotPart's constructor, setting the private name field\n        super(name);\n        hasGamePiece = false;  \u002F\u002F Intake's own field\n    }\n}\n",[95,20877,20878,20882,20886,20890,20894,20898,20903,20907,20911,20915,20919,20923,20927,20932,20936,20941,20946,20951,20955],{"__ignoreMap":48},[112,20879,20880],{"class":114,"line":115},[112,20881,20457],{},[112,20883,20884],{"class":114,"line":49},[112,20885,123],{},[112,20887,20888],{"class":114,"line":126},[112,20889,10679],{},[112,20891,20892],{"class":114,"line":132},[112,20893,907],{"emptyLinePlaceholder":55},[112,20895,20896],{"class":114,"line":138},[112,20897,20474],{},[112,20899,20900],{"class":114,"line":144},[112,20901,20902],{},"    \u002F\u002F ...getName(), log(), and stop() as in Lesson 17.1\n",[112,20904,20905],{"class":114,"line":150},[112,20906,153],{},[112,20908,20909],{"class":114,"line":2276},[112,20910,907],{"emptyLinePlaceholder":55},[112,20912,20913],{"class":114,"line":2282},[112,20914,20502],{},[112,20916,20917],{"class":114,"line":2288},[112,20918,123],{},[112,20920,20921],{"class":114,"line":5760},[112,20922,9894],{},[112,20924,20925],{"class":114,"line":5766},[112,20926,907],{"emptyLinePlaceholder":55},[112,20928,20929],{"class":114,"line":5772},[112,20930,20931],{},"    public Intake(String name)\n",[112,20933,20934],{"class":114,"line":5777},[112,20935,135],{},[112,20937,20938],{"class":114,"line":5783},[112,20939,20940],{},"        \u002F\u002F runs RobotPart's constructor, setting the private name field\n",[112,20942,20943],{"class":114,"line":5789},[112,20944,20945],{},"        super(name);\n",[112,20947,20948],{"class":114,"line":5794},[112,20949,20950],{},"        hasGamePiece = false;  \u002F\u002F Intake's own field\n",[112,20952,20953],{"class":114,"line":10057},[112,20954,147],{},[112,20956,20957],{"class":114,"line":10062},[112,20958,153],{},[15,20960,20961,20963,20964,20966,20967,20969,20970,20972],{},[95,20962,20547],{}," isn't creating a second object — it's the one and only way to run ",[95,20965,20446],{},"'s own initialization logic for the object currently under construction. Without it, ",[95,20968,9621],{}," would never get set, since ",[95,20971,9838],{}," has no direct access to that private field to assign it itself.",[69,20974,20976,20977,20859],{"id":20975},"the-implicit-super-call","The Implicit ",[95,20978,20979],{},"super()",[15,20981,20982,20983,20985,20986,20988,20989,20992,20993,20995,20996,20998,20999,21002,21003,21005],{},"If a constructor doesn't contain an explicit ",[95,20984,20858],{}," call, Java automatically inserts a no-argument ",[95,20987,20979],{}," call at its start. That only works if the superclass actually ",[494,20990,20991],{},"has"," a no-argument constructor — if it doesn't, any subclass constructor must explicitly call ",[95,20994,20858],{}," with arguments matching a constructor that does exist, or the code won't compile. ",[95,20997,20446],{}," has only ",[95,21000,21001],{},"RobotPart(String name)",", so every subclass constructor must call ",[95,21004,20858],{}," itself.",[69,21007,21009,21010,21012],{"id":21008},"where-super-goes","Where ",[95,21011,20858],{}," Goes",[15,21014,21015,21016,476,21018,21020],{},"On Java 25, a constructor may run a few statements ",[494,21017,1814],{},[95,21019,20858],{},", as long as they don't use the object being built — checking or preparing an argument, for example:",[104,21022,21024],{"className":106,"code":21023,"language":108,"meta":48,"style":48},"public Intake(String name)\n{\n    if (name.isBlank()) throw new IllegalArgumentException(\"Intake needs a name\");\n    super(name.trim());\n    hasGamePiece = false;\n}\n",[95,21025,21026,21031,21035,21040,21045,21050],{"__ignoreMap":48},[112,21027,21028],{"class":114,"line":115},[112,21029,21030],{},"public Intake(String name)\n",[112,21032,21033],{"class":114,"line":49},[112,21034,123],{},[112,21036,21037],{"class":114,"line":126},[112,21038,21039],{},"    if (name.isBlank()) throw new IllegalArgumentException(\"Intake needs a name\");\n",[112,21041,21042],{"class":114,"line":132},[112,21043,21044],{},"    super(name.trim());\n",[112,21046,21047],{"class":114,"line":138},[112,21048,21049],{},"    hasGamePiece = false;\n",[112,21051,21052],{"class":114,"line":144},[112,21053,153],{},[15,21055,21056,21057,21060,21061,21063,21064,21066,21067,21073,21074,21076],{},"What those early statements can't do is use the object itself: calling one of its methods (even an inherited one like ",[95,21058,21059],{},"getName()",") or reading its fields before ",[95,21062,20858],{}," is a compile error, because the ",[95,21065,20446],{}," part of the object doesn't exist yet. ",[25,21068,21069,21070,21072],{},"On Java 17, ",[95,21071,20858],{}," must be the very first statement"," of the constructor — nothing at all can come before it. Putting ",[95,21075,20858],{}," first works on every version.",[69,21078,21080],{"id":21079},"the-chain-bottoms-out-at-object","The Chain Bottoms Out at Object",[15,21082,21083,21084,21086,21087,21090,21091,21093],{},"Whether called explicitly or inserted implicitly, every chain of ",[95,21085,20865],{}," calls eventually reaches ",[95,21088,21089],{},"java.lang.Object","'s own no-argument constructor — the one class with no superclass of its own (Lesson 17.4). From there, construction \"unwinds\": ",[95,21092,19753],{},"'s constructor logic runs first, then each class going back down the hierarchy, ending with whichever class was actually instantiated. By the time the rest of your own constructor's body runs, every inherited field further up the chain has already been properly initialized.",[104,21095,21097],{"className":106,"code":21096,"language":108,"meta":48,"style":48},"Intake intake = new Intake(\"Front Intake\");\n\u002F\u002F Order of execution: Object() -> RobotPart(String) -> Intake(String)\n",[95,21098,21099,21104],{"__ignoreMap":48},[112,21100,21101],{"class":114,"line":115},[112,21102,21103],{},"Intake intake = new Intake(\"Front Intake\");\n",[112,21105,21106],{"class":114,"line":49},[112,21107,21108],{},"\u002F\u002F Order of execution: Object() -> RobotPart(String) -> Intake(String)\n",[69,21110,21112],{"id":21111},"a-middle-ground-protected","A Middle Ground: protected",[15,21114,21115,21117,21118,21120,21121,21123,21124,322,21127,21129,21130,21132,21133,21135,21136,21138],{},[95,21116,9905],{}," fields are hidden even from subclasses. Java has one access level in between: a field or method marked ",[95,21119,16738],{}," can be used directly by subclasses (and by other classes in the same package). If ",[95,21122,20446],{}," had declared ",[95,21125,21126],{},"protected String name;",[95,21128,9838],{}," could read and assign ",[95,21131,9621],{}," itself. This course keeps fields ",[95,21134,9905],{}," and goes through ",[95,21137,20858],{}," and getters instead, so the superclass stays in control of its own data. Lesson 23.1 compares all four access levels side by side.",[69,21140,21142],{"id":21141},"writing-your-own-exception","Writing Your Own Exception",[15,21144,21145,21146,21148,21149,21152,21153,21156],{},"Now that you can write a subclass, you can create your own exception type (Ch.12): extend ",[95,21147,17237],{}," and pass the message up with ",[95,21150,21151],{},"super(message)",", so the inherited ",[95,21154,21155],{},"getMessage()"," returns it:",[104,21158,21160],{"className":106,"code":21159,"language":108,"meta":48,"style":48},"public class ArmLimitException extends RuntimeException\n{\n    public ArmLimitException(String message)\n    {\n        super(message);  \u002F\u002F RuntimeException stores it for getMessage()\n    }\n}\n",[95,21161,21162,21167,21171,21176,21180,21185,21189],{"__ignoreMap":48},[112,21163,21164],{"class":114,"line":115},[112,21165,21166],{},"public class ArmLimitException extends RuntimeException\n",[112,21168,21169],{"class":114,"line":49},[112,21170,123],{},[112,21172,21173],{"class":114,"line":126},[112,21174,21175],{},"    public ArmLimitException(String message)\n",[112,21177,21178],{"class":114,"line":132},[112,21179,135],{},[112,21181,21182],{"class":114,"line":138},[112,21183,21184],{},"        super(message);  \u002F\u002F RuntimeException stores it for getMessage()\n",[112,21186,21187],{"class":114,"line":144},[112,21188,147],{},[112,21190,21191],{"class":114,"line":150},[112,21192,153],{},[15,21194,21195,21198,21199,21202,21203,21205],{},[95,21196,21197],{},"throw new ArmLimitException(\"Arm past soft limit\");"," then works like any built-in exception, and a ",[95,21200,21201],{},"catch (ArmLimitException e)"," block can handle exactly this problem and nothing else. Because it extends ",[95,21204,17237],{},", it's unchecked.",[69,21207,462],{"id":461},[19,21209,21210,21231,21246],{},[22,21211,21212,476,21215,17790,21218,21220,21221,1291,21223,4090,21225,21227,21228,21230],{},[25,21213,21214],{},"Trying to assign a superclass's private field directly.",[95,21216,21217],{},"this.name = name;",[95,21219,9838],{},"'s constructor doesn't compile if ",[95,21222,9621],{},[95,21224,9905],{},[95,21226,20446],{}," — only ",[95,21229,20547],{}," can reach it.",[22,21232,21233,21239,21240,21242,21243,21245],{},[25,21234,21235,21236,21238],{},"Using the object before ",[95,21237,20858],{}," has run."," On Java 25, statements that don't touch the object (like checking an argument) may come before ",[95,21241,20858],{},", but calling the object's methods or reading its fields there doesn't compile. On Java 17, ",[95,21244,20858],{}," must be the very first statement, with nothing before it.",[22,21247,21248,21254,21255,21257],{},[25,21249,21250,21251,21253],{},"Assuming a no-argument ",[95,21252,20979],{}," always works."," If the superclass has no no-argument constructor (only ones taking parameters), Java can't insert an implicit call — the subclass must explicitly call ",[95,21256,20858],{}," with matching arguments.",[69,21259,501],{"id":500},[19,21261,21262,21268,21277,21286,21292],{},[22,21263,21264,21265,21267],{},"Constructors are never inherited — only a ",[95,21266,20858],{}," call can run the superclass's constructor logic to initialize its own (even private) fields.",[22,21269,21270,21271,21273,21274,21276],{},"If a subclass constructor doesn't call ",[95,21272,20858],{}," explicitly, Java inserts a no-argument ",[95,21275,20979],{}," call automatically — which only works if the superclass has one.",[22,21278,21279,21280,21282,21283,21285],{},"On Java 25, only statements that don't use the object may come before ",[95,21281,20858],{},"; on Java 17, ",[95,21284,20858],{}," must be first.",[22,21287,21288,21289,21291],{},"Every construction chain eventually reaches ",[95,21290,19753],{},"'s constructor, which runs first; the subclass's own code only runs after every class above it has finished initializing.",[22,21293,21294,21296,21297,21299,21300,79],{},[95,21295,16738],{}," lets subclasses use a member directly; a custom exception is just a subclass of ",[95,21298,17237],{}," that calls ",[95,21301,21151],{},[15,21303,544,21304,548,21306,21309],{},[95,21305,547],{},[95,21307,21308],{},"unit-5-inheritance-optional\u002F5.02-inheritance-and-constructors.md"," (CSA 5.2)",[554,21311,556],{},{"title":48,"searchDepth":49,"depth":49,"links":21313},[21314,21315,21317,21319,21321,21322,21323,21324,21325],{"id":20828,"depth":49,"text":20829},{"id":20855,"depth":49,"text":21316},"The super(...) Call",{"id":20975,"depth":49,"text":21318},"The Implicit super() Call",{"id":21008,"depth":49,"text":21320},"Where super(...) Goes",{"id":21079,"depth":49,"text":21080},{"id":21111,"depth":49,"text":21112},{"id":21141,"depth":49,"text":21142},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":21327,"status":15483},"17.2 — Inheritance and Constructors (CSA 5.2)","\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F2-inheritance-and-constructors",{"title":20820,"description":48},"shockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.2-inheritance-and-constructors","eXpPON_zOeaBCB3uO_4vcf_u-srhtNM1XU03Cbq2zTo",{"id":21333,"title":21334,"body":21335,"description":48,"extension":51,"meta":21631,"navigation":55,"path":21633,"seo":21634,"stem":21635,"__hash__":21636},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.3-inheritance-hierarchies.md","Inheritance Hierarchies",{"type":8,"value":21336,"toc":21623},[21337,21340,21344,21372,21376,21382,21402,21410,21425,21429,21432,21487,21501,21521,21525,21544,21546,21594,21596,21613,21621],[11,21338,21334],{"id":21339},"inheritance-hierarchies",[69,21341,21343],{"id":21342},"multiple-subclasses-one-superclass","Multiple Subclasses, One Superclass",[15,21345,1851,21346,21349,21350,322,21352,325,21354,21356,21357,21359,21360,290,21362,21364,21365,21367,21368,21371],{},[25,21347,21348],{},"inheritance hierarchy"," forms when several subclasses inherit (directly, or through another subclass) from a common superclass. ",[95,21351,9838],{},[95,21353,20639],{},[95,21355,11675],{}," all extending ",[95,21358,20446],{}," (each with a constructor that passes its name to ",[95,21361,20858],{},[95,21363,9838],{},"'s) is a small hierarchy; ",[95,21366,19753],{}," sits at the very top of ",[494,21369,21370],{},"every"," hierarchy in Java, since every class ultimately inherits from it (Lesson 17.4).",[69,21373,21375],{"id":21374},"a-superclass-reference-can-hold-any-subclass-object","A Superclass Reference Can Hold Any Subclass Object",[15,21377,21378,21379,738],{},"A variable typed as the superclass can refer to an object of that class ",[494,21380,21381],{},"or any of its subclasses",[104,21383,21385],{"className":106,"code":21384,"language":108,"meta":48,"style":48},"RobotPart p1 = new RobotPart(\"Generic\");\nRobotPart p2 = new Intake(\"Front Intake\");   \u002F\u002F legal — an Intake IS-A RobotPart\nRobotPart p3 = new Climber(\"Left Climber\");  \u002F\u002F legal — a Climber IS-A RobotPart\n",[95,21386,21387,21392,21397],{"__ignoreMap":48},[112,21388,21389],{"class":114,"line":115},[112,21390,21391],{},"RobotPart p1 = new RobotPart(\"Generic\");\n",[112,21393,21394],{"class":114,"line":49},[112,21395,21396],{},"RobotPart p2 = new Intake(\"Front Intake\");   \u002F\u002F legal — an Intake IS-A RobotPart\n",[112,21398,21399],{"class":114,"line":126},[112,21400,21401],{},"RobotPart p3 = new Climber(\"Left Climber\");  \u002F\u002F legal — a Climber IS-A RobotPart\n",[15,21403,21404,21405,21407,21408,738],{},"The reverse doesn't work — a subclass-typed variable cannot hold a plain superclass object, since not every ",[95,21406,20446],{}," is specifically an ",[95,21409,9838],{},[104,21411,21413],{"className":106,"code":21412,"language":108,"meta":48,"style":48},"\u002F\u002F ERROR — a RobotPart isn't necessarily an Intake\nIntake i = new RobotPart(\"Generic\");\n",[95,21414,21415,21420],{"__ignoreMap":48},[112,21416,21417],{"class":114,"line":115},[112,21418,21419],{},"\u002F\u002F ERROR — a RobotPart isn't necessarily an Intake\n",[112,21421,21422],{"class":114,"line":49},[112,21423,21424],{},"Intake i = new RobotPart(\"Generic\");\n",[69,21426,21428],{"id":21427},"why-this-matters-one-parameter-type-every-subclass","Why This Matters: One Parameter Type, Every Subclass",[15,21430,21431],{},"A method, array, or collection typed against the superclass automatically accepts every subclass too — this is what makes managing all of a robot's parts from one place possible:",[104,21433,21435],{"className":106,"code":21434,"language":108,"meta":48,"style":48},"public void stopAll(RobotPart[] parts)\n{\n    for (RobotPart p : parts)\n    {\n        \u002F\u002F works for an Intake, a Climber, a Shooter — anything extending RobotPart\n        p.stop();\n    }\n}\n\nRobotPart[] parts = { new Intake(\"Front\"), new Climber(\"Left\"), new Shooter(\"Main\") };\nstopAll(parts);\n",[95,21436,21437,21442,21446,21451,21455,21460,21465,21469,21473,21477,21482],{"__ignoreMap":48},[112,21438,21439],{"class":114,"line":115},[112,21440,21441],{},"public void stopAll(RobotPart[] parts)\n",[112,21443,21444],{"class":114,"line":49},[112,21445,123],{},[112,21447,21448],{"class":114,"line":126},[112,21449,21450],{},"    for (RobotPart p : parts)\n",[112,21452,21453],{"class":114,"line":132},[112,21454,135],{},[112,21456,21457],{"class":114,"line":138},[112,21458,21459],{},"        \u002F\u002F works for an Intake, a Climber, a Shooter — anything extending RobotPart\n",[112,21461,21462],{"class":114,"line":144},[112,21463,21464],{},"        p.stop();\n",[112,21466,21467],{"class":114,"line":150},[112,21468,147],{},[112,21470,21471],{"class":114,"line":2276},[112,21472,153],{},[112,21474,21475],{"class":114,"line":2282},[112,21476,907],{"emptyLinePlaceholder":55},[112,21478,21479],{"class":114,"line":2288},[112,21480,21481],{},"RobotPart[] parts = { new Intake(\"Front\"), new Climber(\"Left\"), new Shooter(\"Main\") };\n",[112,21483,21484],{"class":114,"line":5760},[112,21485,21486],{},"stopAll(parts);\n",[15,21488,21489,21490,21493,21494,322,21496,325,21498,21500],{},"The same holds for collections — an ",[95,21491,21492],{},"ArrayList\u003CRobotPart>"," happily holds ",[95,21495,9838],{},[95,21497,11675],{},[95,21499,20639],{}," objects side by side:",[104,21502,21504],{"className":106,"code":21503,"language":108,"meta":48,"style":48},"ArrayList\u003CRobotPart> allParts = new ArrayList\u003CRobotPart>();\nallParts.add(new Intake(\"Front\"));\nallParts.add(new Climber(\"Left\"));\n",[95,21505,21506,21511,21516],{"__ignoreMap":48},[112,21507,21508],{"class":114,"line":115},[112,21509,21510],{},"ArrayList\u003CRobotPart> allParts = new ArrayList\u003CRobotPart>();\n",[112,21512,21513],{"class":114,"line":49},[112,21514,21515],{},"allParts.add(new Intake(\"Front\"));\n",[112,21517,21518],{"class":114,"line":126},[112,21519,21520],{},"allParts.add(new Climber(\"Left\"));\n",[69,21522,21524],{"id":21523},"which-method-actually-runs","Which Method Actually Runs?",[15,21526,21527,21528,21530,21531,21534,21535,21537,21538,21540,21541,21543],{},"When a method typed against the superclass is called on an object that's actually a subclass instance, Java runs ",[494,21529,4846],{}," actual version of the method — decided by its real runtime type, not the variable's declared type. This is the foundation of ",[25,21532,21533],{},"polymorphism",", covered in full in Lesson 18.3 — for now, the key idea is just that a ",[95,21536,20446],{},"-typed variable holding an ",[95,21539,9838],{}," object still calls ",[95,21542,9838],{},"'s own overridden methods, if it has any (overriding, Lesson 18.1).",[69,21545,462],{"id":461},[19,21547,21548,21563,21579],{},[22,21549,21550,476,21553,21556,21557,21559,21560,21562],{},[25,21551,21552],{},"Trying to assign a superclass object to a subclass-typed variable.",[95,21554,21555],{},"Intake i = new RobotPart(...);"," is a compile error — not every ",[95,21558,20446],{}," is an ",[95,21561,9838],{},". This only ever works the other direction (superclass variable, subclass object).",[22,21564,21565,21575,21576,21578],{},[25,21566,21567,21568,21571,21572,21574],{},"Thinking a ",[95,21569,21570],{},"RobotPart[]"," array can only hold plain ",[95,21573,20446],{}," objects."," It can hold any mix of ",[95,21577,20446],{}," and its subclasses — that flexibility is the entire point of typing the array against the superclass.",[22,21580,21581,21584,21585,21587,21588,21590,21591,21593],{},[25,21582,21583],{},"Forgetting which method version actually runs."," Even though a variable is declared ",[95,21586,20446],{},", calling a method on it runs the object's ",[494,21589,10890],{}," class's version — not necessarily ",[95,21592,20446],{},"'s own.",[69,21595,501],{"id":500},[19,21597,21598,21604,21607,21610],{},[22,21599,21600,21601,21603],{},"Several subclasses inheriting from one common superclass form an inheritance hierarchy, with ",[95,21602,19753],{}," at the top of every hierarchy in Java.",[22,21605,21606],{},"A superclass-typed variable, array, or collection can hold objects of that class or any of its subclasses — never the reverse.",[22,21608,21609],{},"This lets one method signature, one array type, or one collection type work seamlessly across an entire family of related robot-part classes.",[22,21611,21612],{},"Which method actually executes depends on the object's real runtime type, not the variable's declared type — the basis of polymorphism (Lesson 18.3).",[15,21614,544,21615,548,21617,21620],{},[95,21616,547],{},[95,21618,21619],{},"unit-5-inheritance-optional\u002F5.05-inheritance-hierarchies.md"," (CSA 5.5)",[554,21622,556],{},{"title":48,"searchDepth":49,"depth":49,"links":21624},[21625,21626,21627,21628,21629,21630],{"id":21342,"depth":49,"text":21343},{"id":21374,"depth":49,"text":21375},{"id":21427,"depth":49,"text":21428},{"id":21523,"depth":49,"text":21524},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":21632,"status":15483},"17.3 — Inheritance Hierarchies (CSA 5.5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F3-inheritance-hierarchies",{"title":21334,"description":48},"shockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.3-inheritance-hierarchies","w5B3-vZR2j83yFIJgUIn5crruwgUzLEd5Q0WodK8qEo",{"id":21638,"title":21639,"body":21640,"description":48,"extension":51,"meta":22394,"navigation":55,"path":22396,"seo":22397,"stem":22398,"__hash__":22399},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.4-object-superclass.md","Object Superclass",{"type":8,"value":21641,"toc":22383},[21642,21645,21649,21673,21686,21690,21709,21745,21759,21814,21818,21832,21836,21891,21895,21943,21949,21992,22009,22043,22047,22081,22106,22118,22145,22167,22171,22229,22231,22301,22303,22373,22381],[11,21643,21639],{"id":21644},"object-superclass",[69,21646,21648],{"id":21647},"every-classs-ultimate-parent","Every Class's Ultimate Parent",[15,21650,21651,12217,21653,21655,21656,21658,21659,21661,21662,322,21664,21667,21668,195,21670,79],{},[95,21652,19753],{},[95,21654,3200],{},") is the superclass of every class in Java — any class without an explicit ",[95,21657,16804],{}," inherits from it automatically. Three of ",[95,21660,19753],{},"'s methods matter enough to override in almost every class you write: ",[95,21663,16983],{},[95,21665,21666],{},"equals(Object other)",", and — always together with ",[95,21669,19530],{},[95,21671,21672],{},"hashCode()",[15,21674,21675,21676,21679,21680,21682,21683,21685],{},"This lesson replaces inherited methods with new versions, which is called ",[25,21677,21678],{},"overriding",", and marks each one with ",[95,21681,10343],{},". Lesson 18.1 covers overriding in full; for now, ",[95,21684,10343],{}," just tells the compiler \"this method replaces one I inherited,\" and the compiler double-checks that it really does.",[69,21687,21689],{"id":21688},"overriding-tostring","Overriding toString()",[15,21691,21692,21694,21695,21697,21698,21701,21702,21705,21706,21708],{},[95,21693,19753],{},"'s default ",[95,21696,16983],{}," produces an unhelpful string like ",[95,21699,21700],{},"RobotPart@1a2b3c"," (the class name, ",[95,21703,21704],{},"@",", and the object's hash code in hex). Overriding it to describe the object's real state is good practice in nearly every class. Here's what ",[95,21707,20446],{}," (Lesson 17.1) adds:",[104,21710,21712],{"className":106,"code":21711,"language":108,"meta":48,"style":48},"public class RobotPart\n{\n    \u002F\u002F ...name field, constructor, getName(), log(), and stop() as in Lesson 17.1\n\n    @Override\n    public String toString() { return name; }\n}\n",[95,21713,21714,21718,21722,21727,21731,21736,21741],{"__ignoreMap":48},[112,21715,21716],{"class":114,"line":115},[112,21717,20457],{},[112,21719,21720],{"class":114,"line":49},[112,21721,123],{},[112,21723,21724],{"class":114,"line":126},[112,21725,21726],{},"    \u002F\u002F ...name field, constructor, getName(), log(), and stop() as in Lesson 17.1\n",[112,21728,21729],{"class":114,"line":132},[112,21730,907],{"emptyLinePlaceholder":55},[112,21732,21733],{"class":114,"line":138},[112,21734,21735],{},"    @Override\n",[112,21737,21738],{"class":114,"line":144},[112,21739,21740],{},"    public String toString() { return name; }\n",[112,21742,21743],{"class":114,"line":150},[112,21744,153],{},[15,21746,21747,21748,21750,21751,21754,21755,21758],{},"A subclass's own ",[95,21749,16983],{}," can call ",[95,21752,21753],{},"super.toString()"," — \"the superclass's version of this method\" (Lesson 18.2 covers ",[95,21756,21757],{},"super.method()"," in full) — and build on it, rather than starting from scratch:",[104,21760,21762],{"className":106,"code":21761,"language":108,"meta":48,"style":48},"public class Intake extends RobotPart\n{\n    private boolean hasGamePiece;\n\n    public Intake(String name) { super(name); }\n\n    @Override\n    public String toString()\n    {\n        return super.toString() + \" (hasGamePiece=\" + hasGamePiece + \")\";\n    }\n}\n",[95,21763,21764,21768,21772,21776,21780,21784,21788,21792,21797,21801,21806,21810],{"__ignoreMap":48},[112,21765,21766],{"class":114,"line":115},[112,21767,20502],{},[112,21769,21770],{"class":114,"line":49},[112,21771,123],{},[112,21773,21774],{"class":114,"line":126},[112,21775,9894],{},[112,21777,21778],{"class":114,"line":132},[112,21779,907],{"emptyLinePlaceholder":55},[112,21781,21782],{"class":114,"line":138},[112,21783,20516],{},[112,21785,21786],{"class":114,"line":144},[112,21787,907],{"emptyLinePlaceholder":55},[112,21789,21790],{"class":114,"line":150},[112,21791,21735],{},[112,21793,21794],{"class":114,"line":2276},[112,21795,21796],{},"    public String toString()\n",[112,21798,21799],{"class":114,"line":2282},[112,21800,135],{},[112,21802,21803],{"class":114,"line":2288},[112,21804,21805],{},"        return super.toString() + \" (hasGamePiece=\" + hasGamePiece + \")\";\n",[112,21807,21808],{"class":114,"line":5760},[112,21809,147],{},[112,21811,21812],{"class":114,"line":5766},[112,21813,153],{},[69,21815,21817],{"id":21816},"the-equals-method","The equals() Method",[15,21819,21820,21822,21823,21825,21826,21828,21829,21831],{},[95,21821,21666],{},", inherited from ",[95,21824,19753],{},", tests whether two references point to the exact same object — the same result as ",[95,21827,1921],{}," (the \"== vs. .equals()\" gotcha from Lesson 6.1 and Ch.13 exists precisely because many classes, like ",[95,21830,361],{},", override this default with something more useful).",[69,21833,21835],{"id":21834},"checking-and-casting-object-types","Checking and Casting Object Types",[15,21837,21838,21839,21841,21842,21844,21845,1291,21848,21850,21851,21853,21854,21856,21857,21859,21860,1291,21862,21864,21865,21867,21868,21871,21872,21874,21875,21877,21878,21880,21881,21883,21884,21886,21887,21890],{},"Overriding ",[95,21840,19530],{}," needs two tools for working with an ",[95,21843,19753],{},"-typed parameter. ",[95,21846,21847],{},"x instanceof RobotPart",[95,21849,661],{}," when the object ",[95,21852,852],{}," refers to is a ",[95,21855,20446],{}," or any subclass of one (and ",[95,21858,664],{}," when ",[95,21861,852],{},[95,21863,4645],{},"). A ",[25,21866,19782],{}," like ",[95,21869,21870],{},"(RobotPart) other"," tells the compiler to treat an ",[95,21873,19753],{}," reference as a ",[95,21876,20446],{}," reference, so ",[95,21879,20446],{},"'s fields and methods can be used through it — it doesn't change the object at all. If the object isn't really a ",[95,21882,20446],{},", the cast throws a ",[95,21885,19547],{},", which is why the ",[95,21888,21889],{},"instanceof"," check comes first. Lesson 18.3 covers casting between class types in full.",[69,21892,21894],{"id":21893},"overriding-equals-correctly","Overriding equals() Correctly",[15,21896,21838,21897,21899,21900,21902,21903,2150,21906,21909,21910,19932,21912,2150,21915,21918,21919,19932,21922,2150,21925,537,21927,21930,21931,19932,21934,21937,21938,79],{},[95,21898,19530],{}," is more involved than ",[95,21901,10318],{},", since it has to satisfy five formal requirements to remain safe to use anywhere: ",[25,21904,21905],{},"reflexive",[95,21907,21908],{},"o.equals(o)"," is always ",[95,21911,661],{},[25,21913,21914],{},"symmetric",[95,21916,21917],{},"a.equals(b)"," matches ",[95,21920,21921],{},"b.equals(a)",[25,21923,21924],{},"transitive",[95,21926,21917],{},[95,21928,21929],{},"b.equals(c)"," implies ",[95,21932,21933],{},"a.equals(c)",[25,21935,21936],{},"consistent"," (repeated calls give the same answer, if nothing changed), and ",[25,21939,21940,21941],{},"never equal to ",[95,21942,4645],{},[15,21944,21945,21946,21948],{},"A standard recipe, added to ",[95,21947,20446],{},", satisfies all five:",[104,21950,21952],{"className":106,"code":21951,"language":108,"meta":48,"style":48},"@Override\npublic boolean equals(Object other)\n{\n    if (this == other) return true;                   \u002F\u002F 1. quick check: same object\n    if (!(other instanceof RobotPart)) return false;  \u002F\u002F 2. must be the same type\n    RobotPart o = (RobotPart) other;                  \u002F\u002F 3. safe to cast now\n    return this.name.equals(o.name);                  \u002F\u002F 4. compare the relevant fields\n}\n",[95,21953,21954,21959,21964,21968,21973,21978,21983,21988],{"__ignoreMap":48},[112,21955,21956],{"class":114,"line":115},[112,21957,21958],{},"@Override\n",[112,21960,21961],{"class":114,"line":49},[112,21962,21963],{},"public boolean equals(Object other)\n",[112,21965,21966],{"class":114,"line":126},[112,21967,123],{},[112,21969,21970],{"class":114,"line":132},[112,21971,21972],{},"    if (this == other) return true;                   \u002F\u002F 1. quick check: same object\n",[112,21974,21975],{"class":114,"line":138},[112,21976,21977],{},"    if (!(other instanceof RobotPart)) return false;  \u002F\u002F 2. must be the same type\n",[112,21979,21980],{"class":114,"line":144},[112,21981,21982],{},"    RobotPart o = (RobotPart) other;                  \u002F\u002F 3. safe to cast now\n",[112,21984,21985],{"class":114,"line":150},[112,21986,21987],{},"    return this.name.equals(o.name);                  \u002F\u002F 4. compare the relevant fields\n",[112,21989,21990],{"class":114,"line":2276},[112,21991,153],{},[15,21993,21994,21995,548,21998,22001,22002,22005,22006,22008],{},"Since Java 16, steps 2 and 3 can be combined into one line with a ",[494,21996,21997],{},"pattern",[95,21999,22000],{},"if (!(other instanceof RobotPart o)) return false;"," checks the type and, when the check passes, gives you ",[95,22003,22004],{},"o"," already cast to ",[95,22007,20446],{},". Both versions do exactly the same thing.",[15,22010,22011,22012,22014,22015,22018,22019,22021,22022,322,22025,322,22027,22029,22030,22033,22034,22036,22037,22039,22040,22042],{},"Note the parameter type is always ",[95,22013,19753],{},", never the class itself. ",[95,22016,22017],{},"equals(RobotPart other)"," would be a completely different method (overloading, not overriding): it runs only when the argument's declared type is ",[95,22020,20446],{},". Library code — ",[95,22023,22024],{},"ArrayList.contains",[95,22026,12950],{},[95,22028,18778],{}," — always calls ",[95,22031,22032],{},"equals(Object)",", which would still be ",[95,22035,19753],{},"'s identity check. The bug stays silent until a collection gives a wrong answer, and ",[95,22038,10343],{}," is what catches it: on ",[95,22041,22017],{}," it's a compile error.",[69,22044,22046],{"id":22045},"equals-and-hashcode-go-together","equals() and hashCode() Go Together",[15,22048,22049,22051,22052,548,22054,22056,22057,22059,22060,537,22062,22064,22065,845,22073,21694,22075,22077,22078,22080],{},[95,22050,19753],{}," has a third method tied to ",[95,22053,19530],{},[95,22055,21672],{},", which returns an ",[95,22058,603],{}," that ",[95,22061,12950],{},[95,22063,18778],{}," (Ch.9, Ch.15) use to decide where to store and look for an object. The rule: ",[25,22066,22067,22068,22070,22071],{},"two objects that are ",[95,22069,19530],{}," must return the same ",[95,22072,21672],{},[95,22074,19753],{},[95,22076,21672],{}," gives every separate object its own value, so a class that overrides only ",[95,22079,19530],{}," breaks hash-based collections:",[104,22082,22084],{"className":106,"code":22083,"language":108,"meta":48,"style":48},"HashSet\u003CRobotPart> parts = new HashSet\u003CRobotPart>();\nparts.add(new RobotPart(\"Front Intake\"));\n\u002F\u002F false without a hashCode() override, even though equals() says they match\nSystem.out.println(parts.contains(new RobotPart(\"Front Intake\")));\n",[95,22085,22086,22091,22096,22101],{"__ignoreMap":48},[112,22087,22088],{"class":114,"line":115},[112,22089,22090],{},"HashSet\u003CRobotPart> parts = new HashSet\u003CRobotPart>();\n",[112,22092,22093],{"class":114,"line":49},[112,22094,22095],{},"parts.add(new RobotPart(\"Front Intake\"));\n",[112,22097,22098],{"class":114,"line":126},[112,22099,22100],{},"\u002F\u002F false without a hashCode() override, even though equals() says they match\n",[112,22102,22103],{"class":114,"line":132},[112,22104,22105],{},"System.out.println(parts.contains(new RobotPart(\"Front Intake\")));\n",[15,22107,22108,22109,22111,22112,22114,22115,22117],{},"The fix is to override ",[95,22110,21672],{}," whenever you override ",[95,22113,19530],{},", built from the same fields ",[95,22116,19530],{}," compares:",[104,22119,22121],{"className":106,"code":22120,"language":108,"meta":48,"style":48},"@Override\npublic int hashCode()\n{\n    return name.hashCode();  \u002F\u002F same name -> same hash code\n}\n",[95,22122,22123,22127,22132,22136,22141],{"__ignoreMap":48},[112,22124,22125],{"class":114,"line":115},[112,22126,21958],{},[112,22128,22129],{"class":114,"line":49},[112,22130,22131],{},"public int hashCode()\n",[112,22133,22134],{"class":114,"line":126},[112,22135,123],{},[112,22137,22138],{"class":114,"line":132},[112,22139,22140],{},"    return name.hashCode();  \u002F\u002F same name -> same hash code\n",[112,22142,22143],{"class":114,"line":138},[112,22144,153],{},[15,22146,22147,22148,22150,22151,22153,22154,22156,22157,22159,22160,12217,22163,22166],{},"With that added to ",[95,22149,20446],{},", the ",[95,22152,9402],{}," call above prints ",[95,22155,661],{},". For a class whose ",[95,22158,19530],{}," compares several fields, ",[95,22161,22162],{},"return Objects.hash(field1, field2);",[95,22164,22165],{},"java.util.Objects",") combines them.",[69,22168,22170],{"id":22169},"the-subclass-equals-trap","The Subclass equals() Trap",[15,22172,21838,22173,22175,22176,22179,22180,22182,22183,22185,22186,4029,22188,22191,22192,7596,22194,22197,22198,14935,22200,22202,22203,2339,22205,22197,22208,14935,22210,22212,22213,22216,22217,22219,22220,22222,22223,22225,22226,22228],{},[95,22174,19530],{}," again in a subclass of a class that's already overridden it is genuinely difficult to get right, and easy to accidentally break ",[25,22177,22178],{},"symmetry",". If ",[95,22181,9838],{}," (subclass of ",[95,22184,20446],{},") overrode ",[95,22187,19530],{},[494,22189,22190],{},"also"," compare ",[95,22193,10261],{},[95,22195,22196],{},"genericPart.equals(intakeObj)"," would call ",[95,22199,20446],{},[95,22201,19530],{}," (comparing only ",[95,22204,9621],{},[95,22206,22207],{},"intakeObj.equals(genericPart)",[95,22209,9838],{},[95,22211,19530],{}," — which checks ",[95,22214,22215],{},"other instanceof Intake"," and returns ",[95,22218,664],{},", since a plain ",[95,22221,20446],{}," isn't an ",[95,22224,9838],{},". The two calls disagree, breaking the symmetry rule. The general guideline: only one class in a hierarchy should provide a real ",[95,22227,19530],{}," override.",[69,22230,462],{"id":461},[19,22232,22233,22259,22275,22291],{},[22,22234,22235,22241,22242,22244,22245,22247,22248,537,22250,22252,22253,22255,22256,22258],{},[25,22236,6120,22237,3181,22239,79],{},[95,22238,22017],{},[95,22240,21666],{}," That's overloading a new method, not overriding ",[95,22243,19753],{},"'s — it only runs for ",[95,22246,20446],{},"-typed arguments, while collections like ",[95,22249,12343],{},[95,22251,18778],{}," still call ",[95,22254,19753],{},"'s original identity check. ",[95,22257,10343],{}," turns this mistake into a compile error.",[22,22260,22261,22267,22268,537,22271,22274],{},[25,22262,21838,22263,12778,22265,79],{},[95,22264,19530],{},[95,22266,19533],{}," Two equal objects then usually have different hash codes, so ",[95,22269,22270],{},"HashSet.contains",[95,22272,22273],{},"HashMap.get"," quietly fail to find them. Override both, using the same fields.",[22,22276,22277,22282,22283,22285,22286,9065,22288,22290],{},[25,22278,20257,22279,22281],{},[95,22280,21889],{}," check before casting."," Casting ",[95,22284,9053],{}," to your class without checking first throws ",[95,22287,19547],{},[95,22289,9053],{}," turns out to be some unrelated type.",[22,22292,22293,22298,22299,22228],{},[25,22294,21838,22295,22297],{},[95,22296,19530],{}," again further down an inheritance hierarchy."," This tends to violate symmetry — safest to let only one class in the hierarchy own the ",[95,22300,19530],{},[69,22302,501],{"id":500},[19,22304,22305,22317,22325,22339,22358,22367],{},[22,22306,22307,22309,22310,322,22312,325,22314,22316],{},[95,22308,19753],{}," is the superclass of every class in Java; ",[95,22311,16983],{},[95,22313,21666],{},[95,22315,21672],{}," are its methods worth overriding almost everywhere.",[22,22318,22319,22320,21750,22322,22324],{},"A subclass's ",[95,22321,16983],{},[95,22323,21753],{}," and extend it, rather than rebuilding the whole description from scratch.",[22,22326,22327,21694,22329,22331,22332,22334,22335,9706,22337,79],{},[95,22328,19753],{},[95,22330,19530],{}," is identity comparison (same as ",[95,22333,1921],{},"); a correct override must be reflexive, symmetric, transitive, consistent, and never ",[95,22336,661],{},[95,22338,4645],{},[22,22340,22341,22342,22344,22345,22348,22349,22351,22352,22355,22356,79],{},"The standard ",[95,22343,19530],{}," recipe: check ",[95,22346,22347],{},"this == other",", check ",[95,22350,21889],{},", cast (or use the ",[95,22353,22354],{},"instanceof RobotPart o"," pattern), then compare the relevant fields — always with parameter type ",[95,22357,19753],{},[22,22359,22360,22361,22363,22364,22366],{},"Whenever you override ",[95,22362,19530],{},", override ",[95,22365,19533],{}," from the same fields — equal objects must have equal hash codes.",[22,22368,22369,22370,22372],{},"Avoid overriding ",[95,22371,19530],{}," more than once down an inheritance hierarchy — it tends to break symmetry.",[15,22374,544,22375,548,22377,22380],{},[95,22376,547],{},[95,22378,22379],{},"unit-5-inheritance-optional\u002F5.07-object-superclass.md"," (CSA 5.7)",[554,22382,556],{},{"title":48,"searchDepth":49,"depth":49,"links":22384},[22385,22386,22387,22388,22389,22390,22391,22392,22393],{"id":21647,"depth":49,"text":21648},{"id":21688,"depth":49,"text":21689},{"id":21816,"depth":49,"text":21817},{"id":21834,"depth":49,"text":21835},{"id":21893,"depth":49,"text":21894},{"id":22045,"depth":49,"text":22046},{"id":22169,"depth":49,"text":22170},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":22395,"status":15483},"17.4 — Object Superclass (CSA 5.7)","\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F4-object-superclass",{"title":21639,"description":48},"shockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.4-object-superclass","nYX24mRpFUeADsrhmH4BbIopA2MyFCSajwjHn3_lLgM",{"id":22401,"title":22402,"body":22403,"description":48,"extension":51,"meta":22852,"navigation":55,"path":22855,"seo":22856,"stem":22857,"__hash__":22858},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.5-abstract-classes-and-methods.md","Abstract Classes and Methods",{"type":8,"value":22404,"toc":22841},[22405,22408,22412,22436,22440,22458,22505,22508,22523,22530,22534,22555,22559,22569,22603,22622,22626,22634,22689,22693,22715,22719,22735,22747,22749,22794,22796,22833,22839],[11,22406,22402],{"id":22407},"abstract-classes-and-methods",[69,22409,22411],{"id":22410},"a-class-that-shouldnt-be-instantiated","A Class That Shouldn't Be Instantiated",[15,22413,22414,22415,22417,22418,22421,22422,14935,22424,22426,22427,22429,22430,22432,22433,79],{},"Every example so far could build a plain ",[95,22416,20446],{}," — Lesson 17.3 even wrote ",[95,22419,22420],{},"new RobotPart(\"Generic\")",". But on a real robot there's no such thing as \"just a robot part\": every part is an intake, a shooter, a climber. And ",[95,22423,20446],{},[95,22425,20442],{}," only prints a message, while every real part has to stop its own hardware in its own way. What the design really wants to say is \"",[95,22428,20446],{}," is only a starting point — every real part must be a subclass, and every subclass must write its own ",[95,22431,20442],{},".\" Java says exactly that with the keyword ",[95,22434,22435],{},"abstract",[69,22437,22439],{"id":22438},"abstract-classes","Abstract Classes",[15,22441,6120,22442,22444,22445,22448,22449,22451,22452,22454,22455,22457],{},[95,22443,22435],{}," in the class declaration makes it an ",[25,22446,22447],{},"abstract class",": a class that can be extended, but never instantiated with ",[95,22450,2504],{},". Here's ",[95,22453,20446],{}," from Lesson 17.1 as an abstract class, with ",[95,22456,20442],{}," turned into an abstract method:",[104,22459,22461],{"className":106,"code":22460,"language":108,"meta":48,"style":48},"public abstract class RobotPart\n{\n    private String name;\n\n    public RobotPart(String name) { this.name = name; }\n    public String getName() { return name; }\n    public void log(String msg) { System.out.println(\"[\" + name + \"] \" + msg); }\n\n    public abstract void stop();  \u002F\u002F no body: every subclass writes its own\n}\n",[95,22462,22463,22468,22472,22476,22480,22484,22488,22492,22496,22501],{"__ignoreMap":48},[112,22464,22465],{"class":114,"line":115},[112,22466,22467],{},"public abstract class RobotPart\n",[112,22469,22470],{"class":114,"line":49},[112,22471,123],{},[112,22473,22474],{"class":114,"line":126},[112,22475,10679],{},[112,22477,22478],{"class":114,"line":132},[112,22479,907],{"emptyLinePlaceholder":55},[112,22481,22482],{"class":114,"line":138},[112,22483,20474],{},[112,22485,22486],{"class":114,"line":144},[112,22487,20479],{},[112,22489,22490],{"class":114,"line":150},[112,22491,20484],{},[112,22493,22494],{"class":114,"line":2276},[112,22495,907],{"emptyLinePlaceholder":55},[112,22497,22498],{"class":114,"line":2282},[112,22499,22500],{},"    public abstract void stop();  \u002F\u002F no body: every subclass writes its own\n",[112,22502,22503],{"class":114,"line":2288},[112,22504,153],{},[15,22506,22507],{},"Trying to build one directly is now a compile error:",[104,22509,22511],{"className":106,"code":22510,"language":108,"meta":48,"style":48},"\u002F\u002F ERROR: RobotPart is abstract; cannot be instantiated\nRobotPart generic = new RobotPart(\"Generic\");\n",[95,22512,22513,22518],{"__ignoreMap":48},[112,22514,22515],{"class":114,"line":115},[112,22516,22517],{},"\u002F\u002F ERROR: RobotPart is abstract; cannot be instantiated\n",[112,22519,22520],{"class":114,"line":49},[112,22521,22522],{},"RobotPart generic = new RobotPart(\"Generic\");\n",[15,22524,22525,22526,22529],{},"A class that can be instantiated — every class you've written until now — is called a ",[25,22527,22528],{},"concrete"," class.",[69,22531,22533],{"id":22532},"abstract-methods","Abstract Methods",[15,22535,1851,22536,22539,22540,22542,22543,22546,22547,10956,22549,22551,22552,22554],{},[25,22537,22538],{},"abstract method"," is declared with ",[95,22541,22435],{},", has a signature, and ends in a semicolon instead of a body: ",[95,22544,22545],{},"public abstract void stop();"," says \"every ",[95,22548,20446],{},[95,22550,20442],{}," method\" without saying what it does. A class that declares an abstract method must itself be marked ",[95,22553,22435],{}," — otherwise it doesn't compile.",[69,22556,22558],{"id":22557},"concrete-subclasses-must-fill-in-every-abstract-method","Concrete Subclasses Must Fill In Every Abstract Method",[15,22560,22561,22562,22565,22566,22568],{},"A concrete subclass must provide a body for every abstract method it inherits. Writing that body is called ",[25,22563,22564],{},"implementing"," the method — it uses the same syntax as overriding (Lesson 18.1), including ",[95,22567,10343],{}," (Lesson 17.4):",[104,22570,22572],{"className":106,"code":22571,"language":108,"meta":48,"style":48},"public class Intake extends RobotPart\n{\n    public Intake(String name) { super(name); }\n\n    @Override\n    public void stop() { log(\"rollers off\"); }\n}\n",[95,22573,22574,22578,22582,22586,22590,22594,22599],{"__ignoreMap":48},[112,22575,22576],{"class":114,"line":115},[112,22577,20502],{},[112,22579,22580],{"class":114,"line":49},[112,22581,123],{},[112,22583,22584],{"class":114,"line":126},[112,22585,20516],{},[112,22587,22588],{"class":114,"line":132},[112,22589,907],{"emptyLinePlaceholder":55},[112,22591,22592],{"class":114,"line":138},[112,22593,21735],{},[112,22595,22596],{"class":114,"line":144},[112,22597,22598],{},"    public void stop() { log(\"rollers off\"); }\n",[112,22600,22601],{"class":114,"line":150},[112,22602,153],{},[15,22604,7566,22605,22607,22608,22610,22611,22614,22615,22617,22618,22621],{},[95,22606,9838],{}," left ",[95,22609,20442],{}," out, the compiler would reject it: ",[95,22612,22613],{},"Intake is not abstract and does not override abstract method stop() in RobotPart",". The only other option is for the subclass to be declared ",[95,22616,22435],{}," too, passing the job down to ",[494,22619,22620],{},"its"," subclasses.",[69,22623,22625],{"id":22624},"what-an-abstract-class-can-still-have","What an Abstract Class Can Still Have",[15,22627,22628,22630,22631,22633],{},[95,22629,22435],{}," removes only the ability to call ",[95,22632,2504],{}," on the class itself. Everything else still works:",[19,22635,22636,22646,22662,22672],{},[22,22637,22638,195,22641,22643,22644,79],{},[25,22639,22640],{},"Fields",[95,22642,20446],{}," still has its private ",[95,22645,9621],{},[22,22647,22648,195,22650,22652,22653,22655,22656,22658,22659,79],{},[25,22649,9847],{},[95,22651,21001],{}," still exists and still runs for every ",[95,22654,9838],{},", through ",[95,22657,20547],{}," (Lesson 17.2). You just can't call it with ",[95,22660,22661],{},"new RobotPart(...)",[22,22663,22664,195,22667,537,22669,22671],{},[25,22665,22666],{},"Concrete methods",[95,22668,21059],{},[95,22670,20595],{}," have bodies, and every subclass inherits them unchanged.",[22,22673,22674,195,22677,22679,22680,537,22683,22686,22687,79],{},[25,22675,22676],{},"Use as a type",[95,22678,20446],{}," is still a perfectly good variable, parameter, array, or collection type (Lesson 17.3): ",[95,22681,22682],{},"RobotPart part = new Intake(\"Front\");",[95,22684,22685],{},"RobotPart[] parts = { new Intake(\"Front\"), new Climber(\"Left\") };"," both compile. Every object they hold is some concrete subclass, so every one of them really has a ",[95,22688,20442],{},[69,22690,22692],{"id":22691},"abstract-classes-in-wpilib","Abstract Classes in WPILib",[15,22694,22695,22696,22699,22700,22703,22704,325,22707,22710,22711,22714],{},"WPILib uses the same tool. ",[95,22697,22698],{},"MotorSafety"," (in ",[95,22701,22702],{},"org.wpilib.hardware.motor",") is an abstract class that declares ",[95,22705,22706],{},"public abstract void stopMotor();",[95,22708,22709],{},"PWMMotorController",", the shared parent of WPILib's PWM motor controller classes, is abstract too. Robot code never writes ",[95,22712,22713],{},"new PWMMotorController(...)"," — it constructs one of the specific controller classes that extend it, each of which inherits the shared code.",[69,22716,22718],{"id":22717},"looking-ahead-interfaces","Looking Ahead: Interfaces",[15,22720,22721,22722,22724,22725,22727,22728,14935,22730,537,22732,22734],{},"Ch.19 introduces ",[25,22723,18663],{},", a related tool: a type that lists methods a class promises to have, but that has no fields holding object state and no constructors, and that a class can ",[95,22726,16808],{}," several of at once. Ch.19 compares the two directly. The short version: reach for an abstract class when the related classes share real state and code (like ",[95,22729,20446],{},[95,22731,9621],{},[95,22733,20595],{},"), and an interface when they only share a set of methods.",[15,22736,22737,22738,22740,22741,22743,22744,22746],{},"The rest of this course's ",[95,22739,20446],{}," examples, starting in Ch.18, go back to the concrete ",[95,22742,20446],{}," from Lesson 17.1, whose ",[95,22745,20442],{}," has a body — Ch.18's lessons override and extend that body.",[69,22748,462],{"id":461},[19,22750,22751,22765,22777,22785],{},[22,22752,22753,476,22756,22758,22759,22761,22762,22764],{},[25,22754,22755],{},"Trying to instantiate an abstract class.",[95,22757,22420],{}," doesn't compile once ",[95,22760,20446],{}," is abstract — build a concrete subclass instead, and store it in a ",[95,22763,20446],{}," variable if you like.",[22,22766,22767,476,22770,22773,22774,22776],{},[25,22768,22769],{},"Giving an abstract method a body, or leaving the semicolon off.",[95,22771,22772],{},"public abstract void stop() { }"," doesn't compile — an abstract method is a signature followed by ",[95,22775,238],{},", with no braces at all.",[22,22778,22779,22782,22783,79],{},[25,22780,22781],{},"Forgetting to implement an abstract method in a concrete subclass."," Every abstract method the subclass inherits needs a body, or the subclass must itself be declared ",[95,22784,22435],{},[22,22786,22787,22790,22791,22793],{},[25,22788,22789],{},"Thinking an abstract class can't have constructors or fields."," It can have both; its constructor runs through ",[95,22792,20858],{}," from each subclass.",[69,22795,501],{"id":500},[19,22797,22798,22806,22811,22819,22825],{},[22,22799,1851,22800,22802,22803,22805],{},[95,22801,22435],{}," class can be extended but never instantiated with ",[95,22804,2504],{},"; a class that can be instantiated is concrete.",[22,22807,22808,22809,79],{},"An abstract method has a signature and a semicolon but no body; a class that declares one must itself be ",[95,22810,22435],{},[22,22812,22813,22814,22816,22817,21005],{},"A concrete subclass must implement every inherited abstract method (same syntax as overriding, with ",[95,22815,10343],{},"), or be declared ",[95,22818,22435],{},[22,22820,22821,22822,22824],{},"Abstract classes still have fields, constructors (run through ",[95,22823,20858],{},"), concrete methods, and can be used as variable, parameter, and collection types.",[22,22826,22827,22828,322,22830,22832],{},"WPILib uses abstract classes too (",[95,22829,22698],{},[95,22831,22709],{},"); Ch.19's interfaces are the related tool for sharing methods without shared state.",[15,22834,22835,22836,22838],{},"Authored for this course (new lesson from the 2026-09 content audit; no ",[95,22837,547],{}," source).",[554,22840,556],{},{"title":48,"searchDepth":49,"depth":49,"links":22842},[22843,22844,22845,22846,22847,22848,22849,22850,22851],{"id":22410,"depth":49,"text":22411},{"id":22438,"depth":49,"text":22439},{"id":22532,"depth":49,"text":22533},{"id":22557,"depth":49,"text":22558},{"id":22624,"depth":49,"text":22625},{"id":22691,"depth":49,"text":22692},{"id":22717,"depth":49,"text":22718},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":22853,"status":22854},"17.5 — Abstract Classes and Methods","new — authored lesson (added in the 2026-09 content audit; no CSA counterpart)","\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F5-abstract-classes-and-methods",{"title":22402,"description":48},"shockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.5-abstract-classes-and-methods","1w7tj257onowvGnT3MdUgL0WybE4fra0OMNWiwIGRZA",{"id":22860,"title":22861,"body":22862,"description":48,"extension":51,"meta":23225,"navigation":55,"path":23227,"seo":23228,"stem":23229,"__hash__":23230},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F18.1-overriding-methods.md","Overriding Methods",{"type":8,"value":22863,"toc":23217},[22864,22867,22871,22888,22902,22954,22968,22972,22990,23030,23042,23046,23055,23104,23108,23137,23139,23172,23174,23204,23215],[11,22865,22861],{"id":22866},"overriding-methods",[69,22868,22870],{"id":22869},"what-overriding-is","What Overriding Is",[15,22872,22873,22874,22876,22877,22880,22881,22883,22884,22887],{},"A subclass inherits all its superclass's ",[95,22875,175],{}," methods unchanged — but it can also ",[25,22878,22879],{},"override"," one, replacing the inherited version with its own. Overriding requires matching the superclass method's ",[25,22882,3356],{}," — the same name and the same parameter list — with a return type that is the same as the superclass method's, or a subtype of it (called a ",[494,22885,22886],{},"covariant"," return type).",[15,22889,22890,22892,22893,22895,22896,845,22899,22901],{},[95,22891,20446],{}," (Lesson 17.1) has a general-purpose ",[95,22894,20442],{}," that only logs a message: ",[95,22897,22898],{},"public void stop() { log(\"stopped\"); }",[95,22900,9838],{}," overrides it with a version specific to its own rollers:",[104,22903,22905],{"className":106,"code":22904,"language":108,"meta":48,"style":48},"public class Intake extends RobotPart\n{\n    public Intake(String name) { super(name); }\n\n    @Override\n    public void stop()\n    {\n        \u002F\u002F Intake's own, specific version replaces RobotPart's\n        log(\"rollers off, game piece held\");\n    }\n}\n",[95,22906,22907,22911,22915,22919,22923,22927,22932,22936,22941,22946,22950],{"__ignoreMap":48},[112,22908,22909],{"class":114,"line":115},[112,22910,20502],{},[112,22912,22913],{"class":114,"line":49},[112,22914,123],{},[112,22916,22917],{"class":114,"line":126},[112,22918,20516],{},[112,22920,22921],{"class":114,"line":132},[112,22922,907],{"emptyLinePlaceholder":55},[112,22924,22925],{"class":114,"line":138},[112,22926,21735],{},[112,22928,22929],{"class":114,"line":144},[112,22930,22931],{},"    public void stop()\n",[112,22933,22934],{"class":114,"line":150},[112,22935,135],{},[112,22937,22938],{"class":114,"line":2276},[112,22939,22940],{},"        \u002F\u002F Intake's own, specific version replaces RobotPart's\n",[112,22942,22943],{"class":114,"line":2282},[112,22944,22945],{},"        log(\"rollers off, game piece held\");\n",[112,22947,22948],{"class":114,"line":2288},[112,22949,147],{},[112,22951,22952],{"class":114,"line":5760},[112,22953,153],{},[15,22955,22956,22958,22959,3181,22962,22964,22965,22967],{},[95,22957,10343],{}," is optional but always worth writing — it tells the compiler \"I intend to override an inherited method here,\" and the compiler then checks the signature truly matches. Without it, a typo in the method name (",[95,22960,22961],{},"stopp()",[95,22963,20442],{},") would silently create a brand-new, unrelated method instead of overriding anything — with ",[95,22966,10343],{},", that same typo becomes a compile error instead of a bug that only shows up at runtime.",[69,22969,22971],{"id":22970},"overriding-vs-overloading","Overriding vs. Overloading",[15,22973,22974,22975,22978,22979,22981,22982,22984,22985,22987,22988,738],{},"These sound similar but are entirely different things. ",[25,22976,22977],{},"Overriding"," means the same signature, in a subclass, replacing the superclass's version. ",[25,22980,3421],{}," means the same method ",[494,22983,9621],{}," with a different parameter list — either in the same class, or added by a subclass alongside the method it inherited. Here ",[95,22986,20446],{}," overloads its own ",[95,22989,20595],{},[104,22991,22993],{"className":106,"code":22992,"language":108,"meta":48,"style":48},"public class RobotPart\n{\n    \u002F\u002F ...name field, constructor, getName(), and stop() as in Lesson 17.1\n    public void log(String msg) { System.out.println(\"[\" + name + \"] \" + msg); }\n\n    \u002F\u002F overload — same name, different parameters\n    public void log(String msg, int code) { log(msg + \" (code \" + code + \")\"); }\n}\n",[95,22994,22995,22999,23003,23008,23012,23016,23021,23026],{"__ignoreMap":48},[112,22996,22997],{"class":114,"line":115},[112,22998,20457],{},[112,23000,23001],{"class":114,"line":49},[112,23002,123],{},[112,23004,23005],{"class":114,"line":126},[112,23006,23007],{},"    \u002F\u002F ...name field, constructor, getName(), and stop() as in Lesson 17.1\n",[112,23009,23010],{"class":114,"line":132},[112,23011,20484],{},[112,23013,23014],{"class":114,"line":138},[112,23015,907],{"emptyLinePlaceholder":55},[112,23017,23018],{"class":114,"line":144},[112,23019,23020],{},"    \u002F\u002F overload — same name, different parameters\n",[112,23022,23023],{"class":114,"line":150},[112,23024,23025],{},"    public void log(String msg, int code) { log(msg + \" (code \" + code + \")\"); }\n",[112,23027,23028],{"class":114,"line":2276},[112,23029,153],{},[15,23031,23032,23033,23035,23036,23038,23039,23041],{},"Two methods can never differ ",[494,23034,9943],{}," in return type — that alone doesn't count as a valid overload. And a subclass method with the same name and parameters as an inherited one, but an incompatible return type (for example ",[95,23037,603],{}," where the superclass method returns ",[95,23040,183],{},"), isn't an override either: it's a compile error.",[69,23043,23045],{"id":23044},"inherited-getters-and-setters-still-apply","Inherited Getters and Setters Still Apply",[15,23047,23048,23049,23051,23052,23054],{},"A subclass gets its superclass's public getters and setters automatically, and — since the superclass's fields are ",[95,23050,9905],{}," — those accessor methods remain the only way to reach them, even from the subclass itself (unless the superclass marks a field ",[95,23053,16738],{},", Lesson 17.2):",[104,23056,23058],{"className":106,"code":23057,"language":108,"meta":48,"style":48},"public class Intake extends RobotPart\n{\n    \u002F\u002F ...constructor and stop() as above\n\n    public void announce()\n    {\n        \u002F\u002F must go through the inherited getter — direct access to name isn't legal here\n        System.out.println(\"Intake online: \" + getName());\n    }\n}\n",[95,23059,23060,23064,23068,23073,23077,23082,23086,23091,23096,23100],{"__ignoreMap":48},[112,23061,23062],{"class":114,"line":115},[112,23063,20502],{},[112,23065,23066],{"class":114,"line":49},[112,23067,123],{},[112,23069,23070],{"class":114,"line":126},[112,23071,23072],{},"    \u002F\u002F ...constructor and stop() as above\n",[112,23074,23075],{"class":114,"line":132},[112,23076,907],{"emptyLinePlaceholder":55},[112,23078,23079],{"class":114,"line":138},[112,23080,23081],{},"    public void announce()\n",[112,23083,23084],{"class":114,"line":144},[112,23085,135],{},[112,23087,23088],{"class":114,"line":150},[112,23089,23090],{},"        \u002F\u002F must go through the inherited getter — direct access to name isn't legal here\n",[112,23092,23093],{"class":114,"line":2276},[112,23094,23095],{},"        System.out.println(\"Intake online: \" + getName());\n",[112,23097,23098],{"class":114,"line":2282},[112,23099,147],{},[112,23101,23102],{"class":114,"line":2288},[112,23103,153],{},[69,23105,23107],{"id":23106},"preventing-an-override-final","Preventing an Override: final",[15,23109,23110,23111,23113,23114,23116,23117,23120,23121,23123,23124,23126,23127,23129,23130,23133,23134,23136],{},"A method declared ",[95,23112,381],{}," can't be overridden: if ",[95,23115,20446],{}," declared ",[95,23118,23119],{},"public final String getName()",", any subclass that tried to write its own ",[95,23122,21059],{}," would fail to compile. A whole class can be ",[95,23125,381],{}," too, which means it can't be extended at all — ",[95,23128,361],{}," is one, so ",[95,23131,23132],{},"class MyString extends String"," doesn't compile. Lesson 23.1 covers ",[95,23135,381],{}," in full.",[69,23138,462],{"id":461},[19,23140,23141,23147,23154],{},[22,23142,23143,23146],{},[25,23144,23145],{},"Mismatching the signature and expecting an override anyway."," Changing the parameter list (even by adding one parameter) makes it an overload, not an override — the original method is still inherited unchanged, sitting alongside the new one.",[22,23148,23149,23153],{},[25,23150,4719,23151,79],{},[95,23152,10343],{}," Skipping it doesn't break anything when the signature is right, but it removes the compiler's safety net against typos — always include it when overriding.",[22,23155,23156,476,23159,23162,23163,20265,23166,23168,23169,23171],{},[25,23157,23158],{},"Changing only the return type.",[95,23160,23161],{},"public int stop()"," next to a superclass's ",[95,23164,23165],{},"public void stop()",[95,23167,603],{}," isn't compatible with ",[95,23170,183],{},", so it's neither a valid override nor a valid overload.",[69,23173,501],{"id":500},[19,23175,23176,23179,23184,23187,23190,23193],{},[22,23177,23178],{},"Overriding replaces an inherited method with a new version in the subclass: same name and parameter list, with a return type that's the same or a subtype (covariant).",[22,23180,23181,23183],{},[95,23182,10343],{}," isn't required, but should always be used — it turns a signature typo into a compile error instead of a silent, unrelated new method.",[22,23185,23186],{},"Overloading is different: same name, different parameter list — in the same class, or added in a subclass — not to be confused with overriding.",[22,23188,23189],{},"Two methods can never differ only in return type.",[22,23191,23192],{},"Inherited getters\u002Fsetters remain the only way to reach a superclass's private fields, even from within the subclass.",[22,23194,405,23195,23197,23198,23200,23201,23203],{},[95,23196,381],{}," method can't be overridden, and a ",[95,23199,381],{}," class (like ",[95,23202,361],{},") can't be extended.",[15,23205,544,23206,548,23208,23211,23212,23214],{},[95,23207,547],{},[95,23209,23210],{},"unit-5-inheritance-optional\u002F5.03-overriding-methods.md"," (CSA 5.3)\n",[25,23213,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 5 (\"Polymorphism: Many Forms\")",[554,23216,556],{},{"title":48,"searchDepth":49,"depth":49,"links":23218},[23219,23220,23221,23222,23223,23224],{"id":22869,"depth":49,"text":22870},{"id":22970,"depth":49,"text":22971},{"id":23044,"depth":49,"text":23045},{"id":23106,"depth":49,"text":23107},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":23226,"status":570},"18.1 — Overriding Methods (CSA 5.3)","\u002Fshockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F1-overriding-methods",{"title":22861,"description":48},"shockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F18.1-overriding-methods","C1Dyfi3bqDyzh0_bC4MXoWI59oBrRmqr-8VA5MjPNRY",{"id":23232,"title":23233,"body":23234,"description":48,"extension":51,"meta":23554,"navigation":55,"path":23556,"seo":23557,"stem":23558,"__hash__":23559},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F18.2-super-keyword.md","super Keyword",{"type":8,"value":23235,"toc":23547},[23236,23239,23243,23261,23314,23324,23343,23347,23350,23380,23411,23415,23468,23470,23510,23512,23535,23545],[11,23237,23233],{"id":23238},"super-keyword",[69,23240,23242],{"id":23241},"extending-not-just-replacing-inherited-behavior","Extending, Not Just Replacing, Inherited Behavior",[15,23244,23245,23246,23249,23250,23252,23253,23255,23256,14935,23258,23260],{},"Overriding a method (Lesson 18.1) completely replaces the superclass's version — but often a subclass wants to run the ",[494,23247,23248],{},"original"," logic too, and add something on top of it, rather than throwing it away entirely. ",[95,23251,21757],{}," calls the superclass's version of a method explicitly, from inside an override. A ",[95,23254,11675],{}," should still do everything ",[95,23257,20446],{},[95,23259,20442],{}," does (Lesson 17.1), and then engage its brake:",[104,23262,23264],{"className":106,"code":23263,"language":108,"meta":48,"style":48},"public class Climber extends RobotPart\n{\n    public Climber(String name) { super(name); }\n\n    @Override\n    public void stop()\n    {\n        super.stop();            \u002F\u002F runs RobotPart's stop() first\n        log(\"brake engaged\");    \u002F\u002F then adds Climber's own step\n    }\n}\n",[95,23265,23266,23271,23275,23280,23284,23288,23292,23296,23301,23306,23310],{"__ignoreMap":48},[112,23267,23268],{"class":114,"line":115},[112,23269,23270],{},"public class Climber extends RobotPart\n",[112,23272,23273],{"class":114,"line":49},[112,23274,123],{},[112,23276,23277],{"class":114,"line":126},[112,23278,23279],{},"    public Climber(String name) { super(name); }\n",[112,23281,23282],{"class":114,"line":132},[112,23283,907],{"emptyLinePlaceholder":55},[112,23285,23286],{"class":114,"line":138},[112,23287,21735],{},[112,23289,23290],{"class":114,"line":144},[112,23291,22931],{},[112,23293,23294],{"class":114,"line":150},[112,23295,135],{},[112,23297,23298],{"class":114,"line":2276},[112,23299,23300],{},"        super.stop();            \u002F\u002F runs RobotPart's stop() first\n",[112,23302,23303],{"class":114,"line":2282},[112,23304,23305],{},"        log(\"brake engaged\");    \u002F\u002F then adds Climber's own step\n",[112,23307,23308],{"class":114,"line":2288},[112,23309,147],{},[112,23311,23312],{"class":114,"line":5760},[112,23313,153],{},[15,23315,23316,23317,23320,23321,23323],{},"You've seen this once already: Lesson 17.4's ",[95,23318,23319],{},"Intake.toString()"," called ",[95,23322,21753],{}," and added to its result.",[15,23325,23326,23328,23329,23331,23332,23334,23335,23331,23337,23339,23340,23342],{},[95,23327,20865],{}," has two distinct uses: ",[95,23330,20858],{},", which calls a superclass ",[494,23333,4566],{}," from inside a constructor (Lesson 17.2); and ",[95,23336,21757],{},[494,23338,3339],{}," from anywhere inside a subclass method body. Where ",[95,23341,20858],{}," may go depends on the Java version: on Java 25, only statements that don't use the object being built may come before it; on Java 17, it must be the constructor's very first statement.",[69,23344,23346],{"id":23345},"how-method-lookup-actually-works","How Method Lookup Actually Works",[15,23348,23349],{},"Every object remembers the actual class it was created with. A method call on that object starts looking there first; if the method isn't found in that exact class, Java searches up the chain — parent, grandparent, and so on — until it finds a match (which it always will, or the code wouldn't have compiled in the first place).",[104,23351,23353],{"className":106,"code":23352,"language":108,"meta":48,"style":48},"RobotPart part = new Climber(\"Left Climber\");\npart.stop();\n\u002F\u002F prints:\n\u002F\u002F [Left Climber] stopped\n\u002F\u002F [Left Climber] brake engaged\n",[95,23354,23355,23360,23365,23370,23375],{"__ignoreMap":48},[112,23356,23357],{"class":114,"line":115},[112,23358,23359],{},"RobotPart part = new Climber(\"Left Climber\");\n",[112,23361,23362],{"class":114,"line":49},[112,23363,23364],{},"part.stop();\n",[112,23366,23367],{"class":114,"line":126},[112,23368,23369],{},"\u002F\u002F prints:\n",[112,23371,23372],{"class":114,"line":132},[112,23373,23374],{},"\u002F\u002F [Left Climber] stopped\n",[112,23376,23377],{"class":114,"line":138},[112,23378,23379],{},"\u002F\u002F [Left Climber] brake engaged\n",[15,23381,13153,23382,23385,23386,23389,23390,23392,23393,23396,23397,23400,23401,23404,23405,23407,23408,79],{},[95,23383,23384],{},"part.stop()"," starts in ",[95,23387,23388],{},"Climber.stop()",", because the object is a ",[95,23391,11675],{},"; when execution reaches ",[95,23394,23395],{},"super.stop()",", it runs ",[95,23398,23399],{},"RobotPart.stop()",", which logs ",[95,23402,23403],{},"stopped",", then returns to finish the rest of ",[95,23406,23388],{},"'s body, which logs ",[95,23409,23410],{},"brake engaged",[69,23412,23414],{"id":23413},"a-subtlety-super-only-affects-the-one-call-its-written-on","A Subtlety: super Only Affects the One Call It's Written On",[15,23416,23417,23420,23421,23424,23425,23427,23428,23430,23431,14935,23433,23435,23436,7519,23439,23441,23442,23444,23445,23448,23449,23451,23452,23454,23455,476,23460,959,23462,23464,23465,23467],{},[95,23418,23419],{},"super.someMethod()"," only changes which version of ",[494,23422,23423],{},"that specific call"," runs — it doesn't change how any other method call inside the same method resolves. Any call made without ",[95,23426,20865],{}," (an unqualified call, or one through ",[95,23429,3132],{},") still dispatches based on the object's actual runtime type, even from inside inherited code. ",[95,23432,20446],{},[95,23434,20442],{}," calls ",[95,23437,23438],{},"log(...)",[95,23440,11675],{}," also overrode ",[95,23443,20595],{},", then the ",[95,23446,23447],{},"log(\"stopped\")"," call inside ",[95,23450,23399],{}," — reached through ",[95,23453,23395],{}," — would run ",[494,23456,23457,23459],{},[95,23458,11675],{},"'s",[95,23461,20595],{},[95,23463,20446],{},"'s. The override \"wins\" everywhere except the one spot ",[95,23466,20865],{}," explicitly overrides it.",[69,23469,462],{"id":461},[19,23471,23472,23485,23499],{},[22,23473,23474,23482,23483,21005],{},[25,23475,4719,23476,23478,23479,23481],{},[95,23477,21757],{}," must be called explicitly — it never happens automatically the way ",[95,23480,20979],{}," does for constructors."," Overriding a method completely discards the superclass's version unless the override calls ",[95,23484,21757],{},[22,23486,23487,476,23493,23495,23496,23498],{},[25,23488,23489,23490,23492],{},"Confusing the two ",[95,23491,20865],{}," forms.",[95,23494,20858],{}," (no method name) only ever calls a constructor, and only from inside a constructor — first on Java 17, and after only object-free statements on Java 25; ",[95,23497,21757],{}," calls a named method, and can appear anywhere inside a method body.",[22,23500,23501,23506,23507,23509],{},[25,23502,1608,23503,23505],{},[95,23504,21757],{}," changes every call inside that method to use the superclass's versions."," It only affects the one call written with ",[95,23508,20865],{}," — any other method call inside that same superclass method still resolves against the object's real runtime type.",[69,23511,501],{"id":500},[19,23513,23514,23519,23522,23530],{},[22,23515,23516,23518],{},[95,23517,21757],{}," explicitly calls the superclass's version of a method, letting a subclass extend rather than fully replace inherited behavior.",[22,23520,23521],{},"Method lookup starts at the object's actual class and searches upward through its ancestors until a match is found.",[22,23523,23524,23526,23527,23529],{},[95,23525,20858],{}," (constructors) and ",[95,23528,21757],{}," (methods) are two distinct, unrelated uses of the same keyword.",[22,23531,405,23532,23534],{},[95,23533,21757],{}," call only affects that one call — any other unqualified method call inside still dispatches to the object's real runtime type.",[15,23536,544,23537,548,23539,23542,23543,23214],{},[95,23538,547],{},[95,23540,23541],{},"unit-5-inheritance-optional\u002F5.04-super-keyword.md"," (CSA 5.4)\n",[25,23544,5351],{},[554,23546,556],{},{"title":48,"searchDepth":49,"depth":49,"links":23548},[23549,23550,23551,23552,23553],{"id":23241,"depth":49,"text":23242},{"id":23345,"depth":49,"text":23346},{"id":23413,"depth":49,"text":23414},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":23555,"status":15483},"18.2 — super Keyword (CSA 5.4)","\u002Fshockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F2-super-keyword",{"title":23233,"description":48},"shockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F18.2-super-keyword","uaw6vBJAZtWSGWurd5sCi6MyKqeS1a6JNYkblVFXj3A",{"id":23561,"title":23562,"body":23563,"description":48,"extension":51,"meta":24089,"navigation":55,"path":24091,"seo":24092,"stem":24093,"__hash__":24094},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F18.3-polymorphism.md","Polymorphism",{"type":8,"value":23564,"toc":24080},[23565,23567,23571,23593,23621,23625,23638,23658,23665,23685,23708,23712,23722,23746,23766,23794,23798,23827,23854,23868,23888,23896,23916,23938,23961,23964,23968,23974,23976,24029,24031,24064,24078],[11,23566,23562],{"id":21533},[69,23568,23570],{"id":23569},"many-forms-one-piece-of-code","Many Forms, One Piece of Code",[15,23572,23573,23575,23576,23579,23580,23583,23584,23586,23587,21559,23589,23592],{},[25,23574,23562],{}," (\"many forms\") means the method that actually runs at runtime depends on the object's ",[494,23577,23578],{},"actual"," type — not the type its variable was declared with. This is the concrete payoff of everything Ch.17 and Lessons 18.1-18.2 built toward. Real WPILib code relies on it constantly: WPILib's ",[95,23581,23582],{},"MotorController"," type (in ",[95,23585,22702],{},") describes what every motor controller can do, and code written against it calls the same method on any motor controller without caring which class it actually is. (",[95,23588,23582],{},[494,23590,23591],{},"interface",", a kind of type Ch.19 covers in full — for now, treat it like a superclass shared by every WPILib motor controller class.)",[104,23594,23596],{"className":106,"code":23595,"language":108,"meta":48,"style":48},"public void driveForward(MotorController controller)\n{\n    \u002F\u002F works the same whichever motor controller class is passed in\n    controller.setThrottle(0.5);\n}\n",[95,23597,23598,23603,23607,23612,23617],{"__ignoreMap":48},[112,23599,23600],{"class":114,"line":115},[112,23601,23602],{},"public void driveForward(MotorController controller)\n",[112,23604,23605],{"class":114,"line":49},[112,23606,123],{},[112,23608,23609],{"class":114,"line":126},[112,23610,23611],{},"    \u002F\u002F works the same whichever motor controller class is passed in\n",[112,23613,23614],{"class":114,"line":132},[112,23615,23616],{},"    controller.setThrottle(0.5);\n",[112,23618,23619],{"class":114,"line":138},[112,23620,153],{},[69,23622,23624],{"id":23623},"declared-type-vs-actual-type","Declared Type vs. Actual Type",[15,23626,23627,23628,23631,23632,23635,23636,738],{},"Every variable has two types that matter: its ",[25,23629,23630],{},"declared (compile-time) type"," — what it's written as in the code — and its ",[25,23633,23634],{},"actual (runtime) type"," — the real class that was actually constructed with ",[95,23637,2504],{},[104,23639,23641],{"className":106,"code":23640,"language":108,"meta":48,"style":48},"RobotPart part = new Intake(\"Front Intake\");\n\u002F\u002F declared type: RobotPart\n\u002F\u002F actual type:   Intake\n",[95,23642,23643,23648,23653],{"__ignoreMap":48},[112,23644,23645],{"class":114,"line":115},[112,23646,23647],{},"RobotPart part = new Intake(\"Front Intake\");\n",[112,23649,23650],{"class":114,"line":49},[112,23651,23652],{},"\u002F\u002F declared type: RobotPart\n",[112,23654,23655],{"class":114,"line":126},[112,23656,23657],{},"\u002F\u002F actual type:   Intake\n",[15,23659,23660,23661,23664],{},"The compiler only ever checks the ",[25,23662,23663],{},"declared"," type when deciding whether code compiles — it verifies that whatever method you're calling actually exists on that declared type (or an ancestor of it):",[104,23666,23668],{"className":106,"code":23667,"language":108,"meta":48,"style":48},"Object message = new String(\"hi\");\n\u002F\u002F COMPILE ERROR — Object has no indexOf method, even though String does\nmessage.indexOf(\"h\");\n",[95,23669,23670,23675,23680],{"__ignoreMap":48},[112,23671,23672],{"class":114,"line":115},[112,23673,23674],{},"Object message = new String(\"hi\");\n",[112,23676,23677],{"class":114,"line":49},[112,23678,23679],{},"\u002F\u002F COMPILE ERROR — Object has no indexOf method, even though String does\n",[112,23681,23682],{"class":114,"line":126},[112,23683,23684],{},"message.indexOf(\"h\");\n",[15,23686,23687,23688,23690,23691,23693,23694,14935,23697,23699,23700,23702,23703,23705,23706,10993],{},"Even though the real object here is a ",[95,23689,361],{}," (which absolutely does have ",[95,23692,9542],{},"), the compiler only looks at ",[95,23695,23696],{},"message",[494,23698,23663],{}," type, ",[95,23701,19753],{}," — and refuses to compile, since ",[95,23704,19753],{}," never promises an ",[95,23707,9542],{},[69,23709,23711],{"id":23710},"runtime-dispatch-the-actual-type-decides-which-version-runs","Runtime Dispatch: The Actual Type Decides Which Version Runs",[15,23713,23714,23715,23718,23719,23721],{},"Once code ",[494,23716,23717],{},"does"," compile, the JVM decides which overridden version of a method actually executes by looking at the object's real, actual type — starting there and searching upward through its superclasses if needed (same lookup process as Lesson 18.2's ",[95,23720,20865],{},"):",[104,23723,23725],{"className":106,"code":23724,"language":108,"meta":48,"style":48},"RobotPart part = new Intake(\"Front Intake\");  \u002F\u002F declared RobotPart, actually an Intake\n\u002F\u002F the compiler only confirms RobotPart HAS a stop() method —\n\u002F\u002F but Intake's own override (Lesson 18.1) is what actually runs\npart.stop();\n",[95,23726,23727,23732,23737,23742],{"__ignoreMap":48},[112,23728,23729],{"class":114,"line":115},[112,23730,23731],{},"RobotPart part = new Intake(\"Front Intake\");  \u002F\u002F declared RobotPart, actually an Intake\n",[112,23733,23734],{"class":114,"line":49},[112,23735,23736],{},"\u002F\u002F the compiler only confirms RobotPart HAS a stop() method —\n",[112,23738,23739],{"class":114,"line":126},[112,23740,23741],{},"\u002F\u002F but Intake's own override (Lesson 18.1) is what actually runs\n",[112,23743,23744],{"class":114,"line":132},[112,23745,23364],{},[15,23747,23748,23749,176,23751,23753,23754,23757,23758,23760,23761,176,23763,23765],{},"This is exactly what makes the earlier ",[95,23750,21570],{},[95,23752,21492],{}," examples (Lesson 17.3) genuinely useful — a single loop calling ",[95,23755,23756],{},"p.stop()"," on each element automatically runs whichever subclass's own ",[95,23759,20442],{}," actually applies, without an ",[95,23762,2179],{},[95,23764,5104],{}," chain checking each one's specific type:",[104,23767,23769],{"className":106,"code":23768,"language":108,"meta":48,"style":48},"for (RobotPart p : allParts)\n{\n    \u002F\u002F Intake's stop(), Climber's stop(), Shooter's stop() — whichever fits each object\n    p.stop();\n}\n",[95,23770,23771,23776,23780,23785,23790],{"__ignoreMap":48},[112,23772,23773],{"class":114,"line":115},[112,23774,23775],{},"for (RobotPart p : allParts)\n",[112,23777,23778],{"class":114,"line":49},[112,23779,123],{},[112,23781,23782],{"class":114,"line":126},[112,23783,23784],{},"    \u002F\u002F Intake's stop(), Climber's stop(), Shooter's stop() — whichever fits each object\n",[112,23786,23787],{"class":114,"line":132},[112,23788,23789],{},"    p.stop();\n",[112,23791,23792],{"class":114,"line":138},[112,23793,153],{},[69,23795,23797],{"id":23796},"casting-back-down","Casting Back Down",[15,23799,23800,23801,6439,23803,23805,23806,23809,23810,4875,23812,23814,23815,23818,23819,21559,23821,23823,23824,23826],{},"Storing an ",[95,23802,9838],{},[95,23804,20446],{}," variable is an ",[25,23807,23808],{},"upcast"," — from a subclass type up to a superclass type — and it happens automatically, because every ",[95,23811,9838],{},[95,23813,20446],{},". Going the other way, a ",[25,23816,23817],{},"downcast",", needs an explicit cast, because not every ",[95,23820,20446],{},[95,23822,9838],{},". Suppose ",[95,23825,9838],{}," adds a method of its own, a getter for the field from Lesson 17.2:",[104,23828,23830],{"className":106,"code":23829,"language":108,"meta":48,"style":48},"public class Intake extends RobotPart\n{\n    \u002F\u002F ...hasGamePiece field, constructor, and stop() as in Lessons 17.2 and 18.1\n    public boolean hasGamePiece() { return hasGamePiece; }\n}\n",[95,23831,23832,23836,23840,23845,23850],{"__ignoreMap":48},[112,23833,23834],{"class":114,"line":115},[112,23835,20502],{},[112,23837,23838],{"class":114,"line":49},[112,23839,123],{},[112,23841,23842],{"class":114,"line":126},[112,23843,23844],{},"    \u002F\u002F ...hasGamePiece field, constructor, and stop() as in Lessons 17.2 and 18.1\n",[112,23846,23847],{"class":114,"line":132},[112,23848,23849],{},"    public boolean hasGamePiece() { return hasGamePiece; }\n",[112,23851,23852],{"class":114,"line":138},[112,23853,153],{},[15,23855,23856,23859,23860,20299,23863,23865,23866,738],{},[95,23857,23858],{},"part.hasGamePiece()"," doesn't compile, since ",[95,23861,23862],{},"part",[95,23864,20446],{},". A cast tells the compiler to treat the reference as an ",[95,23867,9838],{},[104,23869,23871],{"className":106,"code":23870,"language":108,"meta":48,"style":48},"RobotPart part = new Intake(\"Front Intake\");  \u002F\u002F upcast: automatic\nIntake intake = (Intake) part;                \u002F\u002F downcast: needs a cast\nSystem.out.println(intake.hasGamePiece());\n",[95,23872,23873,23878,23883],{"__ignoreMap":48},[112,23874,23875],{"class":114,"line":115},[112,23876,23877],{},"RobotPart part = new Intake(\"Front Intake\");  \u002F\u002F upcast: automatic\n",[112,23879,23880],{"class":114,"line":49},[112,23881,23882],{},"Intake intake = (Intake) part;                \u002F\u002F downcast: needs a cast\n",[112,23884,23885],{"class":114,"line":126},[112,23886,23887],{},"System.out.println(intake.hasGamePiece());\n",[15,23889,23890,23891,23893,23894,738],{},"The cast is checked when the program runs. If the object isn't really an ",[95,23892,9838],{},", it throws a ",[95,23895,19547],{},[104,23897,23899],{"className":106,"code":23898,"language":108,"meta":48,"style":48},"RobotPart other = new Climber(\"Left Climber\");\n\u002F\u002F compiles, but throws ClassCastException when it runs: a Climber isn't an Intake\nIntake wrong = (Intake) other;\n",[95,23900,23901,23906,23911],{"__ignoreMap":48},[112,23902,23903],{"class":114,"line":115},[112,23904,23905],{},"RobotPart other = new Climber(\"Left Climber\");\n",[112,23907,23908],{"class":114,"line":49},[112,23909,23910],{},"\u002F\u002F compiles, but throws ClassCastException when it runs: a Climber isn't an Intake\n",[112,23912,23913],{"class":114,"line":126},[112,23914,23915],{},"Intake wrong = (Intake) other;\n",[15,23917,23918,23919,23921,23922,7519,23924,23926,23927,23929,23930,23932,23933,23935,23936,738],{},"So check with ",[95,23920,21889],{}," first. Since Java 16, the check and the cast combine into one step with a ",[494,23923,21997],{},[95,23925,23862],{}," refers to an ",[95,23928,9838],{},", the new variable ",[95,23931,5244],{}," is that same object, already typed as ",[95,23934,9838],{},", inside the ",[95,23937,2179],{},[104,23939,23941],{"className":106,"code":23940,"language":108,"meta":48,"style":48},"if (part instanceof Intake i)\n{\n    System.out.println(\"Holding a piece: \" + i.hasGamePiece());\n}\n",[95,23942,23943,23948,23952,23957],{"__ignoreMap":48},[112,23944,23945],{"class":114,"line":115},[112,23946,23947],{},"if (part instanceof Intake i)\n",[112,23949,23950],{"class":114,"line":49},[112,23951,123],{},[112,23953,23954],{"class":114,"line":126},[112,23955,23956],{},"    System.out.println(\"Holding a piece: \" + i.hasGamePiece());\n",[112,23958,23959],{"class":114,"line":132},[112,23960,153],{},[15,23962,23963],{},"Needing lots of downcasts is usually a sign the method belongs in the superclass as an override — polymorphism exists so most code never has to ask \"which kind is this?\"",[69,23965,23967],{"id":23966},"static-methods-dont-get-this","Static Methods Don't Get This",[15,23969,23970,23971,23973],{},"Polymorphic dispatch only applies to regular (instance) methods. A ",[95,23972,179],{}," method call is resolved entirely by the declared type, at compile time — there's no runtime lookup involved at all, since static methods belong to the class itself, not to any particular object.",[69,23975,462],{"id":461},[19,23977,23978,23988,23998,24023],{},[22,23979,23980,23983,23984,23987],{},[25,23981,23982],{},"Assuming the compiler checks the actual type."," It never does — ",[95,23985,23986],{},"message.indexOf(\"h\")"," fails to compile even when the real object genuinely has that method, because the compiler only ever consults the declared type.",[22,23989,23990,23993,23994,23997],{},[25,23991,23992],{},"Forgetting that runtime dispatch is what actually decides which override runs."," The declared type only gates ",[494,23995,23996],{},"whether the code compiles"," — which specific version executes is always decided by the real, actual object type.",[22,23999,24000,476,24003,24006,24007,24009,24010,24012,24013,24015,24016,24018,24019,24022],{},[25,24001,24002],{},"Downcasting without checking.",[95,24004,24005],{},"(Intake) part"," compiles whenever ",[95,24008,23862],{}," could be an ",[95,24011,9838],{},", but throws ",[95,24014,19547],{}," at runtime if it isn't — guard it with ",[95,24017,21889],{},", or use the ",[95,24020,24021],{},"part instanceof Intake i"," pattern.",[22,24024,24025,24028],{},[25,24026,24027],{},"Expecting polymorphism to apply to static methods."," Static method calls are resolved by declared type alone, with no runtime dispatch — they don't participate in overriding the way instance methods do.",[69,24030,501],{"id":500},[19,24032,24033,24036,24039,24052,24061],{},[22,24034,24035],{},"Polymorphism means the method that runs depends on an object's actual runtime type, not its variable's declared type.",[22,24037,24038],{},"The compiler only checks the declared type for whether a method call is legal; the JVM decides which overridden version actually runs based on the real, actual type.",[22,24040,24041,24042,24044,24045,322,24047,322,24049,24051],{},"This is why a ",[95,24043,20446],{},"-typed array or method parameter can transparently work with ",[95,24046,9838],{},[95,24048,11675],{},[95,24050,20639],{},", or any other subclass — one piece of code, many possible real behaviors.",[22,24053,24054,24055,24057,24058,79],{},"Upcasts are automatic; downcasts need an explicit cast, can throw ",[95,24056,19547],{},", and are safest as ",[95,24059,24060],{},"if (x instanceof Intake i)",[22,24062,24063],{},"Static methods don't participate in this — they're resolved entirely by declared type, at compile time.",[15,24065,544,24066,548,24068,24071,24072,24074,24075,24077],{},[95,24067,547],{},[95,24069,24070],{},"unit-5-inheritance-optional\u002F5.06-polymorphism.md"," (CSA 5.6)\n",[25,24073,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 5 (\"Polymorphism: Many Forms\") — the deck's vendor motor classes are replaced here by WPILib's generic ",[95,24076,23582],{}," interface",[554,24079,556],{},{"title":48,"searchDepth":49,"depth":49,"links":24081},[24082,24083,24084,24085,24086,24087,24088],{"id":23569,"depth":49,"text":23570},{"id":23623,"depth":49,"text":23624},{"id":23710,"depth":49,"text":23711},{"id":23796,"depth":49,"text":23797},{"id":23966,"depth":49,"text":23967},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":24090,"status":570},"18.3 — Polymorphism (CSA 5.6)","\u002Fshockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F3-polymorphism",{"title":23562,"description":48},"shockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F18.3-polymorphism","-FrB-Ojd4DTl1DcixGURN4svBYAmWMgQ39cQpnTa5jw",{"id":24096,"title":24097,"body":24098,"description":48,"extension":51,"meta":24831,"navigation":55,"path":24833,"seo":24834,"stem":24835,"__hash__":24836},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch19-interfaces-as-contracts\u002F19-interfaces-as-contracts.md","Interfaces as Contracts",{"type":8,"value":24099,"toc":24818},[24100,24103,24107,24122,24150,24158,24198,24227,24231,24240,24263,24266,24270,24273,24301,24307,24311,24317,24352,24362,24366,24375,24420,24427,24431,24447,24499,24516,24523,24558,24573,24578,24585,24589,24611,24679,24681,24746,24748,24790,24816],[11,24101,24097],{"id":24102},"interfaces-as-contracts",[69,24104,24106],{"id":24105},"what-vs-how","What vs. How",[15,24108,1851,24109,24111,24112,24114,24115,24118,24119,24121],{},[25,24110,23591],{}," defines ",[494,24113,4416],{}," an object can do, without specifying ",[494,24116,24117],{},"how"," it does it. It's a \"contract\" — a set of method signatures any implementing class agrees to provide, with no implementation of its own for those methods (every one of those methods is ",[25,24120,22435],{},", Lesson 17.5's term for a signature with no body). This matters enormously in real engineering: it lets two groups write code against a shared agreement without either needing to know the other's internals — a hardware vendor and an application team can each build against the same interface independently, as long as both honor it.",[104,24123,24125],{"className":106,"code":24124,"language":108,"meta":48,"style":48},"public interface IntakeIO\n{\n    void updateInputs(IntakeInputs inputs);\n    void setVoltage(double volts);\n}\n",[95,24126,24127,24132,24136,24141,24146],{"__ignoreMap":48},[112,24128,24129],{"class":114,"line":115},[112,24130,24131],{},"public interface IntakeIO\n",[112,24133,24134],{"class":114,"line":49},[112,24135,123],{},[112,24137,24138],{"class":114,"line":126},[112,24139,24140],{},"    void updateInputs(IntakeInputs inputs);\n",[112,24142,24143],{"class":114,"line":132},[112,24144,24145],{},"    void setVoltage(double volts);\n",[112,24147,24148],{"class":114,"line":138},[112,24149,153],{},[15,24151,24152,24153,24155,24156,738],{},"Method signatures inside an interface have no body — just a semicolon, no braces. ",[95,24154,23591],{}," is the keyword; a class agrees to the contract with ",[95,24157,16808],{},[104,24159,24161],{"className":106,"code":24160,"language":108,"meta":48,"style":48},"public class RealIntakeIO implements IntakeIO\n{\n    @Override\n    public void updateInputs(IntakeInputs inputs) { \u002F* real sensor reads *\u002F }\n\n    @Override\n    public void setVoltage(double volts) { \u002F* real motor.setVoltage(volts) *\u002F }\n}\n",[95,24162,24163,24168,24172,24176,24181,24185,24189,24194],{"__ignoreMap":48},[112,24164,24165],{"class":114,"line":115},[112,24166,24167],{},"public class RealIntakeIO implements IntakeIO\n",[112,24169,24170],{"class":114,"line":49},[112,24171,123],{},[112,24173,24174],{"class":114,"line":126},[112,24175,21735],{},[112,24177,24178],{"class":114,"line":132},[112,24179,24180],{},"    public void updateInputs(IntakeInputs inputs) { \u002F* real sensor reads *\u002F }\n",[112,24182,24183],{"class":114,"line":138},[112,24184,907],{"emptyLinePlaceholder":55},[112,24186,24187],{"class":114,"line":144},[112,24188,21735],{},[112,24190,24191],{"class":114,"line":150},[112,24192,24193],{},"    public void setVoltage(double volts) { \u002F* real motor.setVoltage(volts) *\u002F }\n",[112,24195,24196],{"class":114,"line":2276},[112,24197,153],{},[15,24199,24200,24201,24203,24204,24206,24207,24210,24211,24213,24214,24216,24217,24220,24221,24224,24225,79],{},"A class implementing an interface must provide a real method body for ",[494,24202,21370],{}," method the interface declares (default and static methods excepted — see below) — or the class fails to compile. Every one of those methods is implicitly ",[95,24205,175],{},", even though ",[95,24208,24209],{},"IntakeIO"," never writes the word — an implementing method has to be written ",[95,24212,175],{}," too, or it doesn't compile: a ",[95,24215,9905],{}," or package-private ",[95,24218,24219],{},"updateInputs"," would be ",[494,24222,24223],{},"weakening"," access the interface already promised as ",[95,24226,175],{},[69,24228,24230],{"id":24229},"multiple-interfaces-one-superclass","Multiple Interfaces, One Superclass",[15,24232,24233,24234,24236,24237,24239],{},"Unlike ",[95,24235,16804],{}," (limited to exactly one superclass — Lesson 17.1), a class can ",[95,24238,16808],{}," as many interfaces as it needs:",[104,24241,24243],{"className":106,"code":24242,"language":108,"meta":48,"style":48},"public class Intake implements Stowable, Diagnosable\n{\n    \u002F\u002F must provide every method declared by BOTH Stowable and Diagnosable\n}\n",[95,24244,24245,24250,24254,24259],{"__ignoreMap":48},[112,24246,24247],{"class":114,"line":115},[112,24248,24249],{},"public class Intake implements Stowable, Diagnosable\n",[112,24251,24252],{"class":114,"line":49},[112,24253,123],{},[112,24255,24256],{"class":114,"line":126},[112,24257,24258],{},"    \u002F\u002F must provide every method declared by BOTH Stowable and Diagnosable\n",[112,24260,24261],{"class":114,"line":132},[112,24262,153],{},[15,24264,24265],{},"This is one of the biggest practical differences between inheritance and interfaces: a class has one parent, but can honor any number of separate contracts at once.",[69,24267,24269],{"id":24268},"using-an-interface-as-a-type","Using an Interface as a Type",[15,24271,24272],{},"Just like a superclass (Lesson 17.3), an interface is a real reference type — a variable, parameter, array, or collection can be declared against an interface type, and hold any object whose class implements it:",[104,24274,24276],{"className":106,"code":24275,"language":108,"meta":48,"style":48},"public void configureIntake(IntakeIO io)\n{\n    \u002F\u002F works for RealIntakeIO, SimIntakeIO, or any other IntakeIO implementation\n    io.setVoltage(0.0);\n}\n",[95,24277,24278,24283,24287,24292,24297],{"__ignoreMap":48},[112,24279,24280],{"class":114,"line":115},[112,24281,24282],{},"public void configureIntake(IntakeIO io)\n",[112,24284,24285],{"class":114,"line":49},[112,24286,123],{},[112,24288,24289],{"class":114,"line":126},[112,24290,24291],{},"    \u002F\u002F works for RealIntakeIO, SimIntakeIO, or any other IntakeIO implementation\n",[112,24293,24294],{"class":114,"line":132},[112,24295,24296],{},"    io.setVoltage(0.0);\n",[112,24298,24299],{"class":114,"line":138},[112,24300,153],{},[15,24302,24303,24304,24306],{},"Code written against ",[95,24305,24209],{}," never needs to know or care which concrete implementation it's actually working with — real hardware, or a simulated stand-in (this exact pattern is the foundation of the IO-Layer Pattern, Ch.20).",[69,24308,24310],{"id":24309},"interface-constants","Interface Constants",[15,24312,24313,24314,24316],{},"A field declared inside an interface is implicitly ",[95,24315,11360],{}," — a shared constant, not per-object state (an interface has no object state of its own; it declares behavior, not fields to hold data):",[104,24318,24320],{"className":106,"code":24319,"language":108,"meta":48,"style":48},"public interface IntakeIO\n{\n    \u002F\u002F implicitly public static final — same as Lesson 7.4's constants\n    double MAX_VOLTS = 12.0;\n\n    void setVoltage(double volts);\n}\n",[95,24321,24322,24326,24330,24335,24340,24344,24348],{"__ignoreMap":48},[112,24323,24324],{"class":114,"line":115},[112,24325,24131],{},[112,24327,24328],{"class":114,"line":49},[112,24329,123],{},[112,24331,24332],{"class":114,"line":126},[112,24333,24334],{},"    \u002F\u002F implicitly public static final — same as Lesson 7.4's constants\n",[112,24336,24337],{"class":114,"line":132},[112,24338,24339],{},"    double MAX_VOLTS = 12.0;\n",[112,24341,24342],{"class":114,"line":138},[112,24343,907],{"emptyLinePlaceholder":55},[112,24345,24346],{"class":114,"line":144},[112,24347,24145],{},[112,24349,24350],{"class":114,"line":150},[112,24351,153],{},[15,24353,24354,24357,24358,24361],{},[95,24355,24356],{},"IntakeIO.MAX_VOLTS"," reads it directly off the interface name, exactly like any other ",[95,24359,24360],{},"static final"," constant (Lesson 7.4).",[69,24363,24365],{"id":24364},"one-interface-extending-another","One Interface Extending Another",[15,24367,24368,24369,24371,24372,24374],{},"An interface can ",[95,24370,16804],{}," another interface — not a class — to build a bigger contract out of a smaller one. Unlike a class, an interface can ",[95,24373,16804],{}," more than one interface at once, since there's no object state to conflict:",[104,24376,24378],{"className":106,"code":24377,"language":108,"meta":48,"style":48},"public interface Diagnosable\n{\n    String getStatus();\n}\n\npublic interface LoggingDiagnosable extends Diagnosable\n{\n    void logStatus(); \u002F\u002F LoggingDiagnosable now requires BOTH getStatus() and logStatus()\n}\n",[95,24379,24380,24385,24389,24394,24398,24402,24407,24411,24416],{"__ignoreMap":48},[112,24381,24382],{"class":114,"line":115},[112,24383,24384],{},"public interface Diagnosable\n",[112,24386,24387],{"class":114,"line":49},[112,24388,123],{},[112,24390,24391],{"class":114,"line":126},[112,24392,24393],{},"    String getStatus();\n",[112,24395,24396],{"class":114,"line":132},[112,24397,153],{},[112,24399,24400],{"class":114,"line":138},[112,24401,907],{"emptyLinePlaceholder":55},[112,24403,24404],{"class":114,"line":144},[112,24405,24406],{},"public interface LoggingDiagnosable extends Diagnosable\n",[112,24408,24409],{"class":114,"line":150},[112,24410,123],{},[112,24412,24413],{"class":114,"line":2276},[112,24414,24415],{},"    void logStatus(); \u002F\u002F LoggingDiagnosable now requires BOTH getStatus() and logStatus()\n",[112,24417,24418],{"class":114,"line":2282},[112,24419,153],{},[15,24421,24422,24423,24426],{},"A class that ",[95,24424,24425],{},"implements LoggingDiagnosable"," must provide both methods — the inherited one and the new one.",[69,24428,24430],{"id":24429},"default-and-static-methods","Default and Static Methods",[15,24432,24433,24434,537,24437,24439,24440,24443,24444,24446],{},"Normally every method in an interface is abstract (no body). ",[25,24435,24436],{},"Default",[25,24438,179],{}," methods are the exceptions. A ",[25,24441,24442],{},"default method"," provides a real implementation directly inside the interface, marked with the ",[95,24445,5816],{}," keyword, which implementing classes inherit automatically without being forced to write it themselves. The strongest default methods build on top of the interface's own abstract methods, adding real behavior without weakening the contract:",[104,24448,24450],{"className":106,"code":24449,"language":108,"meta":48,"style":48},"public interface IntakeIO\n{\n    void updateInputs(IntakeInputs inputs);\n    void setVoltage(double volts);\n\n    default void stop()\n    {\n        \u002F\u002F built on top of the abstract method every implementer must provide\n        setVoltage(0.0);\n    }\n}\n",[95,24451,24452,24456,24460,24464,24468,24472,24477,24481,24486,24491,24495],{"__ignoreMap":48},[112,24453,24454],{"class":114,"line":115},[112,24455,24131],{},[112,24457,24458],{"class":114,"line":49},[112,24459,123],{},[112,24461,24462],{"class":114,"line":126},[112,24463,24140],{},[112,24465,24466],{"class":114,"line":132},[112,24467,24145],{},[112,24469,24470],{"class":114,"line":138},[112,24471,907],{"emptyLinePlaceholder":55},[112,24473,24474],{"class":114,"line":144},[112,24475,24476],{},"    default void stop()\n",[112,24478,24479],{"class":114,"line":150},[112,24480,135],{},[112,24482,24483],{"class":114,"line":2276},[112,24484,24485],{},"        \u002F\u002F built on top of the abstract method every implementer must provide\n",[112,24487,24488],{"class":114,"line":2282},[112,24489,24490],{},"        setVoltage(0.0);\n",[112,24492,24493],{"class":114,"line":2288},[112,24494,147],{},[112,24496,24497],{"class":114,"line":5760},[112,24498,153],{},[15,24500,24501,537,24503,24506,24507,24509,24510,24512,24513,24515],{},[95,24502,24219],{},[95,24504,24505],{},"setVoltage"," are still required — every implementing class must provide them, or it won't compile. ",[95,24508,20442],{}," comes for free: it's written once, here, and every ",[95,24511,24209],{}," implementation inherits it automatically, calling that implementation's own ",[95,24514,24505],{},". This matters for a very practical reason: default methods let an interface add new methods later without breaking every class that already implements it — existing implementations simply inherit the default behavior rather than suddenly failing to compile. A class can still override a default method with its own real implementation, exactly like overriding an inherited method from a superclass (Lesson 18.1).",[15,24517,24518,24519,24522],{},"An interface can also declare ",[25,24520,24521],{},"static methods"," — utility methods associated with the interface itself, not with any implementing object, called directly on the interface name rather than through an instance:",[104,24524,24526],{"className":106,"code":24525,"language":108,"meta":48,"style":48},"public interface IntakeIO\n{\n    static double clampVolts(double v)\n    {\n        return Math.max(-12.0, Math.min(12.0, v));\n    }\n}\n",[95,24527,24528,24532,24536,24541,24545,24550,24554],{"__ignoreMap":48},[112,24529,24530],{"class":114,"line":115},[112,24531,24131],{},[112,24533,24534],{"class":114,"line":49},[112,24535,123],{},[112,24537,24538],{"class":114,"line":126},[112,24539,24540],{},"    static double clampVolts(double v)\n",[112,24542,24543],{"class":114,"line":132},[112,24544,135],{},[112,24546,24547],{"class":114,"line":138},[112,24548,24549],{},"        return Math.max(-12.0, Math.min(12.0, v));\n",[112,24551,24552],{"class":114,"line":144},[112,24553,147],{},[112,24555,24556],{"class":114,"line":150},[112,24557,153],{},[15,24559,24560,24563,24564,24566,24567,24570,24571,10755],{},[95,24561,24562],{},"IntakeIO.clampVolts(14.0)"," calls it directly on the interface name — no ",[95,24565,24209],{}," object needed, the same way ",[95,24568,24569],{},"Math.max(...)"," needs no ",[95,24572,2766],{},[24574,24575,24577],"h3",{"id":24576},"when-two-interfaces-defaults-collide","When Two Interfaces' Defaults Collide",[15,24579,24580,24581,24584],{},"If a class implements two interfaces that both supply a default method with the same signature, Java can't pick one for you — the class must override that method itself (calling one of them explicitly, e.g. ",[95,24582,24583],{},"Stowable.super.stop()",", if that's what's wanted), or it's a compile error. This only comes up with defaults; two abstract methods with the same signature just merge into one requirement.",[69,24586,24588],{"id":24587},"interface-or-abstract-class","Interface or Abstract Class?",[15,24590,24591,24592,24594,24595,14935,24597,537,24599,24601,24602,24604,24605,24607,24608,24610],{},"Lesson 17.5 introduced abstract classes as the other tool for \"some methods without bodies, filled in by subclasses\" — and promised this comparison. The short version: reach for an ",[25,24593,22447],{}," when the related classes share real state and code (fields, constructors, concrete helper methods) — like ",[95,24596,20446],{},[95,24598,9621],{},[95,24600,20595],{},". Reach for an ",[25,24603,23591],{}," when classes only need to share a set of methods, with no shared state, and especially when a class needs to honor more than one contract at once (a class can ",[95,24606,16808],{}," many interfaces, but ",[95,24609,16804],{}," only one class).",[3819,24612,24613,24625],{},[3822,24614,24615],{},[3825,24616,24617,24619,24622],{},[3828,24618],{},[3828,24620,24621],{},"Abstract class",[3828,24623,24624],{},"Interface",[3838,24626,24627,24641,24650,24665],{},[3825,24628,24629,24632,24635],{},[3843,24630,24631],{},"Fields (state)",[3843,24633,24634],{},"Yes",[3843,24636,24637,24638,24640],{},"Only ",[95,24639,11360],{}," constants",[3825,24642,24643,24645,24647],{},[3843,24644,9847],{},[3843,24646,24634],{},[3843,24648,24649],{},"No",[3825,24651,24652,24655,24660],{},[3843,24653,24654],{},"How many can a class have?",[3843,24656,24657,24658,1282],{},"One (",[95,24659,16804],{},[3843,24661,24662,24663,1282],{},"Any number (",[95,24664,16808],{},[3825,24666,24667,24670,24673],{},[3843,24668,24669],{},"Method bodies allowed?",[3843,24671,24672],{},"Yes, freely",[3843,24674,24637,24675,176,24677],{},[95,24676,5816],{},[95,24678,179],{},[69,24680,462],{"id":461},[19,24682,24683,24689,24705,24716,24736],{},[22,24684,24685,24688],{},[25,24686,24687],{},"Forgetting to implement every abstract method an interface declares."," A class that leaves even one required method unimplemented fails to compile — every non-default, non-static method is a firm requirement.",[22,24690,24691,24698,24699,24701,24702,24704],{},[25,24692,24693,24694,537,24696,79],{},"Confusing ",[95,24695,16804],{},[95,24697,16808],{}," A class ",[95,24700,16804],{}," exactly one class, but can ",[95,24703,16808],{}," any number of interfaces — these are two entirely separate mechanisms.",[22,24706,24707,24710,24711,12534,24713,24715],{},[25,24708,24709],{},"Assuming every interface method needs to be written from scratch."," Default methods (like ",[95,24712,20442],{},[95,24714,24209],{}," above) come \"for free\" — only override one if the default behavior isn't what you want.",[22,24717,24718,24723,24724,16960,24726,24729,24730,24732,24733,24735],{},[25,24719,24720,24721,79],{},"Writing an implementing method with weaker access than ",[95,24722,175],{}," Every interface method is implicitly ",[95,24725,175],{},[95,24727,24728],{},"RealIntakeIO.updateInputs"," declared without ",[95,24731,175],{}," (or as ",[95,24734,9905],{},") fails to compile with \"attempting to assign weaker access privileges.\"",[22,24737,24738,24741,24742,24745],{},[25,24739,24740],{},"Making every interface method an empty default \"for convenience.\""," That silently removes the compiler's guarantee that an implementation provides real behavior — a class that forgets to override an empty ",[95,24743,24744],{},"default setVoltage(double)"," compiles fine and simply never moves the motor. Keep methods abstract unless a default genuinely builds useful shared behavior on top of them.",[69,24747,501],{"id":500},[19,24749,24750,24764,24776,24779,24787],{},[22,24751,24752,24753,24755,24756,24758,24759,24761,24762,79],{},"An interface is a contract: method signatures with no implementation (default\u002Fstatic methods aside), specifying ",[494,24754,4416],{}," a class can do, not ",[494,24757,24117],{}," — every abstract method is implicitly ",[95,24760,175],{},", and every field is implicitly ",[95,24763,11360],{},[22,24765,24766,24767,24769,24770,24772,24773,24775],{},"A class agrees to an interface's contract with ",[95,24768,16808],{},", and can implement any number of interfaces at once — unlike the single-superclass limit of ",[95,24771,16804],{},". An interface can itself ",[95,24774,16804],{}," one or more other interfaces.",[22,24777,24778],{},"An interface is a real type — variables, parameters, arrays, and collections can all be declared against it, holding any object whose class implements it.",[22,24780,405,24781,24783,24784,24786],{},[95,24782,5816],{}," method provides a real implementation directly in the interface, letting implementing classes inherit it without writing their own; a ",[95,24785,179],{}," method belongs to the interface itself, called on its name. Two colliding defaults force the implementing class to override and resolve them.",[22,24788,24789],{},"Abstract class vs. interface (Lesson 17.5): shared state and code → abstract class; shared behavior only, or multiple contracts at once → interface.",[15,24791,544,24792,548,24794,322,24797,322,24800,322,24803,322,24806,322,24809,24812,24813,24815],{},[95,24793,17008],{},[95,24795,24796],{},"oracle-java-tutorials\u002Finterfaces\u002F01-interfaces.md",[95,24798,24799],{},"02-defining-an-interface.md",[95,24801,24802],{},"03-implementing-an-interface.md",[95,24804,24805],{},"04-using-an-interface-as-a-type.md",[95,24807,24808],{},"05-default-methods.md",[95,24810,24811],{},"06-summary-of-interfaces.md"," (ORACLE 15.1-6)\n",[25,24814,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 6 (\"Interfaces as Contracts\") — IntakeIO example",[554,24817,556],{},{"title":48,"searchDepth":49,"depth":49,"links":24819},[24820,24821,24822,24823,24824,24825,24828,24829,24830],{"id":24105,"depth":49,"text":24106},{"id":24229,"depth":49,"text":24230},{"id":24268,"depth":49,"text":24269},{"id":24309,"depth":49,"text":24310},{"id":24364,"depth":49,"text":24365},{"id":24429,"depth":49,"text":24430,"children":24826},[24827],{"id":24576,"depth":126,"text":24577},{"id":24587,"depth":49,"text":24588},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":24832,"status":570},"19 — Interfaces as Contracts (ORACLE 15.1-6)","\u002Fshockwave-curriculum\u002Flessons\u002Fch19-interfaces-as-contracts\u002F19-interfaces-as-contracts",{"title":24097,"description":48},"shockwave-curriculum\u002Flessons\u002Fch19-interfaces-as-contracts\u002F19-interfaces-as-contracts","gomPHyhX7zSiFiZH6enwa5B_pbXV2ngWLBtEFQPJM1o",{"id":24838,"title":24839,"body":24840,"description":48,"extension":51,"meta":25720,"navigation":55,"path":25722,"seo":25723,"stem":25724,"__hash__":25725},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch19-interfaces-as-contracts\u002F19.1-lambdas-and-method-references.md","Lambdas & Method References",{"type":8,"value":24841,"toc":25710},[24842,24845,24849,24866,24889,24916,24926,24930,24944,24988,24994,24998,25004,25013,25045,25087,25090,25122,25126,25139,25168,25171,25175,25186,25283,25327,25370,25374,25388,25464,25514,25539,25555,25557,25634,25636,25697,25708],[11,24843,24839],{"id":24844},"lambdas-method-references",[69,24846,24848],{"id":24847},"anonymous-classes-an-interface-implemented-without-a-name","Anonymous Classes: An Interface, Implemented Without a Name",[15,24850,24851,24852,24854,24855,24858,24859,24862,24863,738],{},"Lesson 19's ",[95,24853,16808],{}," always names a class. Java also lets you implement an interface ",[25,24856,24857],{},"inline",", right where an object is needed, with no separate class declaration at all — an ",[25,24860,24861],{},"anonymous class",". The syntax is ",[95,24864,24865],{},"new InterfaceName() { ...method bodies... }",[104,24867,24869],{"className":106,"code":24868,"language":108,"meta":48,"style":48},"interface SpeedSource\n{\n    double get(); \u002F\u002F exactly one abstract method (Lesson 19) — a method with no body\n}\n",[95,24870,24871,24876,24880,24885],{"__ignoreMap":48},[112,24872,24873],{"class":114,"line":115},[112,24874,24875],{},"interface SpeedSource\n",[112,24877,24878],{"class":114,"line":49},[112,24879,123],{},[112,24881,24882],{"class":114,"line":126},[112,24883,24884],{},"    double get(); \u002F\u002F exactly one abstract method (Lesson 19) — a method with no body\n",[112,24886,24887],{"class":114,"line":132},[112,24888,153],{},[104,24890,24892],{"className":106,"code":24891,"language":108,"meta":48,"style":48},"SpeedSource speed = new SpeedSource()\n{\n    @Override\n    public double get() { return joystick.getY(); }\n};\n",[95,24893,24894,24899,24903,24907,24912],{"__ignoreMap":48},[112,24895,24896],{"class":114,"line":115},[112,24897,24898],{},"SpeedSource speed = new SpeedSource()\n",[112,24900,24901],{"class":114,"line":49},[112,24902,123],{},[112,24904,24905],{"class":114,"line":126},[112,24906,21735],{},[112,24908,24909],{"class":114,"line":132},[112,24910,24911],{},"    public double get() { return joystick.getY(); }\n",[112,24913,24914],{"class":114,"line":138},[112,24915,6261],{},[15,24917,24918,24919,24922,24923,24925],{},"This creates one object of a brand-new, unnamed class that ",[95,24920,24921],{},"implements SpeedSource"," — built and used in a single expression, with none of the ceremony of a separate ",[95,24924,10701],{}," file or a named top-level class. It's most useful for a one-off implementation that nothing else in the program needs to refer to by name.",[69,24927,24929],{"id":24928},"the-problem-lambdas-solve","The Problem Lambdas Solve",[15,24931,24932,24933,24935,24936,24939,24940,24943],{},"When an interface declares exactly ",[25,24934,20553],{}," abstract method (a ",[25,24937,24938],{},"functional interface","), an anonymous class is still a lot of ceremony for something conceptually simple: \"here's the one bit of behavior you asked for.\" A ",[25,24941,24942],{},"lambda expression"," lets you write that one method's body directly, with no class declaration — named or anonymous — at all:",[104,24945,24947],{"className":106,"code":24946,"language":108,"meta":48,"style":48},"\u002F\u002F Anonymous class: still a full class body just to supply one value\nSpeedSource speed = new SpeedSource()\n{\n    @Override\n    public double get() { return joystick.getY(); }\n};\n\n\u002F\u002F With a lambda: the same thing, far more directly\nSpeedSource speed = () -> joystick.getY();\n",[95,24948,24949,24954,24958,24962,24966,24970,24974,24978,24983],{"__ignoreMap":48},[112,24950,24951],{"class":114,"line":115},[112,24952,24953],{},"\u002F\u002F Anonymous class: still a full class body just to supply one value\n",[112,24955,24956],{"class":114,"line":49},[112,24957,24898],{},[112,24959,24960],{"class":114,"line":126},[112,24961,123],{},[112,24963,24964],{"class":114,"line":132},[112,24965,21735],{},[112,24967,24968],{"class":114,"line":138},[112,24969,24911],{},[112,24971,24972],{"class":114,"line":144},[112,24973,6261],{},[112,24975,24976],{"class":114,"line":150},[112,24977,907],{"emptyLinePlaceholder":55},[112,24979,24980],{"class":114,"line":2276},[112,24981,24982],{},"\u002F\u002F With a lambda: the same thing, far more directly\n",[112,24984,24985],{"class":114,"line":2282},[112,24986,24987],{},"SpeedSource speed = () -> joystick.getY();\n",[15,24989,24990,24993],{},[95,24991,24992],{},"WPILib"," commands and suppliers are built almost entirely on this pattern — this is exactly what makes lambdas so central to command-based programming (Ch.25).",[69,24995,24997],{"id":24996},"lambda-syntax","Lambda Syntax",[15,24999,25000,25001,25003],{},"A lambda expression has three parts: a parameter list in parentheses, the arrow ",[95,25002,6195],{},", and a body:",[104,25005,25007],{"className":106,"code":25006,"language":108,"meta":48,"style":48},"(parameters) -> expression\n",[95,25008,25009],{"__ignoreMap":48},[112,25010,25011],{"class":114,"line":115},[112,25012,25006],{},[19,25014,25015,25021,25034],{},[22,25016,25017,25020],{},[25,25018,25019],{},"Parameter types are usually left out",", not written — the compiler already knows them from the functional interface being implemented. Writing them explicitly is legal (see Common Pitfalls) but not the normal style.",[22,25022,25023,25026,25027,25030,25031,79],{},[25,25024,25025],{},"Parentheses can be dropped"," around a single parameter: ",[95,25028,25029],{},"p -> p.getY()"," is valid, just like ",[95,25032,25033],{},"(p) -> p.getY()",[22,25035,25036,25039,25040,25042,25043,738],{},[25,25037,25038],{},"A single expression is the return value automatically"," — no ",[95,25041,3632],{}," keyword needed. A multi-statement body needs braces and an explicit ",[95,25044,3632],{},[104,25046,25048],{"className":106,"code":25047,"language":108,"meta":48,"style":48},"\u002F\u002F single expression — auto-returned\nSpeedSource speed = () -> joystick.getY();\n\n\u002F\u002F multi-statement body needs braces + return\nSpeedSource clampedSpeed = () -> {\n    double raw = joystick.getY();\n    return Math.max(-1.0, Math.min(1.0, raw));\n};\n",[95,25049,25050,25055,25059,25063,25068,25073,25078,25083],{"__ignoreMap":48},[112,25051,25052],{"class":114,"line":115},[112,25053,25054],{},"\u002F\u002F single expression — auto-returned\n",[112,25056,25057],{"class":114,"line":49},[112,25058,24987],{},[112,25060,25061],{"class":114,"line":126},[112,25062,907],{"emptyLinePlaceholder":55},[112,25064,25065],{"class":114,"line":132},[112,25066,25067],{},"\u002F\u002F multi-statement body needs braces + return\n",[112,25069,25070],{"class":114,"line":138},[112,25071,25072],{},"SpeedSource clampedSpeed = () -> {\n",[112,25074,25075],{"class":114,"line":144},[112,25076,25077],{},"    double raw = joystick.getY();\n",[112,25079,25080],{"class":114,"line":150},[112,25081,25082],{},"    return Math.max(-1.0, Math.min(1.0, raw));\n",[112,25084,25085],{"class":114,"line":2276},[112,25086,6261],{},[15,25088,25089],{},"A lambda with more than one parameter lists them comma-separated inside the parentheses:",[104,25091,25093],{"className":106,"code":25092,"language":108,"meta":48,"style":48},"public interface IntBinaryOperation\n{\n    int apply(int a, int b);\n}\n\nIntBinaryOperation add = (a, b) -> a + b;\n",[95,25094,25095,25100,25104,25109,25113,25117],{"__ignoreMap":48},[112,25096,25097],{"class":114,"line":115},[112,25098,25099],{},"public interface IntBinaryOperation\n",[112,25101,25102],{"class":114,"line":49},[112,25103,123],{},[112,25105,25106],{"class":114,"line":126},[112,25107,25108],{},"    int apply(int a, int b);\n",[112,25110,25111],{"class":114,"line":132},[112,25112,153],{},[112,25114,25115],{"class":114,"line":138},[112,25116,907],{"emptyLinePlaceholder":55},[112,25118,25119],{"class":114,"line":144},[112,25120,25121],{},"IntBinaryOperation add = (a, b) -> a + b;\n",[69,25123,25125],{"id":25124},"a-lambda-can-only-capture-final-or-effectively-final-locals","A Lambda Can Only Capture Final (or Effectively Final) Locals",[15,25127,25128,25129,25132,25133,25135,25136,738],{},"A lambda body can read local variables and parameters from the method around it — but only ones that are never reassigned after being given a value (",[25,25130,25131],{},"effectively final",", even without writing the ",[95,25134,381],{}," keyword). Reassigning one after the lambda is written is a compile error, not a runtime surprise — the exact message is ",[95,25137,25138],{},"local variables referenced from a lambda expression must be final or effectively final",[104,25140,25142],{"className":106,"code":25141,"language":108,"meta":48,"style":48},"double base = 1.0;\nbase = 2.0; \u002F\u002F reassigned — base is no longer effectively final\n\n\u002F\u002F does NOT compile — base is no longer effectively final\nSpeedSource s = () -> base;\n",[95,25143,25144,25149,25154,25158,25163],{"__ignoreMap":48},[112,25145,25146],{"class":114,"line":115},[112,25147,25148],{},"double base = 1.0;\n",[112,25150,25151],{"class":114,"line":49},[112,25152,25153],{},"base = 2.0; \u002F\u002F reassigned — base is no longer effectively final\n",[112,25155,25156],{"class":114,"line":126},[112,25157,907],{"emptyLinePlaceholder":55},[112,25159,25160],{"class":114,"line":132},[112,25161,25162],{},"\u002F\u002F does NOT compile — base is no longer effectively final\n",[112,25164,25165],{"class":114,"line":138},[112,25166,25167],{},"SpeedSource s = () -> base;\n",[15,25169,25170],{},"If a value genuinely needs to change and be read from inside a lambda, it has to live somewhere other than a local variable — a field (Lesson 7.2's \"Where Variables Live\") is the usual fix.",[69,25172,25174],{"id":25173},"functional-interfaces-youll-actually-use","Functional Interfaces You'll Actually Use",[15,25176,25177,25178,25181,25182,25185],{},"Java ships a whole family of ready-made functional interfaces in the ",[95,25179,25180],{},"java.util.function"," package, so you rarely need to declare your own. Each one is marked ",[95,25183,25184],{},"@FunctionalInterface"," (a compiler check confirming it has exactly one abstract method) and named after the shape of the one method it declares:",[3819,25187,25188,25201],{},[3822,25189,25190],{},[3825,25191,25192,25194,25196,25199],{},[3828,25193,24624],{},[3828,25195,3830],{},[3828,25197,25198],{},"Shape",[3828,25200,3836],{},[3838,25202,25203,25223,25243,25263],{},[3825,25204,25205,25210,25215,25218],{},[3843,25206,25207],{},[95,25208,25209],{},"Supplier\u003CT>",[3843,25211,25212],{},[95,25213,25214],{},"T get()",[3843,25216,25217],{},"no input, returns a value",[3843,25219,25220],{},[95,25221,25222],{},"Supplier\u003CString> name = () -> \"Intake\";",[3825,25224,25225,25230,25235,25238],{},[3843,25226,25227],{},[95,25228,25229],{},"Consumer\u003CT>",[3843,25231,25232],{},[95,25233,25234],{},"void accept(T t)",[3843,25236,25237],{},"takes a value, returns nothing",[3843,25239,25240],{},[95,25241,25242],{},"Consumer\u003CString> print = s -> System.out.println(s);",[3825,25244,25245,25250,25255,25258],{},[3843,25246,25247],{},[95,25248,25249],{},"Function\u003CT,R>",[3843,25251,25252],{},[95,25253,25254],{},"R apply(T t)",[3843,25256,25257],{},"takes a value, returns a (possibly different-typed) value",[3843,25259,25260],{},[95,25261,25262],{},"Function\u003CString,Integer> len = s -> s.length();",[3825,25264,25265,25270,25275,25278],{},[3843,25266,25267],{},[95,25268,25269],{},"Predicate\u003CT>",[3843,25271,25272],{},[95,25273,25274],{},"boolean test(T t)",[3843,25276,25277],{},"takes a value, returns true\u002Ffalse",[3843,25279,25280],{},[95,25281,25282],{},"Predicate\u003CString> isEmpty = s -> s.isEmpty();",[15,25284,25285,322,25288,322,25291,537,25294,25297,25298,25301,25302,25304,25305,25308,25309,2154,25311,25308,25314,25316,25317,25319,25320,25323,25324,25326],{},[95,25286,25287],{},"Supplier",[95,25289,25290],{},"Consumer",[95,25292,25293],{},"Function",[95,25295,25296],{},"Predicate"," all need ",[95,25299,25300],{},"import java.util.function.___;"," — they live in that package, not ",[95,25303,3200],{},". Two more specialized ones show up constantly in robot code — ",[95,25306,25307],{},"DoubleSupplier"," (no arguments, returns a ",[95,25310,631],{},[95,25312,25313],{},"BooleanSupplier",[95,25315,657],{},") — these also come from ",[95,25318,25180],{}," and need the same import. ",[95,25321,25322],{},"Runnable"," (no arguments, no return value) is the one exception: it lives in ",[95,25325,3200],{},", so it never needs an import.",[104,25328,25330],{"className":106,"code":25329,"language":108,"meta":48,"style":48},"import java.util.function.DoubleSupplier;\nimport java.util.function.BooleanSupplier;\n\nRunnable stopAll = () -> intake.stop();                 \u002F\u002F java.lang — no import needed\n\n\u002F\u002F java.util.function — needs the import above\nDoubleSupplier speed = () -> joystick.getY();\nBooleanSupplier hasGamePiece = () -> intake.hasPiece();\n",[95,25331,25332,25337,25342,25346,25351,25355,25360,25365],{"__ignoreMap":48},[112,25333,25334],{"class":114,"line":115},[112,25335,25336],{},"import java.util.function.DoubleSupplier;\n",[112,25338,25339],{"class":114,"line":49},[112,25340,25341],{},"import java.util.function.BooleanSupplier;\n",[112,25343,25344],{"class":114,"line":126},[112,25345,907],{"emptyLinePlaceholder":55},[112,25347,25348],{"class":114,"line":132},[112,25349,25350],{},"Runnable stopAll = () -> intake.stop();                 \u002F\u002F java.lang — no import needed\n",[112,25352,25353],{"class":114,"line":138},[112,25354,907],{"emptyLinePlaceholder":55},[112,25356,25357],{"class":114,"line":144},[112,25358,25359],{},"\u002F\u002F java.util.function — needs the import above\n",[112,25361,25362],{"class":114,"line":150},[112,25363,25364],{},"DoubleSupplier speed = () -> joystick.getY();\n",[112,25366,25367],{"class":114,"line":2276},[112,25368,25369],{},"BooleanSupplier hasGamePiece = () -> intake.hasPiece();\n",[69,25371,25373],{"id":25372},"method-references-an-even-shorter-form","Method References: An Even Shorter Form",[15,25375,25376,25377,25380,25381,2150,25384,25387],{},"When a lambda's ",[494,25378,25379],{},"entire"," body is just calling one existing method, a ",[25,25382,25383],{},"method reference",[95,25385,25386],{},"::",") says the same thing even more directly. There are four kinds:",[3819,25389,25390,25402],{},[3822,25391,25392],{},[3825,25393,25394,25397,25399],{},[3828,25395,25396],{},"Kind",[3828,25398,3836],{},[3828,25400,25401],{},"Equivalent lambda",[3838,25403,25404,25419,25434,25449],{},[3825,25405,25406,25409,25414],{},[3843,25407,25408],{},"Bound instance reference",[3843,25410,25411],{},[95,25412,25413],{},"intake::stop",[3843,25415,25416],{},[95,25417,25418],{},"() -> intake.stop()",[3825,25420,25421,25424,25429],{},[3843,25422,25423],{},"Unbound instance reference",[3843,25425,25426],{},[95,25427,25428],{},"String::isEmpty",[3843,25430,25431],{},[95,25432,25433],{},"s -> s.isEmpty()",[3825,25435,25436,25439,25444],{},[3843,25437,25438],{},"Static reference",[3843,25440,25441],{},[95,25442,25443],{},"Math::abs",[3843,25445,25446],{},[95,25447,25448],{},"x -> Math.abs(x)",[3825,25450,25451,25454,25459],{},[3843,25452,25453],{},"Constructor reference",[3843,25455,25456],{},[95,25457,25458],{},"IllegalStateException::new",[3843,25460,25461],{},[95,25462,25463],{},"() -> new IllegalStateException()",[15,25465,405,25466,25469,25470,25473,25474,25476,25477,25480,25481,25483,25484,25487,25488,25490,25491,25493,25494,25496,25497,25499,25500,25503,25504,25507,25508,25510,25511,79],{},[25,25467,25468],{},"bound"," reference already has its object (",[95,25471,25472],{},"intake",") — Java calls ",[95,25475,20442],{}," on that exact object. An ",[25,25478,25479],{},"unbound"," reference names only a class (",[95,25482,361],{},"); the object to call the method on arrives as the functional interface's own argument, e.g. a ",[95,25485,25486],{},"Predicate\u003CString>"," supplies the ",[95,25489,361],{}," itself. A ",[25,25492,179],{}," reference calls a ",[95,25495,179],{}," method directly, with the functional interface's argument(s) forwarded to it. A ",[25,25498,4566],{}," reference (",[95,25501,25502],{},"ClassName::new",") calls ",[95,25505,25506],{},"new ClassName(...)",", forwarding whatever arguments the functional interface's method supplies — this is exactly how Ch.24's ",[95,25509,25458],{}," works, as a ",[95,25512,25513],{},"Supplier\u003CIllegalStateException>",[104,25515,25517],{"className":106,"code":25516,"language":108,"meta":48,"style":48},"\u002F\u002F a lambda...\nRunnable stopAll = () -> intake.stop();\n\u002F\u002F ...is exactly equivalent to this bound method reference\nRunnable stopAll2 = intake::stop;\n",[95,25518,25519,25524,25529,25534],{"__ignoreMap":48},[112,25520,25521],{"class":114,"line":115},[112,25522,25523],{},"\u002F\u002F a lambda...\n",[112,25525,25526],{"class":114,"line":49},[112,25527,25528],{},"Runnable stopAll = () -> intake.stop();\n",[112,25530,25531],{"class":114,"line":126},[112,25532,25533],{},"\u002F\u002F ...is exactly equivalent to this bound method reference\n",[112,25535,25536],{"class":114,"line":132},[112,25537,25538],{},"Runnable stopAll2 = intake::stop;\n",[15,25540,25541,25543,25544,25547,25548,25550,25551,25554],{},[95,25542,25413],{}," reads as \"the ",[95,25545,25546],{},"stop"," method, called on ",[95,25549,25472],{},"\" — Java fills in the call automatically, with whatever arguments the functional interface's method expects. Method references exist purely as a shorthand for a lambda that does nothing but forward to an existing method — but they aren't ",[494,25552,25553],{},"quite"," identical in one respect (see Common Pitfalls).",[69,25556,462],{"id":461},[19,25558,25559,25575,25589,25598,25604],{},[22,25560,25561,476,25564,25567,25568,25571,25572,25574],{},[25,25562,25563],{},"Writing parameter types into a lambda.",[95,25565,25566],{},"(Person p) -> p.getAge()"," — while technically legal — is unusual style; letting the compiler infer the type (",[95,25569,25570],{},"p -> p.getAge()",") is the normal convention, since the functional interface already pins down what type ",[95,25573,15],{}," has to be.",[22,25576,25577,25582,25583,25585,25586,25588],{},[25,25578,4719,25579,25581],{},[95,25580,3632],{}," in a multi-statement lambda body."," A single-expression lambda auto-returns its value, but a ",[95,25584,7352],{}," block body needs an explicit ",[95,25587,3632],{},", exactly like a regular method.",[22,25590,25591,476,25594,25597],{},[25,25592,25593],{},"Reaching for a method reference when the lambda does more than forward one call.",[95,25595,25596],{},"() -> { intake.stop(); logEvent(\"stopped\"); }"," genuinely needs a lambda — a method reference only replaces a lambda that does nothing but call one existing method.",[22,25599,25600,25603],{},[25,25601,25602],{},"Reassigning a local variable a lambda reads."," A lambda can only capture locals that are final or effectively final — see above; reassigning one after (or before) the lambda reads it is a compile error.",[22,25605,25606,476,25609,25611,25612,25614,25615,25618,25619,25621,25622,25624,25625,22179,25628,25630,25631,25633],{},[25,25607,25608],{},"Assuming a bound method reference and its equivalent lambda behave identically.",[95,25610,25413],{}," reads (and can throw on) ",[95,25613,25472],{}," the moment the reference is ",[494,25616,25617],{},"created","; the equivalent lambda ",[95,25620,25418],{}," only reads ",[95,25623,25472],{}," when it's actually ",[494,25626,25627],{},"called",[95,25629,25472],{}," could be ",[95,25632,4645],{}," at the time the reference is written, this timing difference matters.",[69,25635,501],{"id":500},[19,25637,25638,25645,25655,25658,25681],{},[22,25639,25640,25641,25644],{},"An anonymous class (",[95,25642,25643],{},"new InterfaceName() { ... }",") implements an interface inline, with no separate named class — a lambda goes one step further for a functional interface (exactly one abstract method), skipping the class syntax entirely.",[22,25646,25647,25648,7740,25651,25654],{},"Syntax: ",[95,25649,25650],{},"(parameters) -> expression",[95,25652,25653],{},"{ statements; return value; }"," for a multi-statement body); parameter types are normally inferred, and parentheses can be dropped for a single parameter.",[22,25656,25657],{},"A lambda can only read local variables that are final or effectively final (never reassigned); a value that needs to change belongs in a field instead.",[22,25659,25660,25662,25663,322,25665,322,25667,322,25669,322,25671,537,25673,25675,25676,2150,25678,25680],{},[95,25661,25180],{}," ships ",[95,25664,25209],{},[95,25666,25229],{},[95,25668,25249],{},[95,25670,25269],{},[95,25672,25307],{},[95,25674,25313],{}," — all need an import; ",[95,25677,25322],{},[95,25679,3200],{},") doesn't.",[22,25682,25683,25684,322,25687,322,25690,3283,25693,25696],{},"A method reference (",[95,25685,25686],{},"object::method",[95,25688,25689],{},"Class::staticMethod",[95,25691,25692],{},"Class::instanceMethod",[95,25694,25695],{},"Class::new",") is shorthand for a lambda that does nothing but call one existing method or constructor — a bound reference evaluates its target object immediately, not when called.",[15,25698,544,25699,548,25701,25704,25705,25707],{},[95,25700,17008],{},[95,25702,25703],{},"oracle-java-tutorials\u002Flambdas\u002Flambda-expressions.md"," (ORACLE 12.2)\n",[25,25706,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-1.js, slide 12 (\"Lambdas & Method References\")",[554,25709,556],{},{"title":48,"searchDepth":49,"depth":49,"links":25711},[25712,25713,25714,25715,25716,25717,25718,25719],{"id":24847,"depth":49,"text":24848},{"id":24928,"depth":49,"text":24929},{"id":24996,"depth":49,"text":24997},{"id":25124,"depth":49,"text":25125},{"id":25173,"depth":49,"text":25174},{"id":25372,"depth":49,"text":25373},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":25721,"status":570},"19.1 — Lambdas & Method References (ORACLE 12.1-2) — relocated here since a lambda is really shorthand for a functional interface; teaching it before Interfaces existed had no real grounding","\u002Fshockwave-curriculum\u002Flessons\u002Fch19-interfaces-as-contracts\u002F1-lambdas-and-method-references",{"title":24839,"description":48},"shockwave-curriculum\u002Flessons\u002Fch19-interfaces-as-contracts\u002F19.1-lambdas-and-method-references","6QWsJC1geQTZRTJoYJF57zoQQlHeW4buE7luM5kyHaA",{"id":25727,"title":25728,"body":25729,"description":25736,"extension":51,"meta":26092,"navigation":55,"path":26094,"seo":26095,"stem":26096,"__hash__":26097},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch20-the-io-layer-pattern\u002F20-the-io-layer-pattern.md","The IO-Layer Pattern",{"type":8,"value":25730,"toc":26083},[25731,25734,25737,25741,25751,25757,25761,25780,25804,25815,25860,25866,25870,25879,25932,25947,25951,25963,25978,25985,25989,26022,26024,26051,26053,26070,26081],[11,25732,25728],{"id":25733},"the-io-layer-pattern",[15,25735,25736],{},"Everything Ch.17-19 built — inheritance, polymorphism, and especially interfaces as contracts — comes together here in a real, widely-used FRC architecture pattern: keeping hardware access completely separate from the logic that uses it.",[69,25738,25740],{"id":25739},"the-problem-hardware-everywhere-makes-testing-and-logging-hard","The Problem: Hardware Everywhere Makes Testing (and Logging) Hard",[15,25742,25743,25744,25746,25747,25750],{},"A subsystem that talks directly to real motor controllers and sensors is genuinely hard to reason about: it can't run at all without the physical robot present, and there's no clean seam where you could intercept its data. A stronger idea than typical FRC logging solves this: instead of just logging a handful of chosen values, log ",[494,25745,21370],{}," input flowing into the robot code, every loop cycle. Since every input is captured, a match can later be ",[25,25748,25749],{},"replayed"," off the robot with the exact same inputs, running the exact same logic — turning logging from \"a tool for checking specific values\" into a genuine safety net for verifying how any part of the code actually behaved. A logging framework (Ch.33) can record and replay data structured this way.",[15,25752,25753,25754,20710],{},"That capability only works if hardware access is structured so all input data flows through one well-defined seam. This is what the ",[25,25755,25756],{},"IO layer",[69,25758,25760],{"id":25759},"three-layers-of-a-subsystem","Three Layers of a Subsystem",[15,25762,25763,25764,25767,25768,25771,25772,25775,25776,25779],{},"Traditionally, an FRC subsystem mixes three concerns in one class: its ",[25,25765,25766],{},"public interface"," (methods the rest of the robot calls), its ",[25,25769,25770],{},"control logic"," (deciding what to do with sensor data), and its ",[25,25773,25774],{},"hardware interface"," (actually reading sensors, actually commanding motors). The IO-Layer Pattern pulls that third piece out into its own object. (Commands v3, Ch.25, calls this kind of class a ",[95,25777,25778],{},"Mechanism"," — this chapter keeps calling it a \"subsystem,\" the term used across the pattern's whole history.)",[104,25781,25782],{"className":106,"code":24124,"language":108,"meta":48,"style":48},[95,25783,25784,25788,25792,25796,25800],{"__ignoreMap":48},[112,25785,25786],{"class":114,"line":115},[112,25787,24131],{},[112,25789,25790],{"class":114,"line":49},[112,25791,123],{},[112,25793,25794],{"class":114,"line":126},[112,25795,24140],{},[112,25797,25798],{"class":114,"line":132},[112,25799,24145],{},[112,25801,25802],{"class":114,"line":138},[112,25803,153],{},[15,25805,25806,25808,25809,25811,25812,25814],{},[95,25807,24209],{}," is exactly the kind of contract from Lesson 19 — it says ",[494,25810,4416],{}," an intake can do (report its inputs, accept a voltage command), without saying ",[494,25813,24117],{},". Both methods are abstract, since neither one has a sensible default: two real implementations honor this same contract, and each one genuinely needs its own body (each class below is in its own file):",[104,25816,25818],{"className":106,"code":25817,"language":108,"meta":48,"style":48},"public class IntakeIOReal implements IntakeIO\n{\n    \u002F\u002F uses real hardware APIs to move physical rollers\n}\n\npublic class IntakeIOSim implements IntakeIO\n{\n    \u002F\u002F uses physics math (moment of inertia) to \"fake\" the robot in code\n}\n",[95,25819,25820,25825,25829,25834,25838,25842,25847,25851,25856],{"__ignoreMap":48},[112,25821,25822],{"class":114,"line":115},[112,25823,25824],{},"public class IntakeIOReal implements IntakeIO\n",[112,25826,25827],{"class":114,"line":49},[112,25828,123],{},[112,25830,25831],{"class":114,"line":126},[112,25832,25833],{},"    \u002F\u002F uses real hardware APIs to move physical rollers\n",[112,25835,25836],{"class":114,"line":132},[112,25837,153],{},[112,25839,25840],{"class":114,"line":138},[112,25841,907],{"emptyLinePlaceholder":55},[112,25843,25844],{"class":114,"line":144},[112,25845,25846],{},"public class IntakeIOSim implements IntakeIO\n",[112,25848,25849],{"class":114,"line":150},[112,25850,123],{},[112,25852,25853],{"class":114,"line":2276},[112,25854,25855],{},"    \u002F\u002F uses physics math (moment of inertia) to \"fake\" the robot in code\n",[112,25857,25858],{"class":114,"line":2282},[112,25859,153],{},[15,25861,25862,25863,25865],{},"The subsystem class itself only ever talks to the ",[95,25864,24209],{}," interface — it never knows, and never needs to know, which concrete implementation is actually running underneath.",[69,25867,25869],{"id":25868},"choosing-the-implementation-once-at-construction","Choosing the Implementation Once, at Construction",[15,25871,25872,25873,25875,25876,25878],{},"The whole point is decided in exactly one place — typically the ",[95,25874,20602],{}," constructor, at startup — by simply constructing the subsystem with a different ",[95,25877,24209],{}," implementation depending on whether the code is running on the real robot or in simulation:",[104,25880,25882],{"className":106,"code":25881,"language":108,"meta":48,"style":48},"public Robot()\n{\n    if (RobotBase.isReal())\n    {\n        intake = new Intake(new IntakeIOReal());\n    }\n    else\n    {\n        intake = new Intake(new IntakeIOSim());\n    }\n}\n",[95,25883,25884,25889,25893,25898,25902,25907,25911,25915,25919,25924,25928],{"__ignoreMap":48},[112,25885,25886],{"class":114,"line":115},[112,25887,25888],{},"public Robot()\n",[112,25890,25891],{"class":114,"line":49},[112,25892,123],{},[112,25894,25895],{"class":114,"line":126},[112,25896,25897],{},"    if (RobotBase.isReal())\n",[112,25899,25900],{"class":114,"line":132},[112,25901,135],{},[112,25903,25904],{"class":114,"line":138},[112,25905,25906],{},"        intake = new Intake(new IntakeIOReal());\n",[112,25908,25909],{"class":114,"line":144},[112,25910,147],{},[112,25912,25913],{"class":114,"line":150},[112,25914,14213],{},[112,25916,25917],{"class":114,"line":2276},[112,25918,135],{},[112,25920,25921],{"class":114,"line":2282},[112,25922,25923],{},"        intake = new Intake(new IntakeIOSim());\n",[112,25925,25926],{"class":114,"line":2288},[112,25927,147],{},[112,25929,25930],{"class":114,"line":5760},[112,25931,153],{},[15,25933,25934,12217,25937,25940,25941,25943,25944,25946],{},[95,25935,25936],{},"RobotBase.isReal()",[95,25938,25939],{},"org.wpilib.framework",") is the actual check that's true only when the code is running on real SystemCore hardware. ",[95,25942,9838],{}," (the subsystem) accepts an ",[95,25945,24209],{}," in its constructor and stores it — every call from then on goes through that reference, polymorphically (Lesson 18.3) dispatching to whichever implementation was actually supplied.",[69,25948,25950],{"id":25949},"inputs-flow-through-a-shared-object","Inputs Flow Through a Shared Object",[15,25952,25953,25954,25956,25957,25959,25960,25962],{},"Outputs (commands like ",[95,25955,24505],{},") are simple, one-way method calls. Inputs are handled more carefully, since they need to be read consistently ",[494,25958,19237],{}," stay replayable later: each IO interface has an accompanying inputs class holding ",[25,25961,175],{}," fields for every value that comes off the hardware — a plain data holder with no logic of its own, so it's an intentional exception to the private-field style taught since Ch.7 (Lesson 7.1):",[104,25964,25966],{"className":106,"code":25965,"language":108,"meta":48,"style":48},"\u002F\u002F pull fresh data from the IO layer into `inputs`, once per cycle\nio.updateInputs(inputs);\n",[95,25967,25968,25973],{"__ignoreMap":48},[112,25969,25970],{"class":114,"line":115},[112,25971,25972],{},"\u002F\u002F pull fresh data from the IO layer into `inputs`, once per cycle\n",[112,25974,25975],{"class":114,"line":49},[112,25976,25977],{},"io.updateInputs(inputs);\n",[15,25979,25980,25981,25984],{},"The rest of the subsystem then reads from the ",[95,25982,25983],{},"inputs"," object — never straight from the IO layer — for a critical reason: every piece of code within one loop cycle sees the exact same cached values, so the logic feeds off exactly the same numbers a replay later would see, instead of whatever the hardware happens to report at the exact instant each line runs.",[69,25986,25988],{"id":25987},"the-general-pattern-behind-this-ports-and-adapters","The General Pattern Behind This: Ports and Adapters",[15,25990,25991,25992,7740,25995,25998,25999,26002,26003,26005,26006,2150,26009,322,26012,26015,26016,26018,26019,26021],{},"This isn't an FRC-specific trick — it's a specific application of a broader, well-known software architecture idea called ",[25,25993,25994],{},"Hexagonal Architecture",[25,25996,25997],{},"Ports and Adapters","): keep core logic decoupled from whatever external system it happens to talk to (a database, a UI, real hardware), by defining a ",[25,26000,26001],{},"port"," (the interface — ",[95,26004,24209],{},") that any number of ",[25,26007,26008],{},"adapters",[95,26010,26011],{},"IntakeIOReal",[95,26013,26014],{},"IntakeIOSim",") can plug into. The core logic only ever depends on the port, never on any specific adapter — exactly mirroring ",[95,26017,9838],{}," only ever depending on ",[95,26020,24209],{},". The tradeoff is real: it's more abstraction and more files than talking to hardware directly, which is overkill for a one-off script — but it pays for itself the moment testability, simulation, or swappable hardware actually matter, which for a competition robot, they do.",[69,26023,462],{"id":461},[19,26025,26026,26032,26045],{},[22,26027,26028,26031],{},[25,26029,26030],{},"Letting the subsystem read hardware directly, bypassing the IO layer."," That reintroduces exactly the coupling the pattern exists to remove — no sim support, no clean replay.",[22,26033,26034,476,26037,26039,26040,26042,26043,79],{},[25,26035,26036],{},"Adding getters to the IO interface and calling them from the subsystem's logic, instead of reading the cached inputs object.",[95,26038,24209],{}," itself has nothing to read — but as soon as an implementation grows one, reaching for it directly instead of ",[95,26041,25983],{}," reintroduces values that can change mid-cycle in ways a replayed log never could — always read from ",[95,26044,25983],{},[22,26046,26047,26050],{},[25,26048,26049],{},"Treating the IO layer as optional overhead on a small subsystem."," It's genuinely more files and more ceremony — but the payoff (simulation, replay, decoupled testing) is exactly why competitive FRC codebases use it anyway.",[69,26052,501],{"id":500},[19,26054,26055,26058,26061,26067],{},[22,26056,26057],{},"The IO-Layer Pattern separates a subsystem's hardware access into its own interface (the \"IO\" layer), so the subsystem's own logic never touches real hardware APIs directly.",[22,26059,26060],{},"One interface, multiple implementations (real hardware vs. simulated), chosen once at construction — everything else dispatches polymorphically through the shared interface.",[22,26062,26063,26064,26066],{},"Inputs flow through a dedicated, shared object (",[95,26065,24219],{},", called once per cycle), so every piece of logic in that cycle reads the exact same snapshot — the structure a logging framework (Ch.33) needs to record and replay a match later.",[22,26068,26069],{},"This is FRC's specific application of the general Hexagonal Architecture (Ports and Adapters) pattern: core logic depends only on a port (interface), never on a specific adapter (implementation).",[15,26071,544,26072,548,26074,26077,26078,26080],{},[95,26073,17008],{},[95,26075,26076],{},"java-design-patterns\u002Fhexagonal-architecture.md"," (JDP 50.1)\n",[25,26079,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 7 (\"The IO-Layer Pattern\") — IntakeIOReal\u002FIntakeIOSim example",[554,26082,556],{},{"title":48,"searchDepth":49,"depth":49,"links":26084},[26085,26086,26087,26088,26089,26090,26091],{"id":25739,"depth":49,"text":25740},{"id":25759,"depth":49,"text":25760},{"id":25868,"depth":49,"text":25869},{"id":25949,"depth":49,"text":25950},{"id":25987,"depth":49,"text":25988},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":26093,"status":570},"20 — The IO-Layer Pattern (ADVKIT 40.1-11, JDP 50.1)","\u002Fshockwave-curriculum\u002Flessons\u002Fch20-the-io-layer-pattern\u002F20-the-io-layer-pattern",{"title":25728,"description":25736},"shockwave-curriculum\u002Flessons\u002Fch20-the-io-layer-pattern\u002F20-the-io-layer-pattern","tZvU33Jxd7_OtJg2WIM4L0KAnUCqhqqZcWC7MzRAZYY",{"id":26099,"title":26100,"body":26101,"description":48,"extension":51,"meta":26769,"navigation":55,"path":26771,"seo":26772,"stem":26773,"__hash__":26774},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch21-static-factories\u002F21-static-factories.md","Static Factories",{"type":8,"value":26102,"toc":26760},[26103,26106,26112,26124,26147,26188,26197,26201,26207,26252,26267,26271,26288,26473,26488,26517,26521,26532,26597,26631,26665,26667,26709,26711,26741,26758],[11,26104,26100],{"id":26105},"static-factories",[69,26107,26109,26110,20188],{"id":26108},"why-not-just-new","Why Not Just ",[95,26111,2504],{},[15,26113,405,26114,4875,26117,26119,26120,26123],{},[25,26115,26116],{},"static factory method",[95,26118,223],{}," method that returns an object, used ",[494,26121,26122],{},"instead of"," calling a constructor directly. At first glance this looks like extra ceremony for no reason — but it buys a few concrete things a plain constructor can't:",[19,26125,26126,26135,26141],{},[22,26127,26128,476,26131,26134],{},[25,26129,26130],{},"A descriptive name.",[95,26132,26133],{},"MyCommands.print(\"Ready\")"," says exactly what you're getting; a constructor overload chosen by argument types alone doesn't communicate intent nearly as clearly.",[22,26136,26137,26140],{},[25,26138,26139],{},"The freedom to not construct a new object at all."," A factory method can return a cached, already-existing instance instead of a fresh one — a constructor, by contrast, always creates something new.",[22,26142,26143,26146],{},[25,26144,26145],{},"The freedom to return a completely different concrete type",", chosen by logic inside the method — the caller only ever sees the return type (often an interface), never which concrete class was actually picked.",[104,26148,26150],{"className":106,"code":26149,"language":108,"meta":48,"style":48},"public class MyCommands\n{\n    public static Command print(String msg)\n    {\n        return Command.noRequirements(coroutine -> System.out.println(msg))\n            .named(\"Print \" + msg);\n    }\n}\n",[95,26151,26152,26157,26161,26166,26170,26175,26180,26184],{"__ignoreMap":48},[112,26153,26154],{"class":114,"line":115},[112,26155,26156],{},"public class MyCommands\n",[112,26158,26159],{"class":114,"line":49},[112,26160,123],{},[112,26162,26163],{"class":114,"line":126},[112,26164,26165],{},"    public static Command print(String msg)\n",[112,26167,26168],{"class":114,"line":132},[112,26169,135],{},[112,26171,26172],{"class":114,"line":138},[112,26173,26174],{},"        return Command.noRequirements(coroutine -> System.out.println(msg))\n",[112,26176,26177],{"class":114,"line":144},[112,26178,26179],{},"            .named(\"Print \" + msg);\n",[112,26181,26182],{"class":114,"line":150},[112,26183,147],{},[112,26185,26186],{"class":114,"line":2276},[112,26187,153],{},[15,26189,13153,26190,26192,26193,26196],{},[95,26191,26133],{}," reads clearly as \"give me a command that prints this message\" — the caller never needs to know or care that it's built from ",[95,26194,26195],{},"Command.noRequirements"," (Lesson 25.2) underneath.",[69,26198,26200],{"id":26199},"a-concrete-example-returning-a-cached-instance","A Concrete Example: Returning a Cached Instance",[15,26202,26203,26204,26206],{},"The \"freedom to not construct a new object\" isn't just theoretical — here it is in practice. A factory method can hand back the ",[494,26205,3485],{}," object every time instead of building a fresh one:",[104,26208,26210],{"className":106,"code":26209,"language":108,"meta":48,"style":48},"public class SensorLog\n{\n    private static final SensorLog INSTANCE = new SensorLog();\n\n    public static SensorLog getInstance()\n    {\n        return INSTANCE; \u002F\u002F the same object every call — never a fresh one\n    }\n}\n",[95,26211,26212,26217,26221,26226,26230,26235,26239,26244,26248],{"__ignoreMap":48},[112,26213,26214],{"class":114,"line":115},[112,26215,26216],{},"public class SensorLog\n",[112,26218,26219],{"class":114,"line":49},[112,26220,123],{},[112,26222,26223],{"class":114,"line":126},[112,26224,26225],{},"    private static final SensorLog INSTANCE = new SensorLog();\n",[112,26227,26228],{"class":114,"line":132},[112,26229,907],{"emptyLinePlaceholder":55},[112,26231,26232],{"class":114,"line":138},[112,26233,26234],{},"    public static SensorLog getInstance()\n",[112,26236,26237],{"class":114,"line":144},[112,26238,135],{},[112,26240,26241],{"class":114,"line":150},[112,26242,26243],{},"        return INSTANCE; \u002F\u002F the same object every call — never a fresh one\n",[112,26245,26246],{"class":114,"line":2276},[112,26247,147],{},[112,26249,26250],{"class":114,"line":2282},[112,26251,153],{},[15,26253,26254,26255,26258,26259,26262,26263,26266],{},"Every call to ",[95,26256,26257],{},"SensorLog.getInstance()"," returns the exact same ",[95,26260,26261],{},"SensorLog"," object. A constructor could never do this — ",[95,26264,26265],{},"new SensorLog()"," always builds a new one.",[69,26268,26270],{"id":26269},"the-real-payoff-choosing-an-implementation-by-condition","The Real Payoff: Choosing an Implementation by Condition",[15,26272,26273,26274,26277,26278,26280,26281,26283,26284,26287],{},"The pattern's biggest use in FRC code is picking between real and simulated hardware — deciding ",[494,26275,26276],{},"which"," concrete class to construct, in exactly one place, based on a condition. A factory class like this exists purely to hold ",[95,26279,179],{}," members, so it also gets a ",[95,26282,9905],{}," constructor — nothing outside the class ever needs, or is allowed, to write ",[95,26285,26286],{},"new DrivetrainFactory()"," (each class below is in its own file):",[104,26289,26291],{"className":106,"code":26290,"language":108,"meta":48,"style":48},"public interface Drivetrain\n{\n    void drive(double speed, double turn);\n}\n\npublic class RealDrivetrain implements Drivetrain\n{\n    @Override\n    public void drive(double speed, double turn)\n    {\n        \u002F\u002F control the real motor controllers\n    }\n}\n\npublic class SimDrivetrain implements Drivetrain\n{\n    @Override\n    public void drive(double speed, double turn)\n    {\n        \u002F\u002F simulate motion via WPILib sim\n    }\n}\n\npublic class DrivetrainFactory\n{\n    private DrivetrainFactory() {} \u002F\u002F never instantiated — only static members\n\n    public static Drivetrain createDrivetrain()\n    {\n        if (RobotBase.isReal())\n        {\n            return new RealDrivetrain();\n        }\n        else\n        {\n            return new SimDrivetrain();\n        }\n    }\n}\n",[95,26292,26293,26298,26302,26307,26311,26315,26320,26324,26328,26333,26337,26342,26346,26350,26354,26359,26363,26367,26371,26375,26380,26384,26388,26392,26397,26401,26406,26410,26415,26419,26425,26430,26436,26441,26447,26452,26458,26463,26468],{"__ignoreMap":48},[112,26294,26295],{"class":114,"line":115},[112,26296,26297],{},"public interface Drivetrain\n",[112,26299,26300],{"class":114,"line":49},[112,26301,123],{},[112,26303,26304],{"class":114,"line":126},[112,26305,26306],{},"    void drive(double speed, double turn);\n",[112,26308,26309],{"class":114,"line":132},[112,26310,153],{},[112,26312,26313],{"class":114,"line":138},[112,26314,907],{"emptyLinePlaceholder":55},[112,26316,26317],{"class":114,"line":144},[112,26318,26319],{},"public class RealDrivetrain implements Drivetrain\n",[112,26321,26322],{"class":114,"line":150},[112,26323,123],{},[112,26325,26326],{"class":114,"line":2276},[112,26327,21735],{},[112,26329,26330],{"class":114,"line":2282},[112,26331,26332],{},"    public void drive(double speed, double turn)\n",[112,26334,26335],{"class":114,"line":2288},[112,26336,135],{},[112,26338,26339],{"class":114,"line":5760},[112,26340,26341],{},"        \u002F\u002F control the real motor controllers\n",[112,26343,26344],{"class":114,"line":5766},[112,26345,147],{},[112,26347,26348],{"class":114,"line":5772},[112,26349,153],{},[112,26351,26352],{"class":114,"line":5777},[112,26353,907],{"emptyLinePlaceholder":55},[112,26355,26356],{"class":114,"line":5783},[112,26357,26358],{},"public class SimDrivetrain implements Drivetrain\n",[112,26360,26361],{"class":114,"line":5789},[112,26362,123],{},[112,26364,26365],{"class":114,"line":5794},[112,26366,21735],{},[112,26368,26369],{"class":114,"line":10057},[112,26370,26332],{},[112,26372,26373],{"class":114,"line":10062},[112,26374,135],{},[112,26376,26377],{"class":114,"line":13813},[112,26378,26379],{},"        \u002F\u002F simulate motion via WPILib sim\n",[112,26381,26382],{"class":114,"line":13818},[112,26383,147],{},[112,26385,26386],{"class":114,"line":13824},[112,26387,153],{},[112,26389,26390],{"class":114,"line":13830},[112,26391,907],{"emptyLinePlaceholder":55},[112,26393,26394],{"class":114,"line":13835},[112,26395,26396],{},"public class DrivetrainFactory\n",[112,26398,26399],{"class":114,"line":13840},[112,26400,123],{},[112,26402,26403],{"class":114,"line":13845},[112,26404,26405],{},"    private DrivetrainFactory() {} \u002F\u002F never instantiated — only static members\n",[112,26407,26408],{"class":114,"line":13850},[112,26409,907],{"emptyLinePlaceholder":55},[112,26411,26412],{"class":114,"line":13856},[112,26413,26414],{},"    public static Drivetrain createDrivetrain()\n",[112,26416,26417],{"class":114,"line":13861},[112,26418,135],{},[112,26420,26422],{"class":114,"line":26421},30,[112,26423,26424],{},"        if (RobotBase.isReal())\n",[112,26426,26428],{"class":114,"line":26427},31,[112,26429,11303],{},[112,26431,26433],{"class":114,"line":26432},32,[112,26434,26435],{},"            return new RealDrivetrain();\n",[112,26437,26439],{"class":114,"line":26438},33,[112,26440,11313],{},[112,26442,26444],{"class":114,"line":26443},34,[112,26445,26446],{},"        else\n",[112,26448,26450],{"class":114,"line":26449},35,[112,26451,11303],{},[112,26453,26455],{"class":114,"line":26454},36,[112,26456,26457],{},"            return new SimDrivetrain();\n",[112,26459,26461],{"class":114,"line":26460},37,[112,26462,11313],{},[112,26464,26466],{"class":114,"line":26465},38,[112,26467,147],{},[112,26469,26471],{"class":114,"line":26470},39,[112,26472,153],{},[104,26474,26476],{"className":106,"code":26475,"language":108,"meta":48,"style":48},"\u002F\u002F caller never picks the concrete class itself\nDrivetrain drivetrain = DrivetrainFactory.createDrivetrain();\n",[95,26477,26478,26483],{"__ignoreMap":48},[112,26479,26480],{"class":114,"line":115},[112,26481,26482],{},"\u002F\u002F caller never picks the concrete class itself\n",[112,26484,26485],{"class":114,"line":49},[112,26486,26487],{},"Drivetrain drivetrain = DrivetrainFactory.createDrivetrain();\n",[15,26489,26490,26491,26494,26495,26497,26498,26501,26502,26505,26506,26509,26510,26513,26514,26516],{},"This is a genuine alternative to the constructor-injection style from the IO-Layer Pattern (Ch.20) — ",[25,26492,26493],{},"constructor injection"," means the caller decides which implementation to use and passes (\"injects\") it in through a constructor parameter, the way Ch.20's ",[95,26496,20602],{}," constructor builds ",[95,26499,26500],{},"new Intake(new IntakeIOReal())"," itself. A factory flips that: instead of the caller deciding, the factory itself makes the real-vs-sim decision, centralizing that one ",[95,26503,26504],{},"if (RobotBase.isReal())"," check inside ",[95,26507,26508],{},"createDrivetrain()"," rather than repeating it at every construction site. WPILib's own API uses this pattern too — ",[95,26511,26512],{},"Rotation2d.fromDegrees(90)"," (Lesson 4.5) is a real static factory, more descriptive than calling ",[95,26515,4630],{},"'s constructor with radians directly.",[69,26518,26520],{"id":26519},"factories-for-more-than-hardware","Factories for More Than Hardware",[15,26522,26523,26524,476,26526,26529,26530,738],{},"The same idea works for building the right object out of a whole family of choices — not just two (real\u002Fsim), but any number, selected by some other input. This is a ",[95,26525,5700],{},[25,26527,26528],{},"expression"," (Lesson 5.12) over a ",[95,26531,361],{},[104,26533,26535],{"className":106,"code":26534,"language":108,"meta":48,"style":48},"public class AutoFactory\n{\n    public static Command createAuto(String mode)\n    {\n        return switch (mode)\n        {\n            case \"Taxi\" -> MyCommands.driveForward(3.0);\n            case \"2 Ball\" -> MyCommands.twoBallAuto();\n            case \"Nothing\" -> Command.waitFor(Seconds.of(0.1)).named(\"Do Nothing\");\n            case null, default -> MyCommands.print(\"Unknown Auto Mode\");\n        };\n    }\n}\n",[95,26536,26537,26542,26546,26551,26555,26560,26564,26569,26574,26579,26584,26589,26593],{"__ignoreMap":48},[112,26538,26539],{"class":114,"line":115},[112,26540,26541],{},"public class AutoFactory\n",[112,26543,26544],{"class":114,"line":49},[112,26545,123],{},[112,26547,26548],{"class":114,"line":126},[112,26549,26550],{},"    public static Command createAuto(String mode)\n",[112,26552,26553],{"class":114,"line":132},[112,26554,135],{},[112,26556,26557],{"class":114,"line":138},[112,26558,26559],{},"        return switch (mode)\n",[112,26561,26562],{"class":114,"line":144},[112,26563,11303],{},[112,26565,26566],{"class":114,"line":150},[112,26567,26568],{},"            case \"Taxi\" -> MyCommands.driveForward(3.0);\n",[112,26570,26571],{"class":114,"line":2276},[112,26572,26573],{},"            case \"2 Ball\" -> MyCommands.twoBallAuto();\n",[112,26575,26576],{"class":114,"line":2282},[112,26577,26578],{},"            case \"Nothing\" -> Command.waitFor(Seconds.of(0.1)).named(\"Do Nothing\");\n",[112,26580,26581],{"class":114,"line":2288},[112,26582,26583],{},"            case null, default -> MyCommands.print(\"Unknown Auto Mode\");\n",[112,26585,26586],{"class":114,"line":5760},[112,26587,26588],{},"        };\n",[112,26590,26591],{"class":114,"line":5766},[112,26592,147],{},[112,26594,26595],{"class":114,"line":5772},[112,26596,153],{},[104,26598,26600],{"className":106,"code":26599,"language":108,"meta":48,"style":48},"\u002F\u002F org.wpilib.tunable — the 2027 driver-station chooser\nSelectable\u003CString> chooser = new Selectable\u003C>();\nchooser.addDefault(\"Taxi\", \"Taxi\");\n\n\u002F\u002F built from whatever the driver station selected\nCommand auto = AutoFactory.createAuto(chooser.getSelected());\n",[95,26601,26602,26607,26612,26617,26621,26626],{"__ignoreMap":48},[112,26603,26604],{"class":114,"line":115},[112,26605,26606],{},"\u002F\u002F org.wpilib.tunable — the 2027 driver-station chooser\n",[112,26608,26609],{"class":114,"line":49},[112,26610,26611],{},"Selectable\u003CString> chooser = new Selectable\u003C>();\n",[112,26613,26614],{"class":114,"line":126},[112,26615,26616],{},"chooser.addDefault(\"Taxi\", \"Taxi\");\n",[112,26618,26619],{"class":114,"line":132},[112,26620,907],{"emptyLinePlaceholder":55},[112,26622,26623],{"class":114,"line":138},[112,26624,26625],{},"\u002F\u002F built from whatever the driver station selected\n",[112,26627,26628],{"class":114,"line":144},[112,26629,26630],{},"Command auto = AutoFactory.createAuto(chooser.getSelected());\n",[15,26632,26633,26636,26637,26639,26640,26642,26643,26646,26647,26649,26650,26652,26653,26655,26656,845,26658,26661,26662,26664],{},[95,26634,26635],{},"chooser.getSelected()"," can return ",[95,26638,4645],{}," if nothing was ever selected ",[494,26641,19237],{}," no default was set with ",[95,26644,26645],{},"addDefault(...)"," — a plain ",[95,26648,5816],{}," case doesn't catch ",[95,26651,4645],{},", and switching on a ",[95,26654,4645],{}," String otherwise throws a ",[95,26657,4678],{},[95,26659,26660],{},"case null, default ->"," (Java 21+ pattern matching for switch) explicitly routes a ",[95,26663,4645],{}," mode to the same fallback as any other unrecognized one.",[69,26666,462],{"id":461},[19,26668,26669,26681,26696],{},[22,26670,26671,476,26674,26677,26678,26680],{},[25,26672,26673],{},"Returning a concrete class instead of an interface.",[95,26675,26676],{},"public static RealDrivetrain createDrivetrain()"," locks callers into one specific implementation — return the interface type (",[95,26679,365],{},") so the real choice stays hidden inside the factory.",[22,26682,26683,26689,26690,26692,26693,26695],{},[25,26684,26685,26686,26688],{},"Duplicating the same real-vs-sim ",[95,26687,2179],{}," check in multiple places."," The whole point of a factory is centralizing that decision in one method — scattering ",[95,26691,25936],{}," checks throughout the codebase (instead of injecting once, as Ch.20's ",[95,26694,20602],{}," constructor does, or factoring it into one method here) defeats the purpose.",[22,26697,26698,26701,26702,26704,26705,26708],{},[25,26699,26700],{},"Confusing a factory with a constructor."," A factory method is just a regular ",[95,26703,179],{}," method — it can return a cached instance or pick any subtype, neither of which a constructor is free to do (a constructor always returns a new instance of its own exact class). A factory method ",[494,26706,26707],{},"can"," validate its arguments, but so can a constructor (Lesson 12) — that part isn't a difference between them.",[69,26710,501],{"id":500},[19,26712,26713,26719,26722,26733],{},[22,26714,26715,26716,26718],{},"A static factory method returns an object in place of a direct constructor call, with a descriptive name, the option to return a cached instance (",[95,26717,26257],{},"), and the freedom to choose the actual concrete type internally.",[22,26720,26721],{},"Its most common FRC use: centralizing real-vs-simulated (or comp-bot-vs-practice-bot) selection logic in one place, so callers only ever depend on an interface. This is an alternative to constructor injection (Ch.20) — the factory decides, instead of the caller.",[22,26723,26724,26725,26727,26728,26730,26731,79],{},"Factories generalize beyond hardware — anything selected by a condition (an autonomous mode, a config option) is a natural fit; a ",[95,26726,5700],{}," expression choosing between commands needs ",[95,26729,26660],{}," if the input could be ",[95,26732,4645],{},[22,26734,26735,26736,26738,26739,79],{},"Always return the interface type from a factory method, not a specific concrete class, so the actual implementation choice stays hidden from callers. A factory-only class gets a ",[95,26737,9905],{}," constructor, since nothing should ever build one with ",[95,26740,2504],{},[15,26742,544,26743,548,26745,26748,26749,2150,26751,26754,26755,26757],{},[95,26744,17008],{},[95,26746,26747],{},"team-5817-training\u002Fdesign-patterns\u002Ffactory.md"," (T5817 30.2); updated for Commands v3 from allwpilib ",[95,26750,101],{},[95,26752,26753],{},"commandsv3\u002F…\u002Fcommand3\u002FCommand.java",")\n",[25,26756,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 7 (\"Static Factories\")",[554,26759,556],{},{"title":48,"searchDepth":49,"depth":49,"links":26761},[26762,26764,26765,26766,26767,26768],{"id":26108,"depth":49,"text":26763},"Why Not Just new?",{"id":26199,"depth":49,"text":26200},{"id":26269,"depth":49,"text":26270},{"id":26519,"depth":49,"text":26520},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":26770,"status":570},"21 — Static Factories (T5817 30.2)","\u002Fshockwave-curriculum\u002Flessons\u002Fch21-static-factories\u002F21-static-factories",{"title":26100,"description":48},"shockwave-curriculum\u002Flessons\u002Fch21-static-factories\u002F21-static-factories","8mCbvZhJSmRBw2UPCd6j6C4fQTQvE3JlvkHKsySi7WE",{"id":26776,"title":26777,"body":26778,"description":48,"extension":51,"meta":27393,"navigation":55,"path":27395,"seo":27396,"stem":27397,"__hash__":27398},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch22-the-builder-pattern\u002F22-the-builder-pattern.md","The Builder Pattern",{"type":8,"value":26779,"toc":27380},[26780,26783,26787,26790,26799,26802,26806,26828,26873,26884,26888,26903,27058,27070,27074,27110,27147,27161,27169,27191,27195,27229,27233,27239,27259,27277,27281,27284,27286,27330,27332,27367,27378],[11,26781,26777],{"id":26782},"the-builder-pattern",[69,26784,26786],{"id":26785},"the-problem-constructor-hell","The Problem: \"Constructor Hell\"",[15,26788,26789],{},"A constructor with many parameters — especially several of the same type, or several optional ones — becomes genuinely hard to read and easy to get wrong:",[104,26791,26793],{"className":106,"code":26792,"language":108,"meta":48,"style":48},"Shooter shooter = new Shooter(0.01, 0.0, 0.02, true, 5000.0, 1000.0);\n",[95,26794,26795],{"__ignoreMap":48},[112,26796,26797],{"class":114,"line":115},[112,26798,26792],{},[15,26800,26801],{},"What does each number actually mean? Swap two arguments of the same type by mistake, and the compiler won't catch it — it'll just silently misconfigure the shooter. This is sometimes called \"constructor hell,\" and it gets worse the more optional settings a class has, since a constructor either forces every caller to specify every parameter, or multiplies into a pile of overloads trying to cover every combination.",[69,26803,26805],{"id":26804},"the-builder-pattern-construct-step-by-step","The Builder Pattern: Construct Step by Step",[15,26807,2424,26808,26811,26812,26815,26816,26819,26820,26823,26824,26827],{},[25,26809,26810],{},"Builder Pattern"," separates ",[494,26813,26814],{},"building"," an object from ",[494,26817,26818],{},"using"," it — a separate ",[95,26821,26822],{},"Builder"," object collects settings one at a time, through named, chainable methods, then produces the final object only once, via a ",[95,26825,26826],{},"build()"," call:",[104,26829,26831],{"className":106,"code":26830,"language":108,"meta":48,"style":48},"Shooter shooter = new Shooter.Builder()\n    .setKP(0.01)\n    .setKI(0.0)\n    .setKD(0.02)\n    .enableFeedforward(true)\n    .setMaxRPM(5000.0)\n    .setMinRPM(1000.0)\n    .build();\n",[95,26832,26833,26838,26843,26848,26853,26858,26863,26868],{"__ignoreMap":48},[112,26834,26835],{"class":114,"line":115},[112,26836,26837],{},"Shooter shooter = new Shooter.Builder()\n",[112,26839,26840],{"class":114,"line":49},[112,26841,26842],{},"    .setKP(0.01)\n",[112,26844,26845],{"class":114,"line":126},[112,26846,26847],{},"    .setKI(0.0)\n",[112,26849,26850],{"class":114,"line":132},[112,26851,26852],{},"    .setKD(0.02)\n",[112,26854,26855],{"class":114,"line":138},[112,26856,26857],{},"    .enableFeedforward(true)\n",[112,26859,26860],{"class":114,"line":144},[112,26861,26862],{},"    .setMaxRPM(5000.0)\n",[112,26864,26865],{"class":114,"line":150},[112,26866,26867],{},"    .setMinRPM(1000.0)\n",[112,26869,26870],{"class":114,"line":2276},[112,26871,26872],{},"    .build();\n",[15,26874,26875,26876,26879,26880,26883],{},"Every call is now self-documenting — ",[95,26877,26878],{},".setKP(0.01)"," says exactly what ",[95,26881,26882],{},"0.01"," means, in a way a bare constructor argument never could.",[69,26885,26887],{"id":26886},"implementing-a-builder","Implementing a Builder",[15,26889,26890,26891,26893,26894,26896,26897,26899,26900,26902],{},"The target class (",[95,26892,20639],{},") gets a ",[95,26895,9905],{}," constructor — callers can no longer construct it directly, only through the builder — plus a ",[95,26898,223],{}," nested ",[95,26901,26822],{}," class that collects the settings:",[104,26904,26906],{"className":106,"code":26905,"language":108,"meta":48,"style":48},"public class Shooter\n{\n    private final double kP, kI, kD;\n    private final boolean feedforward;\n    private final double maxRPM, minRPM;\n\n    private Shooter(Builder builder)\n    {\n        this.kP = builder.kP;\n        this.kI = builder.kI;\n        this.kD = builder.kD;\n        this.feedforward = builder.feedforward;\n        this.maxRPM = builder.maxRPM;\n        this.minRPM = builder.minRPM;\n    }\n\n    public static class Builder\n    {\n        private double kP = 0, kI = 0, kD = 0;\n        private boolean feedforward = false;\n        private double maxRPM = 0, minRPM = 0;\n\n        public Builder setKP(double kP) { this.kP = kP; return this; }\n        public Builder setKI(double kI) { this.kI = kI; return this; }\n        public Builder setKD(double kD) { this.kD = kD; return this; }\n        public Builder enableFeedforward(boolean ff) { feedforward = ff; return this; }\n        public Builder setMaxRPM(double max) { this.maxRPM = max; return this; }\n        public Builder setMinRPM(double min) { this.minRPM = min; return this; }\n\n        public Shooter build() { return new Shooter(this); }\n    }\n}\n",[95,26907,26908,26913,26917,26922,26927,26932,26936,26941,26945,26950,26955,26960,26965,26970,26975,26979,26983,26988,26992,26997,27002,27007,27011,27016,27021,27026,27031,27036,27041,27045,27050,27054],{"__ignoreMap":48},[112,26909,26910],{"class":114,"line":115},[112,26911,26912],{},"public class Shooter\n",[112,26914,26915],{"class":114,"line":49},[112,26916,123],{},[112,26918,26919],{"class":114,"line":126},[112,26920,26921],{},"    private final double kP, kI, kD;\n",[112,26923,26924],{"class":114,"line":132},[112,26925,26926],{},"    private final boolean feedforward;\n",[112,26928,26929],{"class":114,"line":138},[112,26930,26931],{},"    private final double maxRPM, minRPM;\n",[112,26933,26934],{"class":114,"line":144},[112,26935,907],{"emptyLinePlaceholder":55},[112,26937,26938],{"class":114,"line":150},[112,26939,26940],{},"    private Shooter(Builder builder)\n",[112,26942,26943],{"class":114,"line":2276},[112,26944,135],{},[112,26946,26947],{"class":114,"line":2282},[112,26948,26949],{},"        this.kP = builder.kP;\n",[112,26951,26952],{"class":114,"line":2288},[112,26953,26954],{},"        this.kI = builder.kI;\n",[112,26956,26957],{"class":114,"line":5760},[112,26958,26959],{},"        this.kD = builder.kD;\n",[112,26961,26962],{"class":114,"line":5766},[112,26963,26964],{},"        this.feedforward = builder.feedforward;\n",[112,26966,26967],{"class":114,"line":5772},[112,26968,26969],{},"        this.maxRPM = builder.maxRPM;\n",[112,26971,26972],{"class":114,"line":5777},[112,26973,26974],{},"        this.minRPM = builder.minRPM;\n",[112,26976,26977],{"class":114,"line":5783},[112,26978,147],{},[112,26980,26981],{"class":114,"line":5789},[112,26982,907],{"emptyLinePlaceholder":55},[112,26984,26985],{"class":114,"line":5794},[112,26986,26987],{},"    public static class Builder\n",[112,26989,26990],{"class":114,"line":10057},[112,26991,135],{},[112,26993,26994],{"class":114,"line":10062},[112,26995,26996],{},"        private double kP = 0, kI = 0, kD = 0;\n",[112,26998,26999],{"class":114,"line":13813},[112,27000,27001],{},"        private boolean feedforward = false;\n",[112,27003,27004],{"class":114,"line":13818},[112,27005,27006],{},"        private double maxRPM = 0, minRPM = 0;\n",[112,27008,27009],{"class":114,"line":13824},[112,27010,907],{"emptyLinePlaceholder":55},[112,27012,27013],{"class":114,"line":13830},[112,27014,27015],{},"        public Builder setKP(double kP) { this.kP = kP; return this; }\n",[112,27017,27018],{"class":114,"line":13835},[112,27019,27020],{},"        public Builder setKI(double kI) { this.kI = kI; return this; }\n",[112,27022,27023],{"class":114,"line":13840},[112,27024,27025],{},"        public Builder setKD(double kD) { this.kD = kD; return this; }\n",[112,27027,27028],{"class":114,"line":13845},[112,27029,27030],{},"        public Builder enableFeedforward(boolean ff) { feedforward = ff; return this; }\n",[112,27032,27033],{"class":114,"line":13850},[112,27034,27035],{},"        public Builder setMaxRPM(double max) { this.maxRPM = max; return this; }\n",[112,27037,27038],{"class":114,"line":13856},[112,27039,27040],{},"        public Builder setMinRPM(double min) { this.minRPM = min; return this; }\n",[112,27042,27043],{"class":114,"line":13861},[112,27044,907],{"emptyLinePlaceholder":55},[112,27046,27047],{"class":114,"line":26421},[112,27048,27049],{},"        public Shooter build() { return new Shooter(this); }\n",[112,27051,27052],{"class":114,"line":26427},[112,27053,147],{},[112,27055,27056],{"class":114,"line":26432},[112,27057,153],{},[15,27059,27060,27063,27064,27066,27067,27069],{},[95,27061,27062],{},"private final double kP, kI, kD;"," declares three fields of the same type in one statement, separated by commas (Lesson 2.1). Every field here is also ",[95,27065,381],{}," — Lesson 23.1 covers ",[95,27068,381],{}," fields, methods, and classes in full.",[69,27071,27073],{"id":27072},"classes-inside-classes-static-nested-classes","Classes Inside Classes: Static Nested Classes",[15,27075,27076,27078,27079,27082,27083,27085,27086,27089,27090,27093,27094,27097,27098,27100,27101,27103,27104,27106,27107,27109],{},[95,27077,26822],{}," is written as ",[95,27080,27081],{},"public static class Builder",", declared entirely inside ",[95,27084,20639],{},"'s own braces — that's a ",[25,27087,27088],{},"static nested class",". Its full name is ",[95,27091,27092],{},"Shooter.Builder",", which is exactly why building one starts with ",[95,27095,27096],{},"new Shooter.Builder()",". The ",[95,27099,179],{}," here means what it always means: a ",[95,27102,27092],{}," can be created without an existing ",[95,27105,20639],{}," object around, the same way a ",[95,27108,179],{}," method can be called without an existing object.",[15,27111,27112,27113,537,27115,27117,27118,27120,27121,27123,27124,27127,27128,1291,27131,17790,27133,27135,27136,21750,27139,14935,27141,27143,27144,27146],{},"Nesting one class inside another also grants both classes a special privilege: ",[95,27114,20639],{},[95,27116,27092],{}," can reach each other's ",[95,27119,9905],{}," members directly, something no other class could do. That's how the ",[95,27122,20639],{}," constructor above can read ",[95,27125,27126],{},"builder.kP"," even though ",[95,27129,27130],{},"kP",[95,27132,9905],{},[95,27134,26822],{}," — and how ",[95,27137,27138],{},"Builder.build()",[95,27140,20639],{},[95,27142,9905],{}," constructor. Code outside both classes still can't touch either one's ",[95,27145,9905],{}," fields.",[15,27148,27149,27150,27153,27154,27157,27158,27160],{},"(Java also has ",[494,27151,27152],{},"non-static"," nested classes, called ",[25,27155,27156],{},"inner classes",", where every instance is tied to one specific instance of the outer class — the Builder Pattern only ever needs the ",[95,27159,179],{}," kind shown here, so that's the only kind this course covers.)",[69,27162,27164,27165,27168],{"id":27163},"the-fluent-chain-why-return-this-matters","The Fluent Chain: Why ",[95,27166,27167],{},"return this;"," Matters",[15,27170,27171,27172,27174,27175,27177,27178,27180,27181,27184,27185,27187,27188,79],{},"Every ",[95,27173,26822],{}," method ends with ",[95,27176,27167],{}," — returning the same builder object it was just called on. That's exactly what makes chaining possible: each call's result is another ",[95,27179,26822],{},", ready for the next call in the chain, all the way until ",[95,27182,27183],{},".build()"," finally produces the real ",[95,27186,20639],{},". This style (a method call chain, each step returning the object it was called on) is called a ",[25,27189,27190],{},"fluent interface",[69,27192,27194],{"id":27193},"why-the-result-is-safer-not-just-prettier","Why the Result Is Safer, Not Just Prettier",[19,27196,27197,27200,27203,27212],{},[22,27198,27199],{},"Every setting has a readable name at the call site, instead of an anonymous position in an argument list.",[22,27201,27202],{},"Optional settings simply aren't called, rather than needing a separate constructor overload for every combination.",[22,27204,27205,27206,27208,27209,27211],{},"The final object (",[95,27207,20639],{},") is typically built as immutable — every field is ",[95,27210,381],{}," and set exactly once, inside the private constructor, from the builder's already-finished values.",[22,27213,27214,27216,27217,27220,27221,27224,27225,27228],{},[95,27215,26826],{}," can also validate before constructing the final object — for example, throwing an ",[95,27218,27219],{},"IllegalArgumentException"," (Ch.12) if ",[95,27222,27223],{},"minRPM"," ended up greater than ",[95,27226,27227],{},"maxRPM"," — instead of quietly handing back a nonsensical configuration.",[69,27230,27232],{"id":27231},"real-patterns-this-mirrors-in-wpilib","Real Patterns This Mirrors in WPILib",[15,27234,27235,27236,27238],{},"Several real WPILib classes already use builder-like chaining, even without a nested ",[95,27237,26822],{}," class:",[104,27240,27242],{"className":106,"code":27241,"language":108,"meta":48,"style":48},"TrajectoryConfig config = new TrajectoryConfig(maxVelocity, maxAccel)\n    .setKinematics(driveKinematics)\n    .addConstraint(voltageConstraint);\n",[95,27243,27244,27249,27254],{"__ignoreMap":48},[112,27245,27246],{"class":114,"line":115},[112,27247,27248],{},"TrajectoryConfig config = new TrajectoryConfig(maxVelocity, maxAccel)\n",[112,27250,27251],{"class":114,"line":49},[112,27252,27253],{},"    .setKinematics(driveKinematics)\n",[112,27255,27256],{"class":114,"line":126},[112,27257,27258],{},"    .addConstraint(voltageConstraint);\n",[15,27260,27261,27262,27265,27266,27269,27270,27273,27274,79],{},"Commands v3 (Ch.25) leans on the same idea even harder — building a ",[95,27263,27264],{},"Command"," is itself a staged builder chain, where each stage only offers the methods legal to call next: ",[95,27267,27268],{},"Command.sequence(intake, shoot).named(\"Auto\")"," builds a bigger command out of smaller ones, and ",[95,27271,27272],{},"Command.requiring(drive, arm).executing(coroutine -> ...).named(\"Reach and Drive\")"," is a builder whose required mechanisms are locked in before you can even call ",[95,27275,27276],{},".executing(...)",[69,27278,27280],{"id":27279},"when-not-to-reach-for-a-builder","When Not to Reach for a Builder",[15,27282,27283],{},"A builder is genuine overhead — a whole extra nested class — that only pays for itself once a constructor's parameter list gets long or has several optional pieces. For a class with 2-3 simple, always-required parameters, a plain constructor (or, per Ch.21, a static factory method) is simpler and should be preferred.",[69,27285,462],{"id":461},[19,27287,27288,27313,27324],{},[22,27289,27290,27295,27296,27298,27299,27301,27302,27305,27306,27308,27309,27312],{},[25,27291,4719,27292,27294],{},[95,27293,27167],{}," in a builder method."," If the method still returns ",[95,27297,26822],{},", dropping ",[95,27300,27167],{}," gives a ",[95,27303,27304],{},"missing return statement"," compile error right there. If its return type was also changed to ",[95,27307,183],{},", the error shows up one call later instead: the next call in the chain fails with ",[95,27310,27311],{},"void cannot be dereferenced",", since there's nothing to call it on.",[22,27314,27315,27321,27322,79],{},[25,27316,27317,27318,27320],{},"Making the target class's constructor ",[95,27319,175],{}," alongside the builder."," That defeats the pattern's purpose — callers should only ever construct the object through the builder, which is why the real constructor stays ",[95,27323,9905],{},[22,27325,27326,27329],{},[25,27327,27328],{},"Reaching for a builder on a simple, 2-3-parameter class."," That's exactly the case the pattern isn't meant for — the extra ceremony isn't worth it there.",[69,27331,501],{"id":500},[19,27333,27334,27337,27348,27357,27364],{},[22,27335,27336],{},"The Builder Pattern separates step-by-step construction from a class's actual usage, avoiding \"constructor hell\" (many same-typed or optional parameters).",[22,27338,27339,27340,27342,27343,27345,27346,79],{},"A builder is a nested ",[95,27341,179],{}," class collecting settings via named, chainable methods (each returning ",[95,27344,3132],{}," — a fluent interface), finishing with ",[95,27347,26826],{},[22,27349,27350,27351,27353,27354,27356],{},"The target class's real constructor is ",[95,27352,9905],{},", taking the finished builder and copying its values into ",[95,27355,381],{}," fields — producing an immutable, safely-configured result.",[22,27358,27359,27360,27363],{},"Real WPILib classes (",[95,27361,27362],{},"TrajectoryConfig",") and Commands v3's staged builders (Ch.25) already use this same chaining idea.",[22,27365,27366],{},"Skip the builder for simple classes with few, always-required parameters — a constructor or static factory (Ch.21) is simpler there.",[15,27368,544,27369,548,27371,27374,27375,27377],{},[95,27370,17008],{},[95,27372,27373],{},"team-5817-training\u002Fdesign-patterns\u002Fbuilder.md"," (T5817 30.1)\n",[25,27376,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 8 (\"The Builder Pattern\") — MotorConfig fluent-builder example",[554,27379,556],{},{"title":48,"searchDepth":49,"depth":49,"links":27381},[27382,27383,27384,27385,27386,27388,27389,27390,27391,27392],{"id":26785,"depth":49,"text":26786},{"id":26804,"depth":49,"text":26805},{"id":26886,"depth":49,"text":26887},{"id":27072,"depth":49,"text":27073},{"id":27163,"depth":49,"text":27387},"The Fluent Chain: Why return this; Matters",{"id":27193,"depth":49,"text":27194},{"id":27231,"depth":49,"text":27232},{"id":27279,"depth":49,"text":27280},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":27394,"status":570},"22 — The Builder Pattern (T5817 30.1)","\u002Fshockwave-curriculum\u002Flessons\u002Fch22-the-builder-pattern\u002F22-the-builder-pattern",{"title":26777,"description":48},"shockwave-curriculum\u002Flessons\u002Fch22-the-builder-pattern\u002F22-the-builder-pattern","GBcAqVJVGw5OxlN9L281xzfeMbMDwDy-lJxo31HiJac",{"id":27400,"title":27401,"body":27402,"description":27409,"extension":51,"meta":28249,"navigation":55,"path":28251,"seo":28252,"stem":28253,"__hash__":28254},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch23-encapsulation-and-final\u002F23.1-scope-and-access.md","Access, final, and Immutability",{"type":8,"value":27403,"toc":28239},[27404,27407,27410,27414,27422,27459,27540,27551,27557,27562,27570,27598,27610,27655,27668,27676,27734,27751,27764,27789,27798,27826,27830,27836,27881,27916,27923,27951,27961,27965,27972,28021,28041,28080,28084,28087,28119,28121,28159,28161,28211,28237],[11,27405,27401],{"id":27406},"access-final-and-immutability",[15,27408,27409],{},"Lesson 7.2 already covered where a variable lives — class, method, or block scope — and what happens when a local variable or parameter shadows a field. This lesson builds on that background rather than repeating it: it's about two different questions. Who, outside a class, is allowed to touch a piece of its data? And what can be guaranteed to never change once it's set?",[69,27411,27413],{"id":27412},"access-modifiers-four-levels","Access Modifiers: Four Levels",[15,27415,27416,27417,537,27419,27421],{},"Java actually has four access levels, not two. ",[95,27418,175],{},[95,27420,9905],{}," are the ones used everywhere so far; the other two sit in between:",[104,27423,27425],{"className":106,"code":27424,"language":108,"meta":48,"style":48},"public class Intake\n{\n    public String status;        \u002F\u002F reachable from anywhere\n    protected double maxSpeed;   \u002F\u002F reachable from the same package, or any subclass\n    double gearRatio;            \u002F\u002F no modifier — reachable only from the same package\n    private boolean calibrated;  \u002F\u002F reachable only from inside Intake itself\n}\n",[95,27426,27427,27431,27435,27440,27445,27450,27455],{"__ignoreMap":48},[112,27428,27429],{"class":114,"line":115},[112,27430,9796],{},[112,27432,27433],{"class":114,"line":49},[112,27434,123],{},[112,27436,27437],{"class":114,"line":126},[112,27438,27439],{},"    public String status;        \u002F\u002F reachable from anywhere\n",[112,27441,27442],{"class":114,"line":132},[112,27443,27444],{},"    protected double maxSpeed;   \u002F\u002F reachable from the same package, or any subclass\n",[112,27446,27447],{"class":114,"line":138},[112,27448,27449],{},"    double gearRatio;            \u002F\u002F no modifier — reachable only from the same package\n",[112,27451,27452],{"class":114,"line":144},[112,27453,27454],{},"    private boolean calibrated;  \u002F\u002F reachable only from inside Intake itself\n",[112,27456,27457],{"class":114,"line":150},[112,27458,153],{},[3819,27460,27461,27480],{},[3822,27462,27463],{},[3825,27464,27465,27468,27471,27474,27477],{},[3828,27466,27467],{},"Modifier",[3828,27469,27470],{},"Same class",[3828,27472,27473],{},"Same package",[3828,27475,27476],{},"Subclass (different package)",[3828,27478,27479],{},"Everywhere",[3838,27481,27482,27496,27510,27526],{},[3825,27483,27484,27488,27490,27492,27494],{},[3843,27485,27486],{},[95,27487,175],{},[3843,27489,24634],{},[3843,27491,24634],{},[3843,27493,24634],{},[3843,27495,24634],{},[3825,27497,27498,27502,27504,27506,27508],{},[3843,27499,27500],{},[95,27501,16738],{},[3843,27503,24634],{},[3843,27505,24634],{},[3843,27507,24634],{},[3843,27509,24649],{},[3825,27511,27512,27518,27520,27522,27524],{},[3843,27513,27514,27517],{},[494,27515,27516],{},"(none)"," — package-private",[3843,27519,24634],{},[3843,27521,24634],{},[3843,27523,24649],{},[3843,27525,24649],{},[3825,27527,27528,27532,27534,27536,27538],{},[3843,27529,27530],{},[95,27531,9905],{},[3843,27533,24634],{},[3843,27535,24649],{},[3843,27537,24649],{},[3843,27539,24649],{},[15,27541,27542,27544,27545,27547,27548,27550],{},[95,27543,16738],{}," came up briefly in Lesson 17.2: it's what lets a subclass reach a superclass's member directly, without going through a getter — this table is the full picture, including package-private (no keyword at all, the default when a field or class has none of the other three). This course keeps fields ",[95,27546,9905],{}," and reaches them through getters\u002Fsetters or ",[95,27549,20858],{},", but real WPILib code uses all four.",[69,27552,27554,27556],{"id":27553},"final-not-just-for-fields",[95,27555,381],{},": Not Just for Fields",[15,27558,27559,27561],{},[95,27560,381],{}," can mark a local variable, a parameter, a field, a method, or a whole class — and it means something related but slightly different in each place.",[15,27563,27564,1534,27567,27569],{},[25,27565,27566],{},"Locals and parameters:",[95,27568,381],{}," local variable or parameter can be assigned exactly once, same as a field:",[104,27571,27573],{"className":106,"code":27572,"language":108,"meta":48,"style":48},"public double clamp(final double target, double limit)\n{\n    \u002F\u002F target = -target; would be a compile error here — target is final\n    return Math.min(target, limit);\n}\n",[95,27574,27575,27580,27584,27589,27594],{"__ignoreMap":48},[112,27576,27577],{"class":114,"line":115},[112,27578,27579],{},"public double clamp(final double target, double limit)\n",[112,27581,27582],{"class":114,"line":49},[112,27583,123],{},[112,27585,27586],{"class":114,"line":126},[112,27587,27588],{},"    \u002F\u002F target = -target; would be a compile error here — target is final\n",[112,27590,27591],{"class":114,"line":132},[112,27592,27593],{},"    return Math.min(target, limit);\n",[112,27595,27596],{"class":114,"line":138},[112,27597,153],{},[15,27599,27600,1534,27603,27605,27606,27609],{},[25,27601,27602],{},"Fields, and the blank final rule:",[95,27604,381],{}," field doesn't have to be given a value in its declaration — it can stay ",[494,27607,27608],{},"blank"," there, as long as every constructor assigns it exactly once, on every path through that constructor:",[104,27611,27613],{"className":106,"code":27612,"language":108,"meta":48,"style":48},"class BatteryMonitor\n{\n    private final String label;   \u002F\u002F no initializer here — that's legal\n\n    public BatteryMonitor(String label)\n    {\n        this.label = label;       \u002F\u002F as long as every constructor assigns it exactly once\n    }\n}\n",[95,27614,27615,27620,27624,27629,27633,27638,27642,27647,27651],{"__ignoreMap":48},[112,27616,27617],{"class":114,"line":115},[112,27618,27619],{},"class BatteryMonitor\n",[112,27621,27622],{"class":114,"line":49},[112,27623,123],{},[112,27625,27626],{"class":114,"line":126},[112,27627,27628],{},"    private final String label;   \u002F\u002F no initializer here — that's legal\n",[112,27630,27631],{"class":114,"line":132},[112,27632,907],{"emptyLinePlaceholder":55},[112,27634,27635],{"class":114,"line":138},[112,27636,27637],{},"    public BatteryMonitor(String label)\n",[112,27639,27640],{"class":114,"line":144},[112,27641,135],{},[112,27643,27644],{"class":114,"line":150},[112,27645,27646],{},"        this.label = label;       \u002F\u002F as long as every constructor assigns it exactly once\n",[112,27648,27649],{"class":114,"line":2276},[112,27650,147],{},[112,27652,27653],{"class":114,"line":2282},[112,27654,153],{},[15,27656,27657,27658,27660,27661,27664,27665,27667],{},"Leave a blank ",[95,27659,381],{}," field unassigned in some constructor, and it's a compile error — ",[95,27662,27663],{},"variable label might not have been initialized"," — not a ",[95,27666,4645],{}," at runtime.",[15,27669,27670,1534,27673,27675],{},[25,27671,27672],{},"Methods:",[95,27674,381],{}," method can't be overridden by a subclass, full stop:",[104,27677,27679],{"className":106,"code":27678,"language":108,"meta":48,"style":48},"class RobotPart\n{\n    public final String getName() { return name; }\n    \u002F\u002F ...\n}\n\nclass Intake extends RobotPart\n{\n    @Override\n    public String getName() { return \"Intake\"; }\n    \u002F\u002F COMPILE ERROR — getName() is final in RobotPart\n}\n",[95,27680,27681,27686,27690,27695,27699,27703,27707,27712,27716,27720,27725,27730],{"__ignoreMap":48},[112,27682,27683],{"class":114,"line":115},[112,27684,27685],{},"class RobotPart\n",[112,27687,27688],{"class":114,"line":49},[112,27689,123],{},[112,27691,27692],{"class":114,"line":126},[112,27693,27694],{},"    public final String getName() { return name; }\n",[112,27696,27697],{"class":114,"line":132},[112,27698,14871],{},[112,27700,27701],{"class":114,"line":138},[112,27702,153],{},[112,27704,27705],{"class":114,"line":144},[112,27706,907],{"emptyLinePlaceholder":55},[112,27708,27709],{"class":114,"line":150},[112,27710,27711],{},"class Intake extends RobotPart\n",[112,27713,27714],{"class":114,"line":2276},[112,27715,123],{},[112,27717,27718],{"class":114,"line":2282},[112,27719,21735],{},[112,27721,27722],{"class":114,"line":2288},[112,27723,27724],{},"    public String getName() { return \"Intake\"; }\n",[112,27726,27727],{"class":114,"line":5760},[112,27728,27729],{},"    \u002F\u002F COMPILE ERROR — getName() is final in RobotPart\n",[112,27731,27732],{"class":114,"line":5766},[112,27733,153],{},[15,27735,27736,1534,27739,27741,27742,27744,27745,27747,27748,27750],{},[25,27737,27738],{},"Classes:",[95,27740,381],{}," class can't be extended by anything, anywhere — ",[95,27743,361],{}," is one, which is why ",[95,27746,23132],{}," never compiles. Records (below) are implicitly ",[95,27749,381],{}," too.",[15,27752,27753,27756,27757,27759,27760,27763],{},[25,27754,27755],{},"Effectively final:"," a local variable captured by a lambda (Lesson 19.1) doesn't have to be declared ",[95,27758,381],{},", but it does have to ",[494,27761,27762],{},"behave"," like one — never reassigned anywhere after its first assignment, anywhere in the method:",[104,27765,27767],{"className":106,"code":27766,"language":108,"meta":48,"style":48},"double baseSpeed = 0.5;\nbaseSpeed = 0.6;\nRunnable r = () -> System.out.println(baseSpeed);\n\u002F\u002F COMPILE ERROR — baseSpeed isn't effectively final\n",[95,27768,27769,27774,27779,27784],{"__ignoreMap":48},[112,27770,27771],{"class":114,"line":115},[112,27772,27773],{},"double baseSpeed = 0.5;\n",[112,27775,27776],{"class":114,"line":49},[112,27777,27778],{},"baseSpeed = 0.6;\n",[112,27780,27781],{"class":114,"line":126},[112,27782,27783],{},"Runnable r = () -> System.out.println(baseSpeed);\n",[112,27785,27786],{"class":114,"line":132},[112,27787,27788],{},"\u002F\u002F COMPILE ERROR — baseSpeed isn't effectively final\n",[15,27790,27791,27792,27795,27796,79],{},"That reassignment on the line before disqualifies ",[95,27793,27794],{},"baseSpeed"," the moment the lambda tries to capture it: ",[95,27797,25138],{},[15,27799,27800,27801,27804,27805,27808,27809,27811,27812,322,27815,27818,27819,27821,27822,27825],{},"On an object reference, all of this only ever locks ",[494,27802,27803],{},"the reference itself"," — a ",[95,27806,27807],{},"final Encoder armEncoder = new Encoder(0, 1);"," can never be pointed at a different ",[95,27810,3139],{}," (WPILib's real ",[95,27813,27814],{},"org.wpilib.hardware.rotation.Encoder",[95,27816,27817],{},"getRate()"," reads its current rate), but nothing about ",[95,27820,381],{}," stops ",[95,27823,27824],{},"armEncoder","'s own internal state from changing as it spins. That gap between \"the reference can't change\" and \"nothing about the object can change\" is exactly what the rest of this lesson is about.",[69,27827,27829],{"id":27828},"encapsulation-leaks-defensive-copies","Encapsulation Leaks: Defensive Copies",[15,27831,27832,27833,27835],{},"Marking a field ",[95,27834,9905],{}," isn't automatically enough to protect it — a getter that hands back a direct reference to a mutable field leaks the class's internal state anyway:",[104,27837,27839],{"className":106,"code":27838,"language":108,"meta":48,"style":48},"class PitNotes\n{\n    private final ArrayList\u003CString> notes = new ArrayList\u003CString>();\n\n    public ArrayList\u003CString> getNotes()\n    {\n        return notes; \u002F\u002F leak — the caller now holds the SAME list object\n    }\n}\n",[95,27840,27841,27846,27850,27855,27859,27864,27868,27873,27877],{"__ignoreMap":48},[112,27842,27843],{"class":114,"line":115},[112,27844,27845],{},"class PitNotes\n",[112,27847,27848],{"class":114,"line":49},[112,27849,123],{},[112,27851,27852],{"class":114,"line":126},[112,27853,27854],{},"    private final ArrayList\u003CString> notes = new ArrayList\u003CString>();\n",[112,27856,27857],{"class":114,"line":132},[112,27858,907],{"emptyLinePlaceholder":55},[112,27860,27861],{"class":114,"line":138},[112,27862,27863],{},"    public ArrayList\u003CString> getNotes()\n",[112,27865,27866],{"class":114,"line":144},[112,27867,135],{},[112,27869,27870],{"class":114,"line":150},[112,27871,27872],{},"        return notes; \u002F\u002F leak — the caller now holds the SAME list object\n",[112,27874,27875],{"class":114,"line":2276},[112,27876,147],{},[112,27878,27879],{"class":114,"line":2282},[112,27880,153],{},[15,27882,27883,27884,1291,27887,537,27889,27891,27892,27895,27896,322,27899,27902,27903,27905,27906,27908,27909,27911,27912,27915],{},"Even though ",[95,27885,27886],{},"notes",[95,27888,9905],{},[95,27890,381],{},", this getter hands out a reference to the exact list ",[95,27893,27894],{},"PitNotes"," uses internally. Anything the caller does to that returned list — ",[95,27897,27898],{},"getNotes().clear()",[95,27900,27901],{},"getNotes().add(...)"," — changes ",[95,27904,27894],{},"'s own data, without ever calling one of ",[95,27907,27894],{},"'s own methods. ",[95,27910,9905],{}," only stops outside code from writing ",[95,27913,27914],{},"somePitNotes.notes"," directly; it does nothing once a reference to the same object escapes through a getter.",[15,27917,27918,27919,27922],{},"The fix is a ",[25,27920,27921],{},"defensive copy"," — hand back a new object with the same contents, instead of the original:",[104,27924,27926],{"className":106,"code":27925,"language":108,"meta":48,"style":48},"public List\u003CString> getNotes()\n{\n    \u002F\u002F a defensive copy — an unmodifiable snapshot, not the real list\n    return List.copyOf(notes);\n}\n",[95,27927,27928,27933,27937,27942,27947],{"__ignoreMap":48},[112,27929,27930],{"class":114,"line":115},[112,27931,27932],{},"public List\u003CString> getNotes()\n",[112,27934,27935],{"class":114,"line":49},[112,27936,123],{},[112,27938,27939],{"class":114,"line":126},[112,27940,27941],{},"    \u002F\u002F a defensive copy — an unmodifiable snapshot, not the real list\n",[112,27943,27944],{"class":114,"line":132},[112,27945,27946],{},"    return List.copyOf(notes);\n",[112,27948,27949],{"class":114,"line":138},[112,27950,153],{},[15,27952,27953,27954,27956,27957,27960],{},"Now the caller gets its own snapshot; mutating it can't touch ",[95,27955,27894],{},"'s real data at all, and ",[95,27958,27959],{},"List.copyOf(...)"," refuses to be modified even by accident.",[69,27962,27964],{"id":27963},"records-immutable-data-built-in","Records: Immutable Data, Built In",[15,27966,27967,27968,27971],{},"When a class is really just a bundle of values — no behavior beyond holding them — Java's ",[95,27969,27970],{},"record"," (16+) writes the immutable version of it for you:",[104,27973,27975],{"className":106,"code":27974,"language":108,"meta":48,"style":48},"public record Reading(double volts, double timestampSeconds)\n{\n    public Reading\n    {\n        if (volts \u003C 0)\n        {\n            throw new IllegalArgumentException(\"volts can't be negative\");\n        }\n    }\n}\n",[95,27976,27977,27982,27986,27991,27995,28000,28004,28009,28013,28017],{"__ignoreMap":48},[112,27978,27979],{"class":114,"line":115},[112,27980,27981],{},"public record Reading(double volts, double timestampSeconds)\n",[112,27983,27984],{"class":114,"line":49},[112,27985,123],{},[112,27987,27988],{"class":114,"line":126},[112,27989,27990],{},"    public Reading\n",[112,27992,27993],{"class":114,"line":132},[112,27994,135],{},[112,27996,27997],{"class":114,"line":138},[112,27998,27999],{},"        if (volts \u003C 0)\n",[112,28001,28002],{"class":114,"line":144},[112,28003,11303],{},[112,28005,28006],{"class":114,"line":150},[112,28007,28008],{},"            throw new IllegalArgumentException(\"volts can't be negative\");\n",[112,28010,28011],{"class":114,"line":2276},[112,28012,11313],{},[112,28014,28015],{"class":114,"line":2282},[112,28016,147],{},[112,28018,28019],{"class":114,"line":2288},[112,28020,153],{},[104,28022,28024],{"className":106,"code":28023,"language":108,"meta":48,"style":48},"Reading r = new Reading(12.6, 41.2);\nSystem.out.println(r.volts());   \u002F\u002F an accessor named after the field, not getVolts()\nSystem.out.println(r);           \u002F\u002F Reading[volts=12.6, timestampSeconds=41.2]\n",[95,28025,28026,28031,28036],{"__ignoreMap":48},[112,28027,28028],{"class":114,"line":115},[112,28029,28030],{},"Reading r = new Reading(12.6, 41.2);\n",[112,28032,28033],{"class":114,"line":49},[112,28034,28035],{},"System.out.println(r.volts());   \u002F\u002F an accessor named after the field, not getVolts()\n",[112,28037,28038],{"class":114,"line":126},[112,28039,28040],{},"System.out.println(r);           \u002F\u002F Reading[volts=12.6, timestampSeconds=41.2]\n",[15,28042,28043,28044,28047,28048,28051,28052,322,28055,28058,28059,28061,28062,322,28064,325,28066,28068,28069,28072,28073,28076,28077,28079],{},"One line — ",[95,28045,28046],{},"record Reading(double volts, double timestampSeconds)"," — generates ",[95,28049,28050],{},"private final"," fields for both, a constructor, read-only accessors (",[95,28053,28054],{},"volts()",[95,28056,28057],{},"timestampSeconds()",", no ",[95,28060,4956],{}," prefix), and working ",[95,28063,19530],{},[95,28065,19533],{},[95,28067,10318],{},", all for free. The block after the field list, called a ",[494,28070,28071],{},"compact constructor",", is optional — it runs before the fields are assigned, purely to validate the arguments (as above); no ",[95,28074,28075],{},"this.volts = volts;"," is written or needed there, since that assignment still happens automatically. A record is implicitly ",[95,28078,381],{}," — nothing can extend it.",[69,28081,28083],{"id":28082},"an-immutability-checklist","An Immutability Checklist",[15,28085,28086],{},"Pulling the pieces above together, a class is genuinely immutable once every one of these holds:",[19,28088,28089,28094,28097,28113],{},[22,28090,28091,28092,79],{},"Every field is ",[95,28093,28050],{},[22,28095,28096],{},"Nothing but a constructor (or compact constructor, for a record) ever assigns a field — no setters.",[22,28098,28099,28100,28102,28103,28106,28107,28109,28110,28112],{},"Any field that's itself a mutable type (an array, or a collection like ",[95,28101,12343],{},") is defensively copied going ",[494,28104,28105],{},"in",", through the constructor, and copied going ",[494,28108,17594],{},", through any getter — ",[95,28111,381],{}," alone only locks the reference, not the referenced object's own contents.",[22,28114,28115,28116,28118],{},"When the class is really just a bundle of values, reach for a ",[95,28117,27970],{}," first — it satisfies every bullet above by construction.",[69,28120,462],{"id":461},[19,28122,28123,28137,28149],{},[22,28124,28125,476,28128,28130,28131,3283,28133,28136],{},[25,28126,28127],{},"Returning a mutable field directly from a getter.",[95,28129,9905],{}," doesn't protect a field once a reference to it escapes through a getter — return a defensive copy (",[95,28132,27959],{},[95,28134,28135],{},"new ArrayList\u003C>(original)",") instead of the original object.",[22,28138,28139,28145,28146,28148],{},[25,28140,28141,28142,28144],{},"Leaving a blank ",[95,28143,381],{}," field unassigned on some constructor path."," Every constructor must assign it exactly once — missing it on even one path is a compile error, not a ",[95,28147,4645],{}," waiting to happen.",[22,28150,28151,28154,28155,28158],{},[25,28152,28153],{},"Reassigning a variable after using it in a lambda."," A captured local only has to be ",[494,28156,28157],{},"effectively"," final, but reassigning it anywhere in the method — even after the lambda — breaks that, and the lambda's capture is what fails to compile.",[69,28160,501],{"id":500},[19,28162,28163,28177,28182,28188,28193,28208],{},[22,28164,28165,28166,322,28168,28170,28171,28173,28174,28176],{},"Java has four access levels — ",[95,28167,175],{},[95,28169,16738],{},", package-private (no modifier), and ",[95,28172,9905],{}," — differing in whether same-package code and subclasses in other packages can reach a member; Lesson 17.2 introduced ",[95,28175,16738],{},", this table is the full comparison.",[22,28178,28179,28181],{},[95,28180,381],{}," means \"assign exactly once\" for locals, parameters, and fields (with the blank-final rule allowing one later assignment per constructor); on a method it blocks overriding, and on a class it blocks extending entirely.",[22,28183,28184,28185,28187],{},"A lambda can only capture a local variable that's final or ",[494,28186,28157],{}," final — never reassigned anywhere in the method.",[22,28189,405,28190,28192],{},[95,28191,9905],{}," field isn't automatically safe from outside mutation — a getter that hands back the same mutable object leaks it; return a defensive copy instead.",[22,28194,405,28195,28197,28198,28200,28201,322,28203,325,28205,28207],{},[95,28196,27970],{}," generates an immutable, implicitly-",[95,28199,381],{}," class — fields, accessors, ",[95,28202,19530],{},[95,28204,19533],{},[95,28206,10318],{}," — from one line, with an optional compact constructor for validation.",[22,28209,28210],{},"Scope and shadowing (where a variable lives, and what happens when a local name matches a field's) were covered in Lesson 7.2.",[15,28212,544,28213,548,28215,28218,28219,28221,28222,28224,28225,2150,28227,28229,28230,28232,28233,28236],{},[95,28214,547],{},[95,28216,28217],{},"unit-3-class-creation\u002F3.08-scope-and-access.md"," (CSA 3.8)\n",[25,28220,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 9 (\"Encapsulation & Final\") — refocused 2026-09-25 on access modifiers, ",[95,28223,381],{},", encapsulation leaks, and records (scope moved to Lesson 7.2); real-API check: ",[95,28226,27814],{},[95,28228,27817],{},"), allwpilib ",[95,28231,101],{}," commit ",[95,28234,28235],{},"e985b0fdfce935cb1484d4b9e8d1b98bd391bb51"," (2026-09-25)",[554,28238,556],{},{"title":48,"searchDepth":49,"depth":49,"links":28240},[28241,28242,28244,28245,28246,28247,28248],{"id":27412,"depth":49,"text":27413},{"id":27553,"depth":49,"text":28243},"final: Not Just for Fields",{"id":27828,"depth":49,"text":27829},{"id":27963,"depth":49,"text":27964},{"id":28082,"depth":49,"text":28083},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":28250,"status":570},"23.1 — Scope and Access (CSA 3.8)","\u002Fshockwave-curriculum\u002Flessons\u002Fch23-encapsulation-and-final\u002F1-scope-and-access",{"title":27401,"description":27409},"shockwave-curriculum\u002Flessons\u002Fch23-encapsulation-and-final\u002F23.1-scope-and-access","MtH5iiPPcXI07nKZ2L-x4LdC-EI7o93w4BZ6C5VpQ0M",{"id":28256,"title":28257,"body":28258,"description":48,"extension":51,"meta":28832,"navigation":55,"path":28834,"seo":28835,"stem":28836,"__hash__":28837},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch24-optional-avoiding-null-pointer-exceptions\u002F24-optional-avoiding-null-pointer-exceptions.md","Optional: Avoiding Null Pointer Exceptions",{"type":8,"value":28259,"toc":28822},[28260,28263,28267,28286,28296,28300,28313,28354,28361,28365,28403,28415,28419,28476,28507,28533,28537,28564,28579,28596,28600,28617,28642,28656,28665,28690,28696,28698,28740,28742,28809,28820],[11,28261,28257],{"id":28262},"optional-avoiding-null-pointer-exceptions",[69,28264,28266],{"id":28265},"the-null-problem","The Null Problem",[15,28268,28269,28270,28272,28273,28275,28276,28279,28280,28282,28283,28285],{},"Returning ",[95,28271,4645],{}," to mean \"there's no value here\" is one of the most common sources of bugs in any Java program — Tony Hoare, who introduced the null reference in 1965, later called it his \"billion-dollar mistake.\" The trouble is that ",[95,28274,4645],{}," is invisible in a method's signature: nothing about ",[95,28277,28278],{},"Pose2d getVisionPose()"," warns a caller that it might come back ",[95,28281,4645],{},", so it's easy to forget the check and get a ",[95,28284,4678],{}," (Ch.12\u002F13) instead.",[15,28287,28288,28289,28292,28293,28295],{},"The classic FRC case: a vision pose estimator can only report a robot position if a camera actually sees an AprilTag ",[494,28290,28291],{},"this frame"," — plenty of frames, it can't. Returning ",[95,28294,4645],{}," on those frames leaves every caller responsible for remembering to check first.",[69,28297,28299],{"id":28298},"optional-making-might-be-absent-part-of-the-type","Optional: Making \"Might Be Absent\" Part of the Type",[15,28301,28302,28305,28306,28309,28310,28312],{},[95,28303,28304],{},"java.util.Optional\u003CT>"," is a container that either holds a value, or is explicitly ",[25,28307,28308],{},"empty"," — and unlike ",[95,28311,4645],{},", that possibility is written directly into the method's return type:",[104,28314,28316],{"className":106,"code":28315,"language":108,"meta":48,"style":48},"public Optional\u003CPose2d> getPose()\n{\n    if (!hasTargetThisFrame())\n    {\n        return Optional.empty();       \u002F\u002F explicitly \"no value\" — not null\n    }\n    return Optional.of(currentPose);   \u002F\u002F wraps a real, non-null value\n}\n",[95,28317,28318,28323,28327,28332,28336,28341,28345,28350],{"__ignoreMap":48},[112,28319,28320],{"class":114,"line":115},[112,28321,28322],{},"public Optional\u003CPose2d> getPose()\n",[112,28324,28325],{"class":114,"line":49},[112,28326,123],{},[112,28328,28329],{"class":114,"line":126},[112,28330,28331],{},"    if (!hasTargetThisFrame())\n",[112,28333,28334],{"class":114,"line":132},[112,28335,135],{},[112,28337,28338],{"class":114,"line":138},[112,28339,28340],{},"        return Optional.empty();       \u002F\u002F explicitly \"no value\" — not null\n",[112,28342,28343],{"class":114,"line":144},[112,28344,147],{},[112,28346,28347],{"class":114,"line":150},[112,28348,28349],{},"    return Optional.of(currentPose);   \u002F\u002F wraps a real, non-null value\n",[112,28351,28352],{"class":114,"line":2276},[112,28353,153],{},[15,28355,28356,28357,28360],{},"Just by reading ",[95,28358,28359],{},"Optional\u003CPose2d> getPose()","'s signature, a caller already knows the pose might not be there this frame — the type itself documents it, instead of relying on a comment or tribal knowledge.",[69,28362,28364],{"id":28363},"creating-an-optional","Creating an Optional",[104,28366,28368],{"className":106,"code":28367,"language":108,"meta":48,"style":48},"Optional\u003CPose2d> empty = Optional.empty();       \u002F\u002F definitely no value\n\n\u002F\u002F wraps a value — throws immediately if currentPose is null\nOptional\u003CPose2d> present = Optional.of(currentPose);\n\n\u002F\u002F empty if currentPose is null, present otherwise\nOptional\u003CPose2d> maybe = Optional.ofNullable(currentPose);\n",[95,28369,28370,28375,28379,28384,28389,28393,28398],{"__ignoreMap":48},[112,28371,28372],{"class":114,"line":115},[112,28373,28374],{},"Optional\u003CPose2d> empty = Optional.empty();       \u002F\u002F definitely no value\n",[112,28376,28377],{"class":114,"line":49},[112,28378,907],{"emptyLinePlaceholder":55},[112,28380,28381],{"class":114,"line":126},[112,28382,28383],{},"\u002F\u002F wraps a value — throws immediately if currentPose is null\n",[112,28385,28386],{"class":114,"line":132},[112,28387,28388],{},"Optional\u003CPose2d> present = Optional.of(currentPose);\n",[112,28390,28391],{"class":114,"line":138},[112,28392,907],{"emptyLinePlaceholder":55},[112,28394,28395],{"class":114,"line":144},[112,28396,28397],{},"\u002F\u002F empty if currentPose is null, present otherwise\n",[112,28399,28400],{"class":114,"line":150},[112,28401,28402],{},"Optional\u003CPose2d> maybe = Optional.ofNullable(currentPose);\n",[15,28404,28405,28408,28409,28411,28412,28414],{},[95,28406,28407],{},"Optional.of(...)"," is a deliberate safety check: if you accidentally pass it a ",[95,28410,4645],{},", it throws right away — better to fail loudly at the source than to silently wrap a ",[95,28413,4645],{}," and have it surface as a confusing failure somewhere else later.",[69,28416,28418],{"id":28417},"handling-both-cases-honestly","Handling Both Cases Honestly",[104,28420,28422],{"className":106,"code":28421,"language":108,"meta":48,"style":48},"Optional\u003CPose2d> visionPose = vision.getPose();\n\n\u002F\u002F Run logic only when a value exists\nvisionPose.ifPresent(pose -> estimator.addVisionMeasurement(pose, timestamp));\n\n\u002F\u002F Or supply a fallback value for the empty case\nPose2d fallbackPose = visionPose.orElse(lastKnownPose);\n\n\u002F\u002F Or throw a specific exception if a value was truly required\nPose2d requiredPose = visionPose.orElseThrow(\n    () -> new IllegalStateException(\"No vision pose\"));\n",[95,28423,28424,28429,28433,28438,28443,28447,28452,28457,28461,28466,28471],{"__ignoreMap":48},[112,28425,28426],{"class":114,"line":115},[112,28427,28428],{},"Optional\u003CPose2d> visionPose = vision.getPose();\n",[112,28430,28431],{"class":114,"line":49},[112,28432,907],{"emptyLinePlaceholder":55},[112,28434,28435],{"class":114,"line":126},[112,28436,28437],{},"\u002F\u002F Run logic only when a value exists\n",[112,28439,28440],{"class":114,"line":132},[112,28441,28442],{},"visionPose.ifPresent(pose -> estimator.addVisionMeasurement(pose, timestamp));\n",[112,28444,28445],{"class":114,"line":138},[112,28446,907],{"emptyLinePlaceholder":55},[112,28448,28449],{"class":114,"line":144},[112,28450,28451],{},"\u002F\u002F Or supply a fallback value for the empty case\n",[112,28453,28454],{"class":114,"line":150},[112,28455,28456],{},"Pose2d fallbackPose = visionPose.orElse(lastKnownPose);\n",[112,28458,28459],{"class":114,"line":2276},[112,28460,907],{"emptyLinePlaceholder":55},[112,28462,28463],{"class":114,"line":2282},[112,28464,28465],{},"\u002F\u002F Or throw a specific exception if a value was truly required\n",[112,28467,28468],{"class":114,"line":2288},[112,28469,28470],{},"Pose2d requiredPose = visionPose.orElseThrow(\n",[112,28472,28473],{"class":114,"line":5760},[112,28474,28475],{},"    () -> new IllegalStateException(\"No vision pose\"));\n",[15,28477,28478,28481,28482,28485,28486,28489,28490,28492,28493,28496,28497,28499,28500,28502,28503,28506],{},[95,28479,28480],{},"ifPresent"," runs a lambda (Lesson 19.1) only if a value is actually there — nothing happens otherwise. ",[95,28483,28484],{},"orElse"," supplies a fallback value for the empty case. ",[95,28487,28488],{},"orElseThrow"," is for the rarer case where an empty ",[95,28491,18547],{}," really does mean something has gone wrong, and continuing anyway wouldn't make sense — passing it a lambda that builds the exception (rather than a bare ",[95,28494,28495],{},"new IllegalStateException(...)",") matters here: ",[95,28498,28488],{}," only constructs and throws that exception when the ",[95,28501,18547],{}," really is empty, instead of building it eagerly every time. (You'll also see ",[95,28504,28505],{},"orElseThrow(IllegalStateException::new)"," written as a constructor reference in other code — Lesson 19.1 has the full table of method-reference kinds, including that one.)",[15,28508,28509,28511,28512,28515,28516,28519,28520,17400,28523,28525,28526,28529,28530,28532],{},[95,28510,18547],{}," also has a few less common but genuinely useful methods: a no-argument ",[95,28513,28514],{},"orElseThrow()"," (throws ",[95,28517,28518],{},"NoSuchElementException"," when nothing more specific is needed), ",[95,28521,28522],{},"orElseGet(supplier)",[95,28524,28484],{},", but only computes its fallback value when it's actually needed, instead of always), and ",[95,28527,28528],{},"ifPresentOrElse(consumer, runnable)"," (runs one callback if a value is present, and a different one if it's empty — ",[95,28531,28480],{}," alone has no \"else\").",[69,28534,28536],{"id":28535},"the-one-pitfall-that-defeats-the-whole-point","The One Pitfall That Defeats the Whole Point",[15,28538,28539,28541,28542,28545,28546,28548,28549,28551,28552,28554,28555,28557,28558,28560,28561,28563],{},[95,28540,18547],{}," has an ",[95,28543,28544],{},"isPresent()"," check and a ",[95,28547,13052],{}," method that returns the wrapped value — but calling ",[95,28550,13052],{}," without checking ",[95,28553,28544],{}," first throws ",[95,28556,28518],{}," on an empty ",[95,28559,18547],{},", which is exactly the same class of crash ",[95,28562,18547],{}," exists to prevent, just under a different exception name:",[104,28565,28567],{"className":106,"code":28566,"language":108,"meta":48,"style":48},"\u002F\u002F never do this blind — this is a NullPointerException with extra steps\nPose2d uncheckedPose = visionPose.get();\n",[95,28568,28569,28574],{"__ignoreMap":48},[112,28570,28571],{"class":114,"line":115},[112,28572,28573],{},"\u002F\u002F never do this blind — this is a NullPointerException with extra steps\n",[112,28575,28576],{"class":114,"line":49},[112,28577,28578],{},"Pose2d uncheckedPose = visionPose.get();\n",[15,28580,28581,28582,9543,28584,28586,28587,322,28589,325,28591,28593,28594,79],{},"Even the safer ",[95,28583,28544],{},[95,28585,13052],{}," pairing is discouraged — it's really just a nested-null-check in disguise. ",[95,28588,28480],{},[95,28590,28484],{},[95,28592,28488],{}," all handle both cases directly, without ever needing to call bare ",[95,28595,13052],{},[69,28597,28599],{"id":28598},"filtering-and-transforming-a-brief-look","Filtering and Transforming (a Brief Look)",[15,28601,28602,28603,28605,28606,28609,28610,28613,28614,28616],{},"Beyond the core methods above, ",[95,28604,18547],{}," supports ",[95,28607,28608],{},"filter"," (keep the value only if it matches a condition, otherwise become empty) and ",[95,28611,28612],{},"map"," (transform the value, if present, into something else) — useful for chaining a couple of extra checks without falling back into nested ",[95,28615,2179],{}," statements:",[104,28618,28620],{"className":106,"code":28619,"language":108,"meta":48,"style":48},"visionPose\n    \u002F\u002F only proceed if the pose has a valid X coordinate\n    .filter(pose -> pose.getX() >= 0)\n    .ifPresent(pose -> estimator.addVisionMeasurement(pose, timestamp));\n",[95,28621,28622,28627,28632,28637],{"__ignoreMap":48},[112,28623,28624],{"class":114,"line":115},[112,28625,28626],{},"visionPose\n",[112,28628,28629],{"class":114,"line":49},[112,28630,28631],{},"    \u002F\u002F only proceed if the pose has a valid X coordinate\n",[112,28633,28634],{"class":114,"line":126},[112,28635,28636],{},"    .filter(pose -> pose.getX() >= 0)\n",[112,28638,28639],{"class":114,"line":132},[112,28640,28641],{},"    .ifPresent(pose -> estimator.addVisionMeasurement(pose, timestamp));\n",[15,28643,28644,28646,28647,28649,28650,28652,28653,28655],{},[95,28645,28612],{}," transforms the value inside an ",[95,28648,18547],{},", without ever having to check ",[95,28651,28544],{}," first — on an empty ",[95,28654,18547],{},", it just stays empty:",[104,28657,28659],{"className":106,"code":28658,"language":108,"meta":48,"style":48},"double dashboardX = visionPose.map(pose -> pose.getX()).orElse(0.0);\n",[95,28660,28661],{"__ignoreMap":48},[112,28662,28663],{"class":114,"line":115},[112,28664,28658],{},[15,28666,28667,28670,28671,28674,28675,28678,28679,28682,28683,28686,28687,28689],{},[95,28668,28669],{},"visionPose.map(pose -> pose.getX())"," turns an ",[95,28672,28673],{},"Optional\u003CPose2d>"," into an ",[95,28676,28677],{},"Optional\u003CDouble>"," — present with the X coordinate if ",[95,28680,28681],{},"visionPose"," had a value, empty otherwise — and ",[95,28684,28685],{},".orElse(0.0)"," then unwraps that down to a plain ",[95,28688,631],{}," either way.",[15,28691,28692,28693,28695],{},"These compose well for simple cases; genuinely complex chains of ",[95,28694,18547],{}," transformations are a more advanced topic than this curriculum covers in depth.",[69,28697,462],{"id":461},[19,28699,28700,28712,28724],{},[22,28701,28702,28708,28709,28711],{},[25,28703,13153,28704,28707],{},[95,28705,28706],{},".get()"," without checking first."," This throws on an empty ",[95,28710,18547],{},", defeating the entire purpose of using one.",[22,28713,28714,28719,28720,28723],{},[25,28715,6835,28716,28718],{},[95,28717,18547],{}," for every field or parameter, out of habit."," It's meant for genuinely optional ",[494,28721,28722],{},"results"," (especially return values) — not a blanket replacement for every reference type in a program.",[22,28725,28726,28733,28734,28737,28738,79],{},[25,28727,28728,28729,4029,28731,79],{},"Passing a ",[95,28730,4645],{},[95,28732,28407],{}," That throws immediately — use ",[95,28735,28736],{},"Optional.ofNullable(...)"," instead when the value genuinely might be ",[95,28739,4645],{},[69,28741,501],{"id":500},[19,28743,28744,28753,28770,28785,28795],{},[22,28745,28746,28749,28750,28752],{},[95,28747,28748],{},"Optional\u003CT>"," makes \"this might not have a value\" visible directly in a method's return type, instead of relying on an invisible, easy-to-forget ",[95,28751,4645],{}," check.",[22,28754,28755,28756,322,28759,28762,28763,28765,28766,28769],{},"Create one with ",[95,28757,28758],{},"Optional.empty()",[95,28760,28761],{},"Optional.of(value)"," (throws if ",[95,28764,4024],{}," is null), or ",[95,28767,28768],{},"Optional.ofNullable(value)"," (safe either way).",[22,28771,28772,28773,322,28776,3283,28779,28782,28783,28707],{},"Handle both cases with ",[95,28774,28775],{},"ifPresent(...)",[95,28777,28778],{},"orElse(fallback)",[95,28780,28781],{},"orElseThrow(...)"," — never call bare ",[95,28784,28706],{},[22,28786,28787,537,28789,28791,28792,28794],{},[95,28788,28608],{},[95,28790,28612],{}," let you chain a couple of extra conditions\u002Ftransformations without falling back into nested ",[95,28793,2179],{}," checks.",[22,28796,28797,28798,322,28800,28802,28803,28805,28806,28808],{},"Beyond the core methods: a no-argument ",[95,28799,28514],{},[95,28801,28522],{}," (lazy, unlike eager ",[95,28804,28484],{},"), and ",[95,28807,28528],{}," (a present\u002Fempty pair of callbacks) cover the less common cases.",[15,28810,544,28811,548,28813,28816,28817,28819],{},[95,28812,17008],{},[95,28814,28815],{},"oracle-java-tutorials\u002Foptional\u002Fjava8-optional.md"," (ORACLE 16.1)\n",[25,28818,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 9b (\"Optional: Maybe a Value\") — vision pose estimator example",[554,28821,556],{},{"title":48,"searchDepth":49,"depth":49,"links":28823},[28824,28825,28826,28827,28828,28829,28830,28831],{"id":28265,"depth":49,"text":28266},{"id":28298,"depth":49,"text":28299},{"id":28363,"depth":49,"text":28364},{"id":28417,"depth":49,"text":28418},{"id":28535,"depth":49,"text":28536},{"id":28598,"depth":49,"text":28599},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":28833,"status":570},"24 — Optional: Avoiding Null Pointer Exceptions (ORACLE 16.1) — renamed from \"Optional: Maybe a Value\" to disambiguate from optional method parameters; the deck's actual slide heading is unchanged","\u002Fshockwave-curriculum\u002Flessons\u002Fch24-optional-avoiding-null-pointer-exceptions\u002F24-optional-avoiding-null-pointer-exceptions",{"title":28257,"description":48},"shockwave-curriculum\u002Flessons\u002Fch24-optional-avoiding-null-pointer-exceptions\u002F24-optional-avoiding-null-pointer-exceptions","ClnAIgLcYqtgKZQYJbJDRFKtCmNYE2BBtKltjPLqKNM",{"id":28839,"title":28840,"body":28841,"description":48,"extension":51,"meta":29210,"navigation":55,"path":29213,"seo":29214,"stem":29215,"__hash__":29216},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.1-what-is-command-based-programming.md","What Is Command-Based Programming?",{"type":8,"value":28842,"toc":29201},[28843,28846,28850,28857,28871,28878,28882,28892,28907,28970,28979,28986,28990,28993,29021,29028,29073,29090,29094,29107,29111,29118,29120,29151,29153,29176,29199],[11,28844,28840],{"id":28845},"what-is-command-based-programming",[69,28847,28849],{"id":28848},"the-big-payoff-of-everything-so-far","The Big Payoff of Everything So Far",[15,28851,28852,28853,28856],{},"Every idea from Ch.17-24 — inheritance, interfaces, lambdas, the IO-Layer Pattern, static factories, builders — leads here. ",[25,28854,28855],{},"Command-based programming"," is WPILib's own official architecture pattern for structuring an entire robot's code. It's not the only way to write a robot program, but it's the one WPILib itself provides deep library support for, and the one most competitive FRC codebases are built around.",[15,28858,28859,28860,28863,28864,28866,28867,28870],{},"This chapter teaches ",[25,28861,28862],{},"Commands v3",", the version of the framework built for WPILib 2027 (package ",[95,28865,3062],{},"). Its older sibling, ",[25,28868,28869],{},"Commands v2",", is what most existing team code — including older code of our own — still uses. You'll write v3, but you'll read plenty of v2, so Lesson 25.7 ends with a short guide to recognizing it.",[15,28872,28873,28874,28877],{},"Commands v3 is still in alpha testing, so a few details may change before the season; the lessons flag the parts that are changing most. ",[25,28875,28876],{},"On Java 17:"," Commands v3 doesn't run at all — it's built on a JDK feature (continuations) that Java 17 doesn't have.",[69,28879,28881],{"id":28880},"declarative-not-imperative","Declarative, Not Imperative",[15,28883,28884,28885,28888,28889,28891],{},"Command-based is a ",[25,28886,28887],{},"declarative"," paradigm: you describe ",[494,28890,4416],{}," should happen under what condition, and the library handles checking that condition every single loop, on your behalf. Compare these two ways of saying \"extend the piston when a condition becomes true\":",[104,28893,28895],{"className":106,"code":28894,"language":108,"meta":48,"style":48},"\u002F\u002F Declarative (command-based): say what should happen, once\nnew Trigger(condition::get).onTrue(pneumatics.extendCommand());\n",[95,28896,28897,28902],{"__ignoreMap":48},[112,28898,28899],{"class":114,"line":115},[112,28900,28901],{},"\u002F\u002F Declarative (command-based): say what should happen, once\n",[112,28903,28904],{"class":114,"line":49},[112,28905,28906],{},"new Trigger(condition::get).onTrue(pneumatics.extendCommand());\n",[104,28908,28910],{"className":106,"code":28909,"language":108,"meta":48,"style":48},"\u002F\u002F Imperative (without command-based): manually track state every single loop\nif (condition.get())\n{\n    if (!pressed)\n    {\n        piston.set(FORWARD);\n        pressed = true;\n    }\n}\nelse\n{\n    pressed = false;\n}\n",[95,28911,28912,28917,28922,28926,28931,28935,28940,28945,28949,28953,28957,28961,28966],{"__ignoreMap":48},[112,28913,28914],{"class":114,"line":115},[112,28915,28916],{},"\u002F\u002F Imperative (without command-based): manually track state every single loop\n",[112,28918,28919],{"class":114,"line":49},[112,28920,28921],{},"if (condition.get())\n",[112,28923,28924],{"class":114,"line":126},[112,28925,123],{},[112,28927,28928],{"class":114,"line":132},[112,28929,28930],{},"    if (!pressed)\n",[112,28932,28933],{"class":114,"line":138},[112,28934,135],{},[112,28936,28937],{"class":114,"line":144},[112,28938,28939],{},"        piston.set(FORWARD);\n",[112,28941,28942],{"class":114,"line":150},[112,28943,28944],{},"        pressed = true;\n",[112,28946,28947],{"class":114,"line":2276},[112,28948,147],{},[112,28950,28951],{"class":114,"line":2282},[112,28952,153],{},[112,28954,28955],{"class":114,"line":2288},[112,28956,5131],{},[112,28958,28959],{"class":114,"line":5760},[112,28960,123],{},[112,28962,28963],{"class":114,"line":5766},[112,28964,28965],{},"    pressed = false;\n",[112,28967,28968],{"class":114,"line":5772},[112,28969,153],{},[15,28971,1866,28972,1291,28975,28978],{},[95,28973,28974],{},"FORWARD",[95,28976,28977],{},"DoubleSolenoid.Value.FORWARD",", brought in with a static import — Lesson 3.3.)",[15,28980,28981,28982,28985],{},"The declarative version is written once and never touched again; the imperative version requires you to manually manage a ",[95,28983,28984],{},"pressed"," flag correctly, forever, in every place a similar check is needed. Multiply that by dozens of buttons and sensors across a real robot, and the difference in maintainability is enormous.",[69,28987,28989],{"id":28988},"three-core-abstractions-mechanisms-commands-and-the-scheduler","Three Core Abstractions: Mechanisms, Commands, and the Scheduler",[15,28991,28992],{},"Command-based organizes an entire robot around three ideas:",[19,28994,28995,29007,29015],{},[22,28996,405,28997,28999,29000,29002,29003,29006],{},[25,28998,25778],{}," represents an independently-controlled piece of hardware (or group of hardware) — a drivetrain, an intake, a climber, even an LED strip. ",[95,29001,25778],{}," is an interface: your class ",[95,29004,29005],{},"implements Mechanism",". Ch.20's IO-Layer Pattern already showed how a mechanism can hide its hardware details behind a clean interface; command-based builds directly on that.",[22,29008,405,29009,29011,29012,29014],{},[25,29010,27264],{}," represents an action the robot can take. In v3, a command's whole behavior is one ordinary block of Java — it can use normal loops and ",[95,29013,2179],{}," statements — that pauses once per loop so the rest of the robot keeps running (Lesson 25.2). Every command also has a name.",[22,29016,2424,29017,29020],{},[25,29018,29019],{},"Scheduler"," is the engine that runs every command, once per loop (Lesson 25.3).",[15,29022,29023,29024,29027],{},"Here is the ",[95,29025,29026],{},"extendCommand()"," used above, written inside the mechanism that owns the piston:",[104,29029,29031],{"className":106,"code":29030,"language":108,"meta":48,"style":48},"public class Pneumatics implements Mechanism\n{\n    private final DoubleSolenoid piston; \u002F\u002F created in the constructor (left out here)\n\n    public Command extendCommand()\n    {\n        return run(coroutine -> piston.set(FORWARD)).named(\"Extend Piston\");\n    }\n}\n",[95,29032,29033,29038,29042,29047,29051,29056,29060,29065,29069],{"__ignoreMap":48},[112,29034,29035],{"class":114,"line":115},[112,29036,29037],{},"public class Pneumatics implements Mechanism\n",[112,29039,29040],{"class":114,"line":49},[112,29041,123],{},[112,29043,29044],{"class":114,"line":126},[112,29045,29046],{},"    private final DoubleSolenoid piston; \u002F\u002F created in the constructor (left out here)\n",[112,29048,29049],{"class":114,"line":132},[112,29050,907],{"emptyLinePlaceholder":55},[112,29052,29053],{"class":114,"line":138},[112,29054,29055],{},"    public Command extendCommand()\n",[112,29057,29058],{"class":114,"line":144},[112,29059,135],{},[112,29061,29062],{"class":114,"line":150},[112,29063,29064],{},"        return run(coroutine -> piston.set(FORWARD)).named(\"Extend Piston\");\n",[112,29066,29067],{"class":114,"line":2276},[112,29068,147],{},[112,29070,29071],{"class":114,"line":2282},[112,29072,153],{},[15,29074,29075,29078,29079,29081,29082,29085,29086,29089],{},[95,29076,29077],{},"run(...)"," is a default method the ",[95,29080,25778],{}," interface provides (Ch.19). A command built with it automatically ",[25,29083,29084],{},"requires"," this mechanism — it claims the pneumatics while it runs. Requirements are what make resource management automatic: only one command can control a given mechanism at a time, so two different pieces of code can never fight over the same motor's output. When two commands do collide, the scheduler compares their ",[25,29087,29088],{},"priorities"," to decide which one wins (Lesson 25.3).",[69,29091,29093],{"id":29092},"how-it-all-runs-the-scheduler","How It All Runs: The Scheduler",[15,29095,29096,29097,195,29099,29102,29103,29106],{},"The default ",[95,29098,29019],{},[95,29100,29101],{},"Scheduler.getDefault()"," — is the engine underneath all of this. Once per loop (every 20ms), your robot calls its ",[95,29104,29105],{},"run()"," method, and it checks all registered triggers for commands that should start, then runs every active command until that command pauses or finishes. Lesson 25.3 covers the scheduler's actual run sequence in depth.",[69,29108,29110],{"id":29109},"composability","Composability",[15,29112,29113,29114,29117],{},"Commands are ",[25,29115,29116],{},"recursively composable"," — a complex robot action (like \"intake a game piece, then aim the shooter, then fire\") can be built out of several small, simple commands combined together, and that composite is itself just another command, usable anywhere a command is expected. Lesson 25.2 covers this in depth.",[69,29119,462],{"id":461},[19,29121,29122,29136,29145],{},[22,29123,29124,29129,29130,29132,29133,79],{},[25,29125,29126,29127,79],{},"Writing large amounts of imperative logic directly in ",[95,29128,18517],{}," This works against the entire declarative philosophy command-based is built on — the goal is to describe ",[494,29131,4416],{}," happens, and let the scheduler handle ",[494,29134,29135],{},"when",[22,29137,29138,29141,29142,29144],{},[25,29139,29140],{},"Touching a mechanism's hardware from a command that doesn't require it."," A command that drives a mechanism's motor without requiring that mechanism bypasses the resource-management system entirely, risking two commands fighting over the same hardware. Building commands with the mechanism's own ",[95,29143,29077],{}," makes the requirement automatic.",[22,29146,29147,29150],{},[25,29148,29149],{},"Assuming command-based is the only valid way to write robot code."," It isn't — but it's the pattern this curriculum focuses on, since it's what WPILib itself is built to support.",[69,29152,501],{"id":500},[19,29154,29155,29158,29164,29170,29173],{},[22,29156,29157],{},"Command-based programming is WPILib's own declarative architecture pattern: describe what should happen under what condition, once, and the library handles checking it every loop.",[22,29159,29160,29161,29163],{},"This course teaches Commands v3 (",[95,29162,3062],{},", WPILib 2027); most existing team code still uses Commands v2, which Lesson 25.7 shows you how to read.",[22,29165,29166,29167,29169],{},"The three core abstractions are Mechanisms (hardware, an interface your classes implement), Commands (named actions), and the Scheduler (",[95,29168,29101],{},") that runs them every loop.",[22,29171,29172],{},"A command requires the mechanisms it controls, which is what lets the scheduler guarantee only one command controls a given mechanism at a time; priorities decide who wins a conflict.",[22,29174,29175],{},"Commands are recursively composable — small commands combine into larger ones, which are themselves still just commands.",[15,29177,544,29178,548,29180,29183,29184,2150,29186,322,29189,322,29192,322,29195,29198],{},[95,29179,17008],{},[95,29181,29182],{},"wpilib\u002Fcommand-based\u002F01-what-is-command-based.md"," (WPILIB 20.1); updated for Commands v3 from allwpilib ",[95,29185,101],{},[95,29187,29188],{},"commandsv3\u002F…\u002Fcommand3\u002FMechanism.java",[95,29190,29191],{},"Command.java",[95,29193,29194],{},"Scheduler.java",[95,29196,29197],{},"hatchbotcmdv3"," example)",[554,29200,556],{},{"title":48,"searchDepth":49,"depth":49,"links":29202},[29203,29204,29205,29206,29207,29208,29209],{"id":28848,"depth":49,"text":28849},{"id":28880,"depth":49,"text":28881},{"id":28988,"depth":49,"text":28989},{"id":29092,"depth":49,"text":29093},{"id":29109,"depth":49,"text":29110},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":29211,"status":29212},"25.1 — What Is Command-Based Programming? (WPILIB 20.1)","new — authored lesson (rewritten for Commands v3, WPILib 2027)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F1-what-is-command-based-programming",{"title":28840,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.1-what-is-command-based-programming","V8QhvhogUkIuhG9s_lDA0pfeWSVUZlCCKGzpQHfGnsE",{"id":29218,"title":29219,"body":29220,"description":48,"extension":51,"meta":30064,"navigation":55,"path":30066,"seo":30067,"stem":30068,"__hash__":30069},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.2-commands-and-command-compositions.md","Commands & Command Compositions",{"type":8,"value":29221,"toc":30050},[29222,29225,29229,29240,29296,29324,29393,29407,29410,29414,29450,29454,29460,29486,29492,29496,29531,29553,29556,29581,29585,29601,29638,29649,29657,29673,29702,29712,29716,29732,29786,29799,29814,29826,29834,29840,29847,29872,29885,29887,29942,29944,30018,30048],[11,29223,29219],{"id":29224},"commands-command-compositions",[69,29226,29228],{"id":29227},"one-body-written-like-a-normal-method","One Body, Written Like a Normal Method",[15,29230,29231,29232,29235,29236,29239],{},"In Commands v3, a command's entire behavior is ",[25,29233,29234],{},"one block of code"," — a lambda that receives a ",[95,29237,29238],{},"Coroutine"," object. The body reads top to bottom like any method you've written: code before a loop runs once when the command starts, the loop runs once per scheduler loop, and code after the loop runs once when the goal is reached.",[104,29241,29243],{"className":106,"code":29242,"language":108,"meta":48,"style":48},"public Command raiseCommand()\n{\n    return run(coroutine -> {\n        motor.setThrottle(0.5);       \u002F\u002F once, when the command starts\n        while (!topLimit.get())\n        {\n            coroutine.yield();        \u002F\u002F pause here until the next loop\n        }\n        motor.setThrottle(0.0);       \u002F\u002F once, when the top limit switch trips\n    }).named(\"Raise Elevator\");\n}\n",[95,29244,29245,29250,29254,29259,29264,29269,29273,29278,29282,29287,29292],{"__ignoreMap":48},[112,29246,29247],{"class":114,"line":115},[112,29248,29249],{},"public Command raiseCommand()\n",[112,29251,29252],{"class":114,"line":49},[112,29253,123],{},[112,29255,29256],{"class":114,"line":126},[112,29257,29258],{},"    return run(coroutine -> {\n",[112,29260,29261],{"class":114,"line":132},[112,29262,29263],{},"        motor.setThrottle(0.5);       \u002F\u002F once, when the command starts\n",[112,29265,29266],{"class":114,"line":138},[112,29267,29268],{},"        while (!topLimit.get())\n",[112,29270,29271],{"class":114,"line":144},[112,29272,11303],{},[112,29274,29275],{"class":114,"line":150},[112,29276,29277],{},"            coroutine.yield();        \u002F\u002F pause here until the next loop\n",[112,29279,29280],{"class":114,"line":2276},[112,29281,11313],{},[112,29283,29284],{"class":114,"line":2282},[112,29285,29286],{},"        motor.setThrottle(0.0);       \u002F\u002F once, when the top limit switch trips\n",[112,29288,29289],{"class":114,"line":2288},[112,29290,29291],{},"    }).named(\"Raise Elevator\");\n",[112,29293,29294],{"class":114,"line":5760},[112,29295,153],{},[15,29297,29298,29299,29301,29302,4238,29304,4875,29307,29309,29310,4875,29313,29315,29316,29319,29320,29323],{},"This method lives in an ",[95,29300,4942],{}," class that ",[95,29303,29005],{},[95,29305,29306],{},"motor",[95,29308,4333],{}," (Ch.4) and ",[95,29311,29312],{},"topLimit",[95,29314,3070],{}," (Ch.3). The ",[25,29317,29318],{},"coroutine"," is the object that lets a command pause partway through and pick up again later: ",[95,29321,29322],{},"coroutine.yield()"," means \"I'm done for this loop — let the rest of the robot run, and resume me right here next loop.\"",[3819,29325,29326,29339],{},[3822,29327,29328],{},[3825,29329,29330,29333,29336],{},[3828,29331,29332],{},"Part of the body",[3828,29334,29335],{},"When it runs",[3828,29337,29338],{},"The v2 method you'll see in older code",[3838,29340,29341,29354,29367,29380],{},[3825,29342,29343,29346,29349],{},[3843,29344,29345],{},"Code before the loop",[3843,29347,29348],{},"Once, when the command starts",[3843,29350,29351],{},[95,29352,29353],{},"initialize()",[3825,29355,29356,29359,29362],{},[3843,29357,29358],{},"The loop's body",[3843,29360,29361],{},"Once per scheduler loop",[3843,29363,29364],{},[95,29365,29366],{},"execute()",[3825,29368,29369,29372,29375],{},[3843,29370,29371],{},"The loop's condition",[3843,29373,29374],{},"Checked every loop to decide when to stop",[3843,29376,29377],{},[95,29378,29379],{},"isFinished()",[3825,29381,29382,29385,29388],{},[3843,29383,29384],{},"Code after the loop",[3843,29386,29387],{},"Once, when the command finishes on its own",[3843,29389,29390],{},[95,29391,29392],{},"end(false)",[15,29394,29395,29398,29399,29402,29403,29406],{},[25,29396,29397],{},"In v2 code you'll see"," a class that ",[95,29400,29401],{},"extends Command"," and overrides those four methods separately, plus ",[95,29404,29405],{},"addRequirements(...)"," in its constructor. v3 folds all four into the one body above; Lesson 25.7 has a v2 reading guide.",[15,29408,29409],{},"A body with no loop at all simply runs once and ends — that's how a one-shot action like \"extend the piston\" is written.",[69,29411,29413],{"id":29412},"every-command-has-a-name-enforced-by-a-staged-builder","Every Command Has a Name — Enforced by a Staged Builder",[15,29415,29416,29418,29419,29421,29422,29425,29426,29429,29430,29432,29433,29436,29437,322,29440,322,29443,325,29446,29449],{},[95,29417,29077],{}," doesn't return a ",[95,29420,27264],{}," yet. It returns a builder ",[25,29423,29424],{},"stage",", and only calling ",[95,29427,29428],{},".named(\"...\")"," on it produces the finished ",[95,29431,27264],{},". This is the Builder Pattern from Ch.22 in a strict form: each stage only offers the methods that are legal next, so forgetting the name is a ",[494,29434,29435],{},"compile"," error, not a surprise at a match. Before naming, a stage can take optional settings — ",[95,29438,29439],{},".whenExited(...)",[95,29441,29442],{},".whenCanceled(...)",[95,29444,29445],{},".withPriority(...)",[95,29447,29448],{},".until(...)"," — covered below and in Lesson 25.3.",[69,29451,29453],{"id":29452},"requirements-come-from-how-you-build-the-command","Requirements Come From How You Build the Command",[15,29455,29456,29457,29459],{},"A command ",[25,29458,29084],{}," the mechanisms it controls, and the way you start building it decides which ones:",[19,29461,29462,29474,29480],{},[22,29463,29464,260,29467,29470,29471,29473],{},[95,29465,29466],{},"elevator.run(...)",[95,29468,29469],{},"elevator.runRepeatedly(...)"," — requires ",[95,29472,4938],{},", automatically.",[22,29475,29476,29479],{},[95,29477,29478],{},"Command.requiring(drive, arm).executing(coroutine -> ...)"," — requires several mechanisms at once.",[22,29481,29482,29485],{},[95,29483,29484],{},"Command.noRequirements(coroutine -> ...)"," — requires nothing; for commands that don't touch hardware, like resetting a software value or logging.",[15,29487,29488,29489,29491],{},"There's no separate \"declare my requirements\" step to forget — which is exactly the mistake v2's ",[95,29490,29405],{}," made easy.",[69,29493,29495],{"id":29494},"built-in-factories-most-commands-are-one-statement","Built-In Factories: Most Commands Are One Statement",[104,29497,29499],{"className":106,"code":29498,"language":108,"meta":48,"style":48},"hatch.run(coroutine -> hatch.grab()).named(\"Grab Hatch\");     \u002F\u002F runs once, then ends\ndrive.runRepeatedly(() -> drive.arcade(forward.getAsDouble(), turn.getAsDouble()))\n    .named(\"Arcade Drive\");                                   \u002F\u002F repeats until interrupted\nintake.idle();                                                \u002F\u002F owns the intake, idles\nCommand.waitFor(Seconds.of(5)).named(\"Wait 5 s\");             \u002F\u002F ends after 5 seconds\nCommand.waitUntil(limitSwitch::get).named(\"Wait for Switch\"); \u002F\u002F ends once this is true\n",[95,29500,29501,29506,29511,29516,29521,29526],{"__ignoreMap":48},[112,29502,29503],{"class":114,"line":115},[112,29504,29505],{},"hatch.run(coroutine -> hatch.grab()).named(\"Grab Hatch\");     \u002F\u002F runs once, then ends\n",[112,29507,29508],{"class":114,"line":49},[112,29509,29510],{},"drive.runRepeatedly(() -> drive.arcade(forward.getAsDouble(), turn.getAsDouble()))\n",[112,29512,29513],{"class":114,"line":126},[112,29514,29515],{},"    .named(\"Arcade Drive\");                                   \u002F\u002F repeats until interrupted\n",[112,29517,29518],{"class":114,"line":132},[112,29519,29520],{},"intake.idle();                                                \u002F\u002F owns the intake, idles\n",[112,29522,29523],{"class":114,"line":138},[112,29524,29525],{},"Command.waitFor(Seconds.of(5)).named(\"Wait 5 s\");             \u002F\u002F ends after 5 seconds\n",[112,29527,29528],{"class":114,"line":144},[112,29529,29530],{},"Command.waitUntil(limitSwitch::get).named(\"Wait for Switch\"); \u002F\u002F ends once this is true\n",[15,29532,29533,29536,29537,29539,29540,537,29543,328,29546,29548,29549,29552],{},[95,29534,29535],{},"runRepeatedly"," takes a plain ",[95,29538,25322],{}," (Lesson 19.1) and calls it once every loop, yielding for you — a natural fit for a default command (Lesson 25.3). (Here ",[95,29541,29542],{},"forward",[95,29544,29545],{},"turn",[95,29547,25307],{},"s reading the joystick axes.) ",[95,29550,29551],{},"idle()"," is already named and has the lowest possible priority, so anything else can take the mechanism from it.",[15,29554,29555],{},"Inside a body, the coroutine has helpers for the most common kinds of pausing:",[19,29557,29558,29563,29569,29575],{},[22,29559,29560,29562],{},[95,29561,29322],{}," — pause until the next loop.",[22,29564,29565,29568],{},[95,29566,29567],{},"coroutine.wait(Seconds.of(1))"," — pause for a length of time.",[22,29570,29571,29574],{},[95,29572,29573],{},"coroutine.waitUntil(limitSwitch::get)"," — pause until a condition is true.",[22,29576,29577,29580],{},[95,29578,29579],{},"coroutine.park()"," — pause forever, until something cancels the command.",[69,29582,29584],{"id":29583},"cleaning-up-when-a-command-ends","Cleaning Up When a Command Ends",[15,29586,29587,29588,29591,29592,12534,29594,29596,29597,29600],{},"A command that starts a motor usually has to stop it however the command ends — finished, canceled, or interrupted by another command. ",[95,29589,29590],{},"whenExited(...)"," runs a ",[95,29593,25322],{},[494,29595,21370],{}," exit; ",[95,29598,29599],{},"whenCanceled(...)"," runs only when the command is stopped early.",[104,29602,29604],{"className":106,"code":29603,"language":108,"meta":48,"style":48},"public Command spinCommand()\n{\n    return run(coroutine -> {\n        motor.setThrottle(0.8);\n        coroutine.park();             \u002F\u002F keep spinning until something stops this command\n    }).whenExited(() -> motor.setThrottle(0.0)).named(\"Spin Shooter\");\n}\n",[95,29605,29606,29611,29615,29619,29624,29629,29634],{"__ignoreMap":48},[112,29607,29608],{"class":114,"line":115},[112,29609,29610],{},"public Command spinCommand()\n",[112,29612,29613],{"class":114,"line":49},[112,29614,123],{},[112,29616,29617],{"class":114,"line":126},[112,29618,29258],{},[112,29620,29621],{"class":114,"line":132},[112,29622,29623],{},"        motor.setThrottle(0.8);\n",[112,29625,29626],{"class":114,"line":138},[112,29627,29628],{},"        coroutine.park();             \u002F\u002F keep spinning until something stops this command\n",[112,29630,29631],{"class":114,"line":144},[112,29632,29633],{},"    }).whenExited(() -> motor.setThrottle(0.0)).named(\"Spin Shooter\");\n",[112,29635,29636],{"class":114,"line":150},[112,29637,153],{},[15,29639,29640,29641,29644,29645,29648],{},"Alpha note: ",[95,29642,29643],{},"whenExited"," (and the ",[95,29646,29647],{},"onExit()"," hook behind it) was added to v3 in September 2026 — re-check it against the current WPILib docs before the season.",[69,29650,29652,29653,29656],{"id":29651},"units-durations-are-time-values-not-plain-numbers","Units: Durations Are ",[95,29654,29655],{},"Time"," Values, Not Plain Numbers",[15,29658,29659,29660,12217,29662,29665,29666,29668,29669,29672],{},"Every v3 method that takes a duration takes a ",[95,29661,29655],{},[95,29663,29664],{},"org.wpilib.units.measure","), not a ",[95,29667,631],{},". You make one from a unit constant in WPILib's ",[95,29670,29671],{},"Units"," class, usually brought in with a static import (Lesson 3.3):",[104,29674,29676],{"className":106,"code":29675,"language":108,"meta":48,"style":48},"import static org.wpilib.units.Units.Milliseconds;\nimport static org.wpilib.units.Units.Seconds;\n\nTime autoDelay = Seconds.of(2);        \u002F\u002F 2 seconds\nTime nudge = Milliseconds.of(100);     \u002F\u002F 0.1 seconds\n",[95,29677,29678,29683,29688,29692,29697],{"__ignoreMap":48},[112,29679,29680],{"class":114,"line":115},[112,29681,29682],{},"import static org.wpilib.units.Units.Milliseconds;\n",[112,29684,29685],{"class":114,"line":49},[112,29686,29687],{},"import static org.wpilib.units.Units.Seconds;\n",[112,29689,29690],{"class":114,"line":126},[112,29691,907],{"emptyLinePlaceholder":55},[112,29693,29694],{"class":114,"line":132},[112,29695,29696],{},"Time autoDelay = Seconds.of(2);        \u002F\u002F 2 seconds\n",[112,29698,29699],{"class":114,"line":138},[112,29700,29701],{},"Time nudge = Milliseconds.of(100);     \u002F\u002F 0.1 seconds\n",[15,29703,29704,29705,29708,29709,29711],{},"The payoff: a bare ",[95,29706,29707],{},"withTimeout(5)"," can't compile, so nobody can ever wonder whether that ",[95,29710,607],{}," meant seconds or milliseconds.",[69,29713,29715],{"id":29714},"command-compositions-building-bigger-actions-from-smaller-ones","Command Compositions: Building Bigger Actions From Smaller Ones",[15,29717,405,29718,29721,29722,29724,29725,29727,29728,29731],{},[25,29719,29720],{},"command composition"," combines several commands into one — and since a composition is itself a ",[95,29723,27264],{},", compositions can be nested arbitrarily deep. Like single commands, compositions are built with builders, so they also end in ",[95,29726,29428],{}," — or ",[95,29729,29730],{},".withAutomaticName()",", which names the group after its members. Three shapes matter most:",[19,29733,29734,29749,29767],{},[22,29735,29736,29739,29740],{},[25,29737,29738],{},"Sequential"," — runs each command in order, one after another, finishing when the last one finishes:\n",[104,29741,29743],{"className":106,"code":29742,"language":108,"meta":48,"style":48},"fooCommand.andThen(barCommand).withAutomaticName(); \u002F\u002F runs fooCommand, then barCommand\n",[95,29744,29745],{"__ignoreMap":48},[112,29746,29747],{"class":114,"line":115},[112,29748,29742],{},[22,29750,29751,29754,29755,29757,29758],{},[25,29752,29753],{},"Parallel"," — runs several commands at once, finishing once ",[494,29756,7012],{}," of them finish:\n",[104,29759,29761],{"className":106,"code":29760,"language":108,"meta":48,"style":48},"Command.parallel(twoSec, oneSec, threeSec).named(\"All Three\"); \u002F\u002F ends after 3 seconds\n",[95,29762,29763],{"__ignoreMap":48},[112,29764,29765],{"class":114,"line":115},[112,29766,29760],{},[22,29768,29769,29772,29773,29776,29777],{},[25,29770,29771],{},"Race"," — runs several commands at once, finishing as soon as ",[494,29774,29775],{},"any one"," of them finishes (canceling the rest):\n",[104,29778,29780],{"className":106,"code":29779,"language":108,"meta":48,"style":48},"Command.race(twoSec, oneSec, threeSec).named(\"First Done\"); \u002F\u002F ends after 1 second\n",[95,29781,29782],{"__ignoreMap":48},[112,29783,29784],{"class":114,"line":115},[112,29785,29779],{},[15,29787,29788,29791,29792,537,29795,29798],{},[95,29789,29790],{},"Command.sequence(a, b, c)"," builds a sequence from a list, and ",[95,29793,29794],{},"a.alongWith(b)",[95,29796,29797],{},"a.raceWith(b)"," are the chained forms of parallel and race. Two decorators add extra end conditions to any command:",[104,29800,29802],{"className":106,"code":29801,"language":108,"meta":48,"style":48},"raise.until(limitSwitch::get).named(\"Raise to Switch\"); \u002F\u002F ends early if the switch trips\nraise.withTimeout(Seconds.of(5));                       \u002F\u002F ends after 5 s, no matter what\n",[95,29803,29804,29809],{"__ignoreMap":48},[112,29805,29806],{"class":114,"line":115},[112,29807,29808],{},"raise.until(limitSwitch::get).named(\"Raise to Switch\"); \u002F\u002F ends early if the switch trips\n",[112,29810,29811],{"class":114,"line":49},[112,29812,29813],{},"raise.withTimeout(Seconds.of(5));                       \u002F\u002F ends after 5 s, no matter what\n",[15,29815,1866,29816,29819,29820,29822,29823,1566],{},[95,29817,29818],{},"withTimeout"," returns a finished, automatically named ",[95,29821,27264],{},", so it needs no ",[95,29824,29825],{},".named(...)",[69,29827,29829,29830,29833],{"id":29828},"requirements-of-a-composition-and-the-await-alternative","Requirements of a Composition, and the ",[95,29831,29832],{},"await"," Alternative",[15,29835,29836,29837,29839],{},"A built-in composition requires ",[494,29838,21370],{}," mechanism any of its members requires, for its entire duration — a sequence that uses the intake, then the indexer, then the shooter holds all three the whole time, even while two of them are sitting unused. (Two members of one parallel group can't require the same mechanism at all; building such a group throws an error.)",[15,29841,29842,29843,29846],{},"v3 offers a finer-grained alternative: a command with no requirements of its own that ",[25,29844,29845],{},"awaits"," other commands from inside its body. Each awaited command claims its mechanism only while it's actually running:",[104,29848,29850],{"className":106,"code":29849,"language":108,"meta":48,"style":48},"Command.noRequirements(coroutine -> {\n    coroutine.await(intake.intakeCommand());   \u002F\u002F intake is claimed only during this step\n    coroutine.await(shooter.fireCommand());    \u002F\u002F then the shooter, only during this step\n}).named(\"Intake Then Fire\");\n",[95,29851,29852,29857,29862,29867],{"__ignoreMap":48},[112,29853,29854],{"class":114,"line":115},[112,29855,29856],{},"Command.noRequirements(coroutine -> {\n",[112,29858,29859],{"class":114,"line":49},[112,29860,29861],{},"    coroutine.await(intake.intakeCommand());   \u002F\u002F intake is claimed only during this step\n",[112,29863,29864],{"class":114,"line":126},[112,29865,29866],{},"    coroutine.await(shooter.fireCommand());    \u002F\u002F then the shooter, only during this step\n",[112,29868,29869],{"class":114,"line":132},[112,29870,29871],{},"}).named(\"Intake Then Fire\");\n",[15,29873,29874,537,29877,29880,29881,29884],{},[95,29875,29876],{},"coroutine.awaitAll(...)",[95,29878,29879],{},"coroutine.awaitAny(...)"," wait for several commands at once, and ",[95,29882,29883],{},"coroutine.fork(...)"," starts commands without waiting for them. A command started this way can never outlive the command that started it.",[69,29886,462],{"id":461},[19,29888,29889,29903,29923,29932],{},[22,29890,29891,29896,29897,29899,29900,29902],{},[25,29892,29893,29894,79],{},"A loop that never calls ",[95,29895,29322],{}," The scheduler runs one command at a time, and a command only gives control back when it yields. A ",[95,29898,7977],{}," loop without ",[95,29901,29322],{}," never lets anything else run — not other commands, not trigger checks, not the rest of your robot code — so the whole robot hangs.",[22,29904,29905,476,29914,29916,29917,29920,29921,79],{},[25,29906,6120,29907,12778,29910,29913],{},[95,29908,29909],{},"yield()",[95,29911,29912],{},"coroutine."," in front.",[95,29915,6306],{}," is a restricted word in Java (switch expressions use it, Lesson 5.12), so a bare ",[95,29918,29919],{},"yield();"," is a compile error; the call must be written ",[95,29922,29322],{},[22,29924,29925,29928,29929,79],{},[25,29926,29927],{},"Using a coroutine that isn't yours."," Each command's body gets its own coroutine; calling methods on a different command's coroutine (for example, one captured by a lambda from an outer command) throws an ",[95,29930,29931],{},"IllegalStateException",[22,29933,29934,29937,29938,29941],{},[25,29935,29936],{},"Forgetting that a sequential composition needs every step to actually finish."," If one command in a sequence never finishes — a loop that never ends, or a ",[95,29939,29940],{},"park()"," — every command after it in the sequence never runs.",[69,29943,501],{"id":500},[19,29945,29946,29952,29958,29970,30001,30011],{},[22,29947,29948,29949,29951],{},"A v3 command is one body: code before the loop runs once at the start, the loop body runs once per scheduler loop (ending with ",[95,29950,29322],{},"), and code after the loop runs once at the end.",[22,29953,29954,29955,29957],{},"Commands are built with staged builders, and every command must be named with ",[95,29956,29825],{}," — a missing name is a compile error.",[22,29959,29960,29961,322,29964,3283,29967,79],{},"Requirements come from how a command is built: ",[95,29962,29963],{},"mechanism.run(...)",[95,29965,29966],{},"Command.requiring(...)",[95,29968,29969],{},"Command.noRequirements(...)",[22,29971,29972,29973,322,29975,322,29977,322,29980,322,29983,29986,29987,322,29989,322,29991,322,29994,29997,29998,30000],{},"Built-in factories (",[95,29974,14817],{},[95,29976,29535],{},[95,29978,29979],{},"idle",[95,29981,29982],{},"Command.waitFor",[95,29984,29985],{},"Command.waitUntil",") and coroutine helpers (",[95,29988,6306],{},[95,29990,8121],{},[95,29992,29993],{},"waitUntil",[95,29995,29996],{},"park",") cover most commands in one statement; ",[95,29999,29590],{}," handles cleanup.",[22,30002,30003,30004,30006,30007,30010],{},"Durations are ",[95,30005,29655],{}," values, like ",[95,30008,30009],{},"Seconds.of(2)"," — never plain numbers.",[22,30012,30013,30014,30017],{},"Compositions (sequence, parallel, race) combine commands into bigger ones and are themselves ordinary commands; ",[95,30015,30016],{},"coroutine.await(...)"," lets a command use each mechanism only while it needs it.",[15,30019,544,30020,548,30022,322,30025,30028,30029,2150,30031,322,30033,322,30036,322,30039,322,30042,322,30045,1282],{},[95,30021,17008],{},[95,30023,30024],{},"wpilib\u002Fcommand-based\u002F02-commands.md",[95,30026,30027],{},"03-command-compositions.md"," (WPILIB 20.2-3); updated for Commands v3 from allwpilib ",[95,30030,101],{},[95,30032,26753],{},[95,30034,30035],{},"Coroutine.java",[95,30037,30038],{},"Mechanism.java",[95,30040,30041],{},"NeedsNameBuilderStage.java",[95,30043,30044],{},"SequentialGroupBuilder.java",[95,30046,30047],{},"ParallelGroupBuilder.java",[554,30049,556],{},{"title":48,"searchDepth":49,"depth":49,"links":30051},[30052,30053,30054,30055,30056,30057,30059,30060,30062,30063],{"id":29227,"depth":49,"text":29228},{"id":29412,"depth":49,"text":29413},{"id":29452,"depth":49,"text":29453},{"id":29494,"depth":49,"text":29495},{"id":29583,"depth":49,"text":29584},{"id":29651,"depth":49,"text":30058},"Units: Durations Are Time Values, Not Plain Numbers",{"id":29714,"depth":49,"text":29715},{"id":29828,"depth":49,"text":30061},"Requirements of a Composition, and the await Alternative",{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":30065,"status":29212},"25.2 — Commands & Command Compositions (WPILIB 20.2-3)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F2-commands-and-command-compositions",{"title":29219,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.2-commands-and-command-compositions","yfnlYGBftm9IcQvb1rVZgMS9ICwMBy5AklHyqXL0Gyg",{"id":30071,"title":30072,"body":30073,"description":48,"extension":51,"meta":30599,"navigation":55,"path":30601,"seo":30602,"stem":30603,"__hash__":30604},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.3-the-command-scheduler.md","The Command Scheduler",{"type":8,"value":30074,"toc":30587},[30075,30078,30082,30098,30125,30133,30137,30143,30197,30215,30219,30237,30252,30257,30294,30314,30318,30329,30354,30369,30372,30376,30398,30422,30426,30432,30435,30443,30453,30462,30465,30467,30510,30512,30555,30585],[11,30076,30072],{"id":30077},"the-command-scheduler",[69,30079,30081],{"id":30080},"the-engine-underneath-everything","The Engine Underneath Everything",[15,30083,2424,30084,322,30087,30089,30090,30093,30094,30097],{},[25,30085,30086],{},"default scheduler",[95,30088,29101],{},", is the object that actually runs commands — everything in Lessons 25.1-25.2 depends on it silently doing its job every single loop. Every mechanism and trigger uses it unless you deliberately create a separate one (",[95,30091,30092],{},"Scheduler.createIndependentScheduler()",", mostly useful in tests). It must be told to run explicitly, from ",[95,30095,30096],{},"robotPeriodic()"," (Lesson 25.7 shows exactly where), or nothing in the whole command-based framework ever executes:",[104,30099,30101],{"className":106,"code":30100,"language":108,"meta":48,"style":48},"@Override\npublic void robotPeriodic()\n{\n    Scheduler.getDefault().run();\n}\n",[95,30102,30103,30107,30112,30116,30121],{"__ignoreMap":48},[112,30104,30105],{"class":114,"line":115},[112,30106,21958],{},[112,30108,30109],{"class":114,"line":49},[112,30110,30111],{},"public void robotPeriodic()\n",[112,30113,30114],{"class":114,"line":126},[112,30115,123],{},[112,30117,30118],{"class":114,"line":132},[112,30119,30120],{},"    Scheduler.getDefault().run();\n",[112,30122,30123],{"class":114,"line":138},[112,30124,153],{},[15,30126,30127,476,30129,30132],{},[25,30128,29397],{},[95,30130,30131],{},"CommandScheduler.getInstance().run()"," in this same spot — same job, older name.",[69,30134,30136],{"id":30135},"one-scheduler-loop-step-by-step","One Scheduler Loop, Step by Step",[15,30138,30139,30140,30142],{},"Every 20ms (WPILib's default loop rate), one call to ",[95,30141,29105],{}," works through these steps, always in this order (slightly simplified from the source):",[30144,30145,30146,30152,30162,30176,30182,30188],"ol",{},[22,30147,30148,30151],{},[25,30149,30150],{},"Clean up."," Cancel any commands and trigger bindings whose scope has ended (see \"Scopes\" below). While the robot is disabled, also cancel commands on mechanisms that aren't allowed to move while disabled.",[22,30153,30154,30157,30158,30161],{},[25,30155,30156],{},"Run periodic side jobs"," added with ",[95,30159,30160],{},"addPeriodic(...)"," — data updates such as odometry or logging.",[22,30163,30164,30167,30168,30171,30172,30175],{},[25,30165,30166],{},"Poll triggers."," Every registered ",[95,30169,30170],{},"Trigger"," (Lesson 25.6) is checked. A binding whose condition changed ",[25,30173,30174],{},"queues"," its command — it doesn't start it yet — or cancels a command it started earlier.",[22,30177,30178,30181],{},[25,30179,30180],{},"Queue default commands"," for every mechanism that has nothing running or queued.",[22,30183,30184,30187],{},[25,30185,30186],{},"Start the queued commands."," Requirement conflicts are settled here, by priority (next section). A running command that loses its mechanism is canceled now. If two queued commands with the same priority need the same mechanism, the one queued last wins.",[22,30189,30190,30193,30194,30196],{},[25,30191,30192],{},"Run every running command",", one at a time, until each one calls ",[95,30195,29322],{}," or finishes.",[15,30198,30199,30200,30203,30204,30206,30207,30209,30210,260,30212,30214],{},"Because triggers only ",[494,30201,30202],{},"queue"," commands in step 3, a command bound to a button starts in step 5 of the same ",[95,30205,29105],{}," and gets its first turn in step 6 — still within the same loop. One exception: a command started from ",[494,30208,2168],{}," another command's body (with ",[95,30211,30016],{},[95,30213,29883],{},") skips the queue and starts immediately.",[69,30216,30218],{"id":30217},"priorities-who-wins-a-requirement-conflict","Priorities: Who Wins a Requirement Conflict",[15,30220,30221,30222,30225,30226,30229,30230,537,30233,30236],{},"Every command has an integer ",[25,30223,30224],{},"priority",". The default is ",[95,30227,30228],{},"Command.DEFAULT_PRIORITY"," (0); the extremes are ",[95,30231,30232],{},"Command.LOWEST_PRIORITY",[95,30234,30235],{},"Command.HIGHEST_PRIORITY",". When a new command needs a mechanism that a running command already has, the scheduler compares them:",[19,30238,30239,30246],{},[22,30240,30241,30242,30245],{},"New command's priority is ",[25,30243,30244],{},"equal or higher"," — the running command is canceled and the new one takes over.",[22,30247,30241,30248,30251],{},[25,30249,30250],{},"lower"," — the new command simply isn't scheduled, and the running one keeps going.",[15,30253,30254,30255,738],{},"Priority is set while building the command, with ",[95,30256,29445],{},[104,30258,30260],{"className":106,"code":30259,"language":108,"meta":48,"style":48},"public Command lowBatteryWarning()\n{\n    return run(coroutine -> {\n        showRed();\n        coroutine.wait(Seconds.of(2));\n    }).withPriority(10).named(\"Low Battery Warning\"); \u002F\u002F beats any priority-0 LED command\n}\n",[95,30261,30262,30267,30271,30275,30280,30285,30290],{"__ignoreMap":48},[112,30263,30264],{"class":114,"line":115},[112,30265,30266],{},"public Command lowBatteryWarning()\n",[112,30268,30269],{"class":114,"line":49},[112,30270,123],{},[112,30272,30273],{"class":114,"line":126},[112,30274,29258],{},[112,30276,30277],{"class":114,"line":132},[112,30278,30279],{},"        showRed();\n",[112,30281,30282],{"class":114,"line":138},[112,30283,30284],{},"        coroutine.wait(Seconds.of(2));\n",[112,30286,30287],{"class":114,"line":144},[112,30288,30289],{},"    }).withPriority(10).named(\"Low Battery Warning\"); \u002F\u002F beats any priority-0 LED command\n",[112,30291,30292],{"class":114,"line":150},[112,30293,153],{},[15,30295,30296,30298,30299,30302,30303,30306,30307,176,30310,30313],{},[25,30297,29397],{}," this job done by an \"interruption behavior\" instead: ",[95,30300,30301],{},"InterruptionBehavior.CANCEL_SELF"," (the running command gives way) or ",[95,30304,30305],{},"CANCEL_INCOMING"," (the new command is refused) — spelled ",[95,30308,30309],{},"kCancelSelf",[95,30311,30312],{},"kCancelIncoming"," in code from 2026 and earlier.",[69,30315,30317],{"id":30316},"default-commands","Default Commands",[15,30319,30320,30321,30324,30325,30328],{},"A mechanism's ",[25,30322,30323],{},"default command"," runs whenever no other command requires that mechanism. If you never set one, the mechanism simply sits unused whenever nothing requires it. You set one with ",[95,30326,30327],{},"setDefaultCommand(...)",", once, during setup:",[104,30330,30332],{"className":106,"code":30331,"language":108,"meta":48,"style":48},"drive.setDefaultCommand(\n    drive.runRepeatedly(() -> drive.arcade(forward.getAsDouble(), turn.getAsDouble()))\n        .withPriority(Command.LOWEST_PRIORITY)\n        .named(\"Arcade Drive\"));\n",[95,30333,30334,30339,30344,30349],{"__ignoreMap":48},[112,30335,30336],{"class":114,"line":115},[112,30337,30338],{},"drive.setDefaultCommand(\n",[112,30340,30341],{"class":114,"line":49},[112,30342,30343],{},"    drive.runRepeatedly(() -> drive.arcade(forward.getAsDouble(), turn.getAsDouble()))\n",[112,30345,30346],{"class":114,"line":126},[112,30347,30348],{},"        .withPriority(Command.LOWEST_PRIORITY)\n",[112,30350,30351],{"class":114,"line":132},[112,30352,30353],{},"        .named(\"Arcade Drive\"));\n",[15,30355,30356,30357,30360,30361,30364,30365,30368],{},"Give a default command a priority ",[494,30358,30359],{},"below"," the default — usually ",[95,30362,30363],{},"LOWEST_PRIORITY"," — so any ordinary command can take the mechanism from it. Once that other command ends, the next time step 4 runs it queues the default command again, and the default command starts over from the top of its body. A default command must require its own mechanism and no other; ",[95,30366,30367],{},"setDefaultCommand"," throws an error otherwise.",[15,30370,30371],{},"This \"runs every loop, lowest priority, gives way to anything else\" shape is exactly what Lesson 25.5 uses to run a mechanism's state machine.",[69,30373,30375],{"id":30374},"how-a-command-ends-finished-or-canceled","How a Command Ends: Finished or Canceled",[15,30377,29456,30378,30381,30382,30385,30386,30389,30390,30393,30394,30397],{},[25,30379,30380],{},"finishes"," when its body returns. It is ",[25,30383,30384],{},"canceled"," when something stops it early: a ",[95,30387,30388],{},"whileTrue"," button is released, an ",[95,30391,30392],{},"until(...)"," condition or timeout fires, a higher-or-equal-priority command takes its mechanism, or code calls ",[95,30395,30396],{},"Scheduler.getDefault().cancel(command)",". A canceled command stops wherever it last yielded — the code after its loop never runs.",[15,30399,30400,30401,30403,30404,30406,30407,30409,30410,537,30412,845,30415,30417,30418,30421],{},"That's why cleanup belongs in ",[95,30402,29590],{}," (runs on every exit) or ",[95,30405,29599],{}," (runs only when stopped early) from Lesson 25.2. A class that implements ",[95,30408,27264],{}," directly gets the same two hooks as the methods ",[95,30411,29647],{},[95,30413,30414],{},"onCancel()",[25,30416,29397],{}," a single ",[95,30419,30420],{},"end(boolean interrupted)"," method doing both jobs.",[69,30423,30425],{"id":30424},"scopes-commands-that-clean-up-after-themselves","Scopes: Commands That Clean Up After Themselves",[15,30427,30428,30429,30431],{},"v3 tracks the ",[25,30430,10436],{}," a command or trigger binding was created in, and cancels it automatically when that scope ends. A command scheduled during autonomous is canceled when autonomous ends; a trigger binding created inside an opmode (Lesson 25.7) only works while that opmode is selected; a command started by another command never outlives it. So there's no \"remember to cancel the autonomous command when teleop starts\" step to forget.",[15,30433,30434],{},"Alpha note: scopes are one of the newest parts of v3 (the robot-mode scopes landed in September 2026), so the exact rules may still change.",[69,30436,30438,30439,30442],{"id":30437},"periodic-side-jobs-addperiodic-is-for-data-not-motors","Periodic Side Jobs: ",[95,30440,30441],{},"addPeriodic"," Is for Data, Not Motors",[15,30444,30445,30446,30448,30449,30452],{},"v3 mechanisms have no ",[95,30447,17077],{}," method. A mechanism's getters usually just read their sensor when called, so a command always sees a fresh value. For work that has to happen every loop but doesn't ",[494,30450,30451],{},"control"," anything — updating odometry, logging, filling an LED data buffer — register a side job once during setup:",[104,30454,30456],{"className":106,"code":30455,"language":108,"meta":48,"style":48},"Scheduler.getDefault().addPeriodic(() -> drive.updateOdometry());\n",[95,30457,30458],{"__ignoreMap":48},[112,30459,30460],{"class":114,"line":115},[112,30461,30455],{},[15,30463,30464],{},"Side jobs run in step 2, before triggers and commands, so commands in step 6 see this loop's data. They must never drive a motor, though: a side job requires no mechanisms, so it would bypass the whole requirement system. Anything that controls a mechanism every loop belongs in a command — often its default command.",[69,30466,462],{"id":461},[19,30468,30469,30480,30489,30501],{},[22,30470,30471,30479],{},[25,30472,30473,30474,4090,30477,79],{},"Forgetting to call ",[95,30475,30476],{},"Scheduler.getDefault().run()",[95,30478,30096],{}," Without this one line, nothing in the entire command-based framework does anything — commands never run, triggers never fire.",[22,30481,30482,30485,30486,30488],{},[25,30483,30484],{},"Assuming a trigger starts its command the instant its condition changes."," The trigger only ",[494,30487,30174],{}," the command in step 3; it starts in step 5 — and if another command with the same priority that needs the same mechanism is queued later in that loop, the later one wins.",[22,30490,30491,30496,30497,260,30499,79],{},[25,30492,30493,30494,79],{},"Putting cleanup after the loop instead of in ",[95,30495,29590],{}," A canceled command never reaches the code after its loop, so a motor started by the command keeps running unless the cleanup is in ",[95,30498,29590],{},[95,30500,29599],{},[22,30502,30503,30509],{},[25,30504,30505,30506,30508],{},"Controlling a motor from an ",[95,30507,30160],{}," side job."," Side jobs have no requirements, so they fight whatever command owns that mechanism; use a command (usually the default command) instead.",[69,30511,501],{"id":500},[19,30513,30514,30524,30533,30536,30542,30550],{},[22,30515,29096,30516,2150,30518,30520,30521,30523],{},[95,30517,29019],{},[95,30519,29101],{},") must be run explicitly, from ",[95,30522,30096],{}," — without this call, the framework does nothing.",[22,30525,30526,30527,30529,30530,30532],{},"Each ",[95,30528,29105],{}," goes in a fixed order: clean up ended scopes, run ",[95,30531,30441],{}," side jobs, poll triggers (which queue commands), queue default commands, start queued commands (settling conflicts), then run each command until it yields or finishes.",[22,30534,30535],{},"Requirement conflicts are settled by priority: an equal-or-higher-priority command takes over, a lower-priority one is refused.",[22,30537,30538,30539,30541],{},"A default command runs whenever its mechanism is free; give it ",[95,30540,30363],{}," so any other command can take over.",[22,30543,30544,30545,176,30547,30549],{},"Cleanup goes in ",[95,30546,29590],{},[95,30548,29599],{},", because a canceled command stops where it last yielded; scopes cancel autonomous- and opmode-scoped commands automatically.",[22,30551,30552,30554],{},[95,30553,30160],{}," is for data updates only — never for controlling a mechanism.",[15,30556,544,30557,548,30559,30562,30563,2150,30565,476,30568,176,30570,176,30573,322,30576,30578,30579,30581,30582,1282],{},[95,30558,17008],{},[95,30560,30561],{},"wpilib\u002Fcommand-based\u002F08-command-scheduler.md"," (WPILIB 20.8); updated for Commands v3 from allwpilib ",[95,30564,101],{},[95,30566,30567],{},"commandsv3\u002F…\u002Fcommand3\u002FScheduler.java",[95,30569,29105],{},[95,30571,30572],{},"schedule()",[95,30574,30575],{},"addPeriodic()",[95,30577,29191],{}," priorities, ",[95,30580,30038],{}," default commands, ",[95,30583,30584],{},"BindingScope.java",[554,30586,556],{},{"title":48,"searchDepth":49,"depth":49,"links":30588},[30589,30590,30591,30592,30593,30594,30595,30597,30598],{"id":30080,"depth":49,"text":30081},{"id":30135,"depth":49,"text":30136},{"id":30217,"depth":49,"text":30218},{"id":30316,"depth":49,"text":30317},{"id":30374,"depth":49,"text":30375},{"id":30424,"depth":49,"text":30425},{"id":30437,"depth":49,"text":30596},"Periodic Side Jobs: addPeriodic Is for Data, Not Motors",{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":30600,"status":29212},"25.3 — The Command Scheduler (WPILIB 20.8)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F3-the-command-scheduler",{"title":30072,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.3-the-command-scheduler","Q_x0PeUrVhWRazI57oZvBCHuYE2yXqfIUgvFm7Airy0",{"id":30606,"title":30607,"body":30608,"description":48,"extension":51,"meta":31016,"navigation":55,"path":31019,"seo":31020,"stem":31021,"__hash__":31022},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.4-state-machines-logic.md","State Machines: Logic",{"type":8,"value":30609,"toc":31006},[30610,30613,30617,30620,30645,30661,30665,30675,30735,30739,30742,30748,30755,30824,30839,30843,30859,30863,30866,30913,30920,30924,30931,30933,30971,30973,30990,31004],[11,30611,30607],{"id":30612},"state-machines-logic",[69,30614,30616],{"id":30615},"the-problem-tracking-state-with-booleans-doesnt-scale","The Problem: Tracking State With Booleans Doesn't Scale",[15,30618,30619],{},"A mechanism often needs to remember \"what am I currently doing\" — an intake might be idle, actively intaking, holding a game piece, or scoring. Tracking that with a pile of booleans gets unmanageable fast:",[104,30621,30623],{"className":106,"code":30622,"language":108,"meta":48,"style":48},"private boolean isIdle;\nprivate boolean isIntaking;\nprivate boolean isHolding;\nprivate boolean isScoring;\n",[95,30624,30625,30630,30635,30640],{"__ignoreMap":48},[112,30626,30627],{"class":114,"line":115},[112,30628,30629],{},"private boolean isIdle;\n",[112,30631,30632],{"class":114,"line":49},[112,30633,30634],{},"private boolean isIntaking;\n",[112,30636,30637],{"class":114,"line":126},[112,30638,30639],{},"private boolean isHolding;\n",[112,30641,30642],{"class":114,"line":132},[112,30643,30644],{},"private boolean isScoring;\n",[15,30646,30647,30648,30650,30651,537,30654,30657,30658,30660],{},"Nothing stops two of these from accidentally being ",[95,30649,661],{}," at the same time — a bug that's easy to introduce and hard to spot, since \"impossible\" combinations (",[95,30652,30653],{},"isIdle",[95,30655,30656],{},"isScoring"," both ",[95,30659,661],{},") compile just fine.",[69,30662,30664],{"id":30663},"the-state-machine-design-pattern","The State Machine Design Pattern",[15,30666,405,30667,30670,30671,30674],{},[25,30668,30669],{},"state machine"," is a design pattern for exactly this problem: a system that is always in ",[25,30672,30673],{},"exactly one"," of a fixed set of named states, and moves between them according to defined rules. It has five parts:",[19,30676,30677,30700,30708,30719,30725],{},[22,30678,30679,30682,30683,322,30686,322,30689,322,30692,30695,30696,30699],{},[25,30680,30681],{},"States"," — every situation the mechanism can be in, each with a name: ",[95,30684,30685],{},"IDLE",[95,30687,30688],{},"INTAKING",[95,30690,30691],{},"HOLDING",[95,30693,30694],{},"SCORING",". Each state has its own ",[25,30697,30698],{},"state action",": what the mechanism does, every loop, while it's in that state (for example, \"run the rollers inward at half speed\").",[22,30701,30702,30705,30706,4410],{},[25,30703,30704],{},"The start state"," — the one state the machine is in when the robot turns on (",[95,30707,30685],{},[22,30709,30710,30713,30714,3860,30716,30718],{},[25,30711,30712],{},"Transitions"," — the allowed moves from one state to another, like ",[95,30715,30688],{},[95,30717,30691],{},". A move that isn't listed can't happen.",[22,30720,30721,30724],{},[25,30722,30723],{},"Guard conditions"," — the condition that must be true for a transition to happen, like \"the sensor sees a game piece.\" A guard can check a sensor, a timer, or a driver's button.",[22,30726,30727,30730,30731,30734],{},[25,30728,30729],{},"Entry actions"," — anything that should happen exactly ",[494,30732,30733],{},"once",", at the moment the machine enters a state, like logging the change or resetting a timer. (This is different from the state action, which repeats every loop.)",[69,30736,30738],{"id":30737},"drawing-it-the-state-diagram","Drawing It: The State Diagram",[15,30740,30741],{},"Before writing any code, draw the machine. Each box is a state, each arrow is a transition labeled with its guard, and the arrow from \"start\" marks the start state:",[104,30743,30746],{"className":30744,"code":30745,"language":6629},[6627],"             start\n               │\n               ▼\n         ┌───────────┐   intake button pressed   ┌───────────┐\n         │   IDLE    │ ────────────────────────▶ │ INTAKING  │\n         └───────────┘                           └───────────┘\n               ▲                                       │\n               │ sensor no longer                      │ sensor sees\n               │ sees a piece                          │ a piece\n               │                                       ▼\n         ┌───────────┐   score button pressed    ┌───────────┐\n         │  SCORING  │ ◀──────────────────────── │  HOLDING  │\n         └───────────┘                           └───────────┘\n",[95,30747,30745],{"__ignoreMap":48},[15,30749,30750,30751,30754],{},"The same machine as a ",[25,30752,30753],{},"transition table"," — one row per arrow:",[3819,30756,30757,30770],{},[3822,30758,30759],{},[3825,30760,30761,30764,30767],{},[3828,30762,30763],{},"From",[3828,30765,30766],{},"To",[3828,30768,30769],{},"Guard condition",[3838,30771,30772,30785,30798,30811],{},[3825,30773,30774,30778,30782],{},[3843,30775,30776],{},[95,30777,30685],{},[3843,30779,30780],{},[95,30781,30688],{},[3843,30783,30784],{},"the driver presses the intake button",[3825,30786,30787,30791,30795],{},[3843,30788,30789],{},[95,30790,30688],{},[3843,30792,30793],{},[95,30794,30691],{},[3843,30796,30797],{},"the sensor sees a game piece",[3825,30799,30800,30804,30808],{},[3843,30801,30802],{},[95,30803,30691],{},[3843,30805,30806],{},[95,30807,30694],{},[3843,30809,30810],{},"the driver presses the score button",[3825,30812,30813,30817,30821],{},[3843,30814,30815],{},[95,30816,30694],{},[3843,30818,30819],{},[95,30820,30685],{},[3843,30822,30823],{},"the sensor no longer sees a game piece",[15,30825,30826,30827,30829,30830,30832,30833,30835,30836,30838],{},"And the state actions, one per state: ",[95,30828,30685],{}," stops the rollers, ",[95,30831,30688],{}," runs them inward, ",[95,30834,30691],{}," applies gentle hold pressure, and ",[95,30837,30694],{}," runs them outward. The diagram and the table carry the same information; the diagram is easier to reason about, and the table maps almost line for line onto code (Lesson 25.5).",[69,30840,30842],{"id":30841},"leaving-the-start-state","Leaving the Start State",[15,30844,30845,30846,30848,30849,30851,30852,30855,30856,30858],{},"Look at the diagram again and follow the arrows from \"start.\" The machine begins in ",[95,30847,30685],{}," and stays there — every loop — until a guard on one of ",[95,30850,30685],{},"'s outgoing arrows becomes true. Here that's the driver pressing the intake button. If the start state had ",[494,30853,30854],{},"no"," outgoing transition, the machine would sit in ",[95,30857,30685],{}," forever and the intake would never do anything. Every state needs at least one way out, unless it's deliberately a final state, and the guards on those exits are how the outside world — drivers, sensors, timers — steers the machine.",[69,30860,30862],{"id":30861},"representing-the-states-one-enum-one-field","Representing the States: One Enum, One Field",[15,30864,30865],{},"Enums (Ch.11) are exactly the tool for the states — a fixed, named set of mutually exclusive values, with the compiler enforcing that a variable can only ever be one of them:",[104,30867,30869],{"className":106,"code":30868,"language":108,"meta":48,"style":48},"public enum IntakeState\n{\n    IDLE,\n    INTAKING,\n    HOLDING,\n    SCORING\n}\n\nprivate IntakeState currentState = IntakeState.IDLE;\n",[95,30870,30871,30876,30880,30885,30890,30895,30900,30904,30908],{"__ignoreMap":48},[112,30872,30873],{"class":114,"line":115},[112,30874,30875],{},"public enum IntakeState\n",[112,30877,30878],{"class":114,"line":49},[112,30879,123],{},[112,30881,30882],{"class":114,"line":126},[112,30883,30884],{},"    IDLE,\n",[112,30886,30887],{"class":114,"line":132},[112,30888,30889],{},"    INTAKING,\n",[112,30891,30892],{"class":114,"line":138},[112,30893,30894],{},"    HOLDING,\n",[112,30896,30897],{"class":114,"line":144},[112,30898,30899],{},"    SCORING\n",[112,30901,30902],{"class":114,"line":150},[112,30903,153],{},[112,30905,30906],{"class":114,"line":2276},[112,30907,907],{"emptyLinePlaceholder":55},[112,30909,30910],{"class":114,"line":2282},[112,30911,30912],{},"private IntakeState currentState = IntakeState.IDLE;\n",[15,30914,30915,30916,30919],{},"Now the mechanism's state is a single variable, initialized to the start state, and it's structurally impossible for it to be two states at once. The enum only covers the ",[494,30917,30918],{},"states",", though; the transitions, guards, and actions are logic, and they're the subject of Lesson 25.5.",[69,30921,30923],{"id":30922},"real-codebases-do-this-at-scale","Real Codebases Do This at Scale",[15,30925,30926,30927,30930],{},"This exact pattern — an enum representing a fixed set of named states for a mechanism — is how real, competitive FRC codebases (like Team 5817's own production code) structure their mechanisms, just with more states and richer per-state behavior than this introductory example: an elevator's states might be tied to interpolated target heights that shift based on scoring distance, or a roller's states might each carry their own target voltage. The underlying idea is identical to ",[95,30928,30929],{},"IntakeState"," above — a state machine core built on an enum — dressed up with more sophisticated per-state data as a mechanism's real requirements grow. The subsystem chapters later in this course build directly on this pattern.",[69,30932,462],{"id":461},[19,30934,30935,30941,30959,30965],{},[22,30936,30937,30940],{},[25,30938,30939],{},"Reaching for several independent booleans instead of one enum."," This lets impossible\u002Fcontradictory combinations exist in the code, even though only one is ever supposed to be true — an enum makes that mistake structurally impossible.",[22,30942,30943,476,30946,30949,30950,30952,30953,30955,30956,30958],{},[25,30944,30945],{},"Forgetting a state machine needs an initial value.",[95,30947,30948],{},"currentState"," should always be initialized to the real start state (like ",[95,30951,30685],{},") — an uninitialized state variable is a ",[95,30954,4645],{}," waiting to cause a ",[95,30957,4678],{}," (Ch.12\u002F13) the first time anything reads it.",[22,30960,30961,30964],{},[25,30962,30963],{},"Designing a state with no way out."," If no transition leaves a state — especially the start state — the machine gets stuck there for the rest of the match. Check every box in the diagram for at least one outgoing arrow.",[22,30966,30967,30970],{},[25,30968,30969],{},"Confusing an entry action with a state action."," Something meant to happen once (logging the change, resetting a timer) placed in a state action runs every loop — fifty times a second — instead of once.",[69,30972,501],{"id":500},[19,30974,30975,30978,30981,30984,30987],{},[22,30976,30977],{},"Tracking \"what state am I in\" with multiple independent booleans allows impossible combinations and doesn't scale.",[22,30979,30980],{},"A state machine is always in exactly one of a fixed set of states; it has a start state, transitions between states, guard conditions that decide when each transition happens, state actions that repeat every loop, and entry actions that run once on entering a state.",[22,30982,30983],{},"Draw the state diagram (or write the transition table) before the code, and make sure every state — especially the start state — has a way out.",[22,30985,30986],{},"A single enum field, initialized to the start state, represents the current state and guarantees it's exactly one thing at a time.",[22,30988,30989],{},"This pattern is exactly what real, competitive FRC codebases use for their mechanisms, and the later subsystem chapters build on it.",[15,30991,544,30992,548,30994,322,30997,31000,31001,31003],{},[95,30993,17008],{},[95,30995,30996],{},"team-5817-training\u002Fsubsystems\u002F02-state-based-servo-subsystems.md",[95,30998,30999],{},"03-state-based-roller-subsystems.md"," (T5817 31.1-4)\n",[25,31002,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 10 (\"State Machines: Logic\") — IntakeState enum example",[554,31005,556],{},{"title":48,"searchDepth":49,"depth":49,"links":31007},[31008,31009,31010,31011,31012,31013,31014,31015],{"id":30615,"depth":49,"text":30616},{"id":30663,"depth":49,"text":30664},{"id":30737,"depth":49,"text":30738},{"id":30841,"depth":49,"text":30842},{"id":30861,"depth":49,"text":30862},{"id":30922,"depth":49,"text":30923},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":31017,"status":31018},"25.4 — State Machines: Logic (enum) (T5817 31.1-4)","new — authored lesson (fuller depth than the teaser slide; expanded to the full State Machine design pattern)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F4-state-machines-logic",{"title":30607,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.4-state-machines-logic","q29SM8VozK10WHYAE5F3p0cilQPVWdGPPtbYzENKFbI",{"id":31024,"title":31025,"body":31026,"description":48,"extension":51,"meta":31556,"navigation":55,"path":31559,"seo":31560,"stem":31561,"__hash__":31562},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.5-managing-transitions.md","Managing Transitions",{"type":8,"value":31027,"toc":31545},[31028,31031,31038,31057,31232,31270,31274,31281,31314,31320,31324,31350,31354,31367,31399,31412,31420,31433,31435,31481,31483,31521,31543],[11,31029,31025],{"id":31030},"managing-transitions",[69,31032,31034,31035,31037],{"id":31033},"from-diagram-to-code-one-switch-one-case-per-state","From Diagram to Code: One ",[95,31036,5700],{},", One Case per State",[15,31039,31040,31041,31043,31044,31046,31047,31049,31050,31052,31053,31056],{},"Lesson 25.4 designed the intake's state machine — four states, a start state, and a transition table — and gave the mechanism a single enum field, ",[95,31042,30948],{},". Turning the design into code takes one ",[95,31045,5700],{}," over that field, using the arrow form from Lesson 5.12. Each ",[95,31048,5802],{}," does two jobs: it runs that state's ",[25,31051,30698],{},", then checks the ",[25,31054,31055],{},"guard conditions"," of that state's outgoing transitions:",[104,31058,31060],{"className":106,"code":31059,"language":108,"meta":48,"style":48},"private void update()\n{\n    switch (currentState)\n    {\n        case IDLE ->\n        {\n            motor.setThrottle(0.0);\n            if (intakeButton.getAsBoolean())\n            {\n                enter(IntakeState.INTAKING); \u002F\u002F the way out of the start state\n            }\n        }\n        case INTAKING ->\n        {\n            motor.setThrottle(0.5);\n            if (pieceSensor.get())\n            {\n                enter(IntakeState.HOLDING);\n            }\n        }\n        case HOLDING ->\n        {\n            motor.setThrottle(0.1); \u002F\u002F gentle hold pressure\n            if (scoreButton.getAsBoolean())\n            {\n                enter(IntakeState.SCORING);\n            }\n        }\n        case SCORING ->\n        {\n            motor.setThrottle(-0.5);\n            if (!pieceSensor.get())\n            {\n                enter(IntakeState.IDLE);\n            }\n        }\n    }\n}\n",[95,31061,31062,31067,31071,31076,31080,31085,31089,31094,31099,31103,31108,31112,31116,31121,31125,31130,31135,31139,31144,31148,31152,31157,31161,31166,31171,31175,31180,31184,31188,31193,31197,31202,31207,31211,31216,31220,31224,31228],{"__ignoreMap":48},[112,31063,31064],{"class":114,"line":115},[112,31065,31066],{},"private void update()\n",[112,31068,31069],{"class":114,"line":49},[112,31070,123],{},[112,31072,31073],{"class":114,"line":126},[112,31074,31075],{},"    switch (currentState)\n",[112,31077,31078],{"class":114,"line":132},[112,31079,135],{},[112,31081,31082],{"class":114,"line":138},[112,31083,31084],{},"        case IDLE ->\n",[112,31086,31087],{"class":114,"line":144},[112,31088,11303],{},[112,31090,31091],{"class":114,"line":150},[112,31092,31093],{},"            motor.setThrottle(0.0);\n",[112,31095,31096],{"class":114,"line":2276},[112,31097,31098],{},"            if (intakeButton.getAsBoolean())\n",[112,31100,31101],{"class":114,"line":2282},[112,31102,16009],{},[112,31104,31105],{"class":114,"line":2288},[112,31106,31107],{},"                enter(IntakeState.INTAKING); \u002F\u002F the way out of the start state\n",[112,31109,31110],{"class":114,"line":5760},[112,31111,16019],{},[112,31113,31114],{"class":114,"line":5766},[112,31115,11313],{},[112,31117,31118],{"class":114,"line":5772},[112,31119,31120],{},"        case INTAKING ->\n",[112,31122,31123],{"class":114,"line":5777},[112,31124,11303],{},[112,31126,31127],{"class":114,"line":5783},[112,31128,31129],{},"            motor.setThrottle(0.5);\n",[112,31131,31132],{"class":114,"line":5789},[112,31133,31134],{},"            if (pieceSensor.get())\n",[112,31136,31137],{"class":114,"line":5794},[112,31138,16009],{},[112,31140,31141],{"class":114,"line":10057},[112,31142,31143],{},"                enter(IntakeState.HOLDING);\n",[112,31145,31146],{"class":114,"line":10062},[112,31147,16019],{},[112,31149,31150],{"class":114,"line":13813},[112,31151,11313],{},[112,31153,31154],{"class":114,"line":13818},[112,31155,31156],{},"        case HOLDING ->\n",[112,31158,31159],{"class":114,"line":13824},[112,31160,11303],{},[112,31162,31163],{"class":114,"line":13830},[112,31164,31165],{},"            motor.setThrottle(0.1); \u002F\u002F gentle hold pressure\n",[112,31167,31168],{"class":114,"line":13835},[112,31169,31170],{},"            if (scoreButton.getAsBoolean())\n",[112,31172,31173],{"class":114,"line":13840},[112,31174,16009],{},[112,31176,31177],{"class":114,"line":13845},[112,31178,31179],{},"                enter(IntakeState.SCORING);\n",[112,31181,31182],{"class":114,"line":13850},[112,31183,16019],{},[112,31185,31186],{"class":114,"line":13856},[112,31187,11313],{},[112,31189,31190],{"class":114,"line":13861},[112,31191,31192],{},"        case SCORING ->\n",[112,31194,31195],{"class":114,"line":26421},[112,31196,11303],{},[112,31198,31199],{"class":114,"line":26427},[112,31200,31201],{},"            motor.setThrottle(-0.5);\n",[112,31203,31204],{"class":114,"line":26432},[112,31205,31206],{},"            if (!pieceSensor.get())\n",[112,31208,31209],{"class":114,"line":26438},[112,31210,16009],{},[112,31212,31213],{"class":114,"line":26443},[112,31214,31215],{},"                enter(IntakeState.IDLE);\n",[112,31217,31218],{"class":114,"line":26449},[112,31219,16019],{},[112,31221,31222],{"class":114,"line":26454},[112,31223,11313],{},[112,31225,31226],{"class":114,"line":26460},[112,31227,147],{},[112,31229,31230],{"class":114,"line":26465},[112,31231,153],{},[15,31233,31234,31235,31237,31238,4875,31240,31242,31243,4875,31246,31248,31249,537,31252,328,31255,31257,31258,31260,31261,4875,31263,31265,31266,31269],{},"Compare it with the transition table: every row became one ",[95,31236,2179],{}," inside the case for its \"From\" state. Here ",[95,31239,29306],{},[95,31241,4333],{}," (Ch.4), ",[95,31244,31245],{},"pieceSensor",[95,31247,3070],{}," (Ch.3), and ",[95,31250,31251],{},"intakeButton",[95,31253,31254],{},"scoreButton",[95,31256,25313],{},"s (Lesson 19.1) handed to the intake's constructor — a controller button's ",[95,31259,30170],{}," works, since a ",[95,31262,30170],{},[95,31264,25313],{}," (Lesson 25.6). The arrow form can't fall through from one case into the next, so no ",[95,31267,31268],{},"break;"," is needed.",[69,31271,31273],{"id":31272},"transitions-and-entry-actions-go-through-one-method","Transitions and Entry Actions Go Through One Method",[15,31275,31276,31277,31280],{},"A transition is just a new value in the state field — but routing every transition through one small method gives the machine a single place for ",[25,31278,31279],{},"entry actions",", the things that should happen exactly once on entering a state:",[104,31282,31284],{"className":106,"code":31283,"language":108,"meta":48,"style":48},"private void enter(IntakeState next)\n{\n    \u002F\u002F entry action: log every change, once\n    System.out.println(\"Intake: \" + currentState + \" -> \" + next);\n    currentState = next;\n}\n",[95,31285,31286,31291,31295,31300,31305,31310],{"__ignoreMap":48},[112,31287,31288],{"class":114,"line":115},[112,31289,31290],{},"private void enter(IntakeState next)\n",[112,31292,31293],{"class":114,"line":49},[112,31294,123],{},[112,31296,31297],{"class":114,"line":126},[112,31298,31299],{},"    \u002F\u002F entry action: log every change, once\n",[112,31301,31302],{"class":114,"line":132},[112,31303,31304],{},"    System.out.println(\"Intake: \" + currentState + \" -> \" + next);\n",[112,31306,31307],{"class":114,"line":138},[112,31308,31309],{},"    currentState = next;\n",[112,31311,31312],{"class":114,"line":144},[112,31313,153],{},[15,31315,31316,31317,31319],{},"Logging every transition like this is one of the most useful debugging tools a state machine can have. A state-specific entry action goes here too — for example, restarting a timer when entering ",[95,31318,30694],{},", so a guard in that case could check how long the intake has been scoring.",[69,31321,31323],{"id":31322},"how-the-machine-leaves-its-start-state","How the Machine Leaves Its Start State",[15,31325,31326,31327,31329,31330,31332,31333,31335,31336,31339,31340,31343,31344,31346,31347,31349],{},"Trace it from power-on. ",[95,31328,30948],{}," starts as ",[95,31331,30685],{},", so every loop runs the ",[95,31334,30685],{}," case: the rollers stay stopped, and the guard ",[95,31337,31338],{},"intakeButton.getAsBoolean()"," is checked. The first loop where the driver is pressing the intake button, the guard is true and ",[95,31341,31342],{},"enter(IntakeState.INTAKING)"," runs. From the next loop on, the ",[95,31345,30688],{}," case runs instead. Outside inputs never assign ",[95,31348,30948],{}," directly; they only feed the guards, and the machine decides for itself when to move.",[69,31351,31353],{"id":31352},"running-the-machine-every-loop-a-default-command","Running the Machine Every Loop: A Default Command",[15,31355,31356,31357,31359,31360,31362,31363,31366],{},"A state machine has to be checked every loop, and in Commands v3 anything that controls a mechanism every loop belongs in a command. The natural fit is the mechanism's ",[25,31358,30323],{}," (Lesson 25.3), built with ",[95,31361,29535],{}," so ",[95,31364,31365],{},"update()"," runs once per loop:",[104,31368,31370],{"className":106,"code":31369,"language":108,"meta":48,"style":48},"public Command stateMachineCommand()\n{\n    return runRepeatedly(this::update)\n        .withPriority(Command.LOWEST_PRIORITY)\n        .named(\"Intake State Machine\");\n}\n",[95,31371,31372,31377,31381,31386,31390,31395],{"__ignoreMap":48},[112,31373,31374],{"class":114,"line":115},[112,31375,31376],{},"public Command stateMachineCommand()\n",[112,31378,31379],{"class":114,"line":49},[112,31380,123],{},[112,31382,31383],{"class":114,"line":126},[112,31384,31385],{},"    return runRepeatedly(this::update)\n",[112,31387,31388],{"class":114,"line":132},[112,31389,30348],{},[112,31391,31392],{"class":114,"line":138},[112,31393,31394],{},"        .named(\"Intake State Machine\");\n",[112,31396,31397],{"class":114,"line":144},[112,31398,153],{},[15,31400,31401,31402,31405,31406,31408,31409,31411],{},"During setup (Lesson 25.7 shows where), it's installed once with ",[95,31403,31404],{},"intake.setDefaultCommand(intake.stateMachineCommand());",". The lowest priority means any other command that requires the intake — say, a manual \"eject\" button for a stuck piece — can take over. While it does, ",[95,31407,31365],{}," doesn't run, but ",[95,31410,30948],{}," is an ordinary field, so it keeps its value; when the other command ends, the default command starts again and the machine picks up in the state it was in.",[69,31413,31415,31416,31419],{"id":31414},"sidebar-v3s-built-in-statemachine-alpha","Sidebar: v3's Built-In ",[95,31417,31418],{},"StateMachine"," (Alpha)",[15,31421,31422,31423,31425,31426,31429,31430,31432],{},"Commands v3 also includes a ",[95,31424,31418],{}," class, where each state is a whole command and transitions are declared with methods like ",[95,31427,31428],{},"switchTo(...).when(...)",". It was added in May 2026 and changed again in September 2026, so it's still settling; this course teaches the enum-and-",[95,31431,5700],{}," pattern above, which works the same in any version and is what the later subsystem chapters build on.",[69,31434,462],{"id":461},[19,31436,31437,31448,31465,31475],{},[22,31438,31439,31444,31445,31447],{},[25,31440,31441,31442,79],{},"Putting transition logic in the wrong ",[95,31443,5802],{}," A guard checked inside the wrong state's case either never triggers, or moves the machine out of a state it wasn't in. Each ",[95,31446,2179],{}," belongs in the case for its transition's \"From\" state.",[22,31449,31450,31459,31460,31462,31463,79],{},[25,31451,31452,31453,31455,31456,79],{},"Assigning ",[95,31454,30948],{}," directly instead of calling ",[95,31457,31458],{},"enter(...)"," A direct assignment skips the entry actions, and assignments scattered across many methods make it much harder to reason about when and why transitions happen — keep every transition inside the one ",[95,31461,5700],{},", going through ",[95,31464,31458],{},[22,31466,31467,3708,31472,31474],{},[25,31468,31469,31470,79],{},"Leaving a state out of the ",[95,31471,5700],{},[95,31473,5700],{}," statement doesn't have to list every enum constant, so a missing case compiles fine — and a machine that enters that state does nothing and never leaves it.",[22,31476,31477,31480],{},[25,31478,31479],{},"Expecting the state machine to run while another command owns the mechanism."," The default command pauses whenever a higher-priority command requires the mechanism; the state field keeps its value until the default command resumes.",[69,31482,501],{"id":500},[19,31484,31485,31491,31500,31503,31512],{},[22,31486,31487,31488,31490],{},"An arrow-form ",[95,31489,5700],{}," over the state field, with one case per state, runs each state's action and checks only that state's guards.",[22,31492,31493,31494,31496,31497,31499],{},"Every row of the transition table becomes one ",[95,31495,2179],{}," in its \"From\" state's case; routing transitions through one ",[95,31498,31458],{}," method gives entry actions (like logging) a single home.",[22,31501,31502],{},"The machine leaves its start state when a guard fed by an outside input — like a driver's button — becomes true; outside code feeds guards, it doesn't assign the state.",[22,31504,31505,31506,31508,31509,79],{},"In Commands v3, the ",[95,31507,5700],{}," runs every loop as the mechanism's default command: ",[95,31510,31511],{},"runRepeatedly(this::update).withPriority(Command.LOWEST_PRIORITY).named(...)",[22,31513,31514,31515,31517,31518,31520],{},"v3's built-in ",[95,31516,31418],{}," class exists but is alpha; the enum-and-",[95,31519,5700],{}," pattern is the one this course builds on.",[15,31522,544,31523,548,31525,322,31527,31529,31530,31532,31533,2150,31535,322,31537,26754,31540,31542],{},[95,31524,17008],{},[95,31526,30996],{},[95,31528,30999],{}," (T5817 31.1-4); v3 default-command placement and ",[95,31531,31418],{}," sidebar from allwpilib ",[95,31534,101],{},[95,31536,29188],{},[95,31538,31539],{},"StateMachine.java",[25,31541,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 11 (\"Managing Transitions\") — IntakeState switch example",[554,31544,556],{},{"title":48,"searchDepth":49,"depth":49,"links":31546},[31547,31549,31550,31551,31552,31554,31555],{"id":31033,"depth":49,"text":31548},"From Diagram to Code: One switch, One Case per State",{"id":31272,"depth":49,"text":31273},{"id":31322,"depth":49,"text":31323},{"id":31352,"depth":49,"text":31353},{"id":31414,"depth":49,"text":31553},"Sidebar: v3's Built-In StateMachine (Alpha)",{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":31557,"status":31558},"25.5 — Managing Transitions (switch) (T5817 31.1-4)","new — authored lesson (fuller depth than the teaser slide; rewritten for Commands v3, WPILib 2027)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F5-managing-transitions",{"title":31025,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.5-managing-transitions","5HXlYe5Kbdr9s7VrTbktpo157_eSJXyYKaB2VfQJNX4",{"id":31564,"title":31565,"body":31566,"description":48,"extension":51,"meta":32062,"navigation":55,"path":32064,"seo":32065,"stem":32066,"__hash__":32067},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.6-binding-commands-to-triggers.md","Binding Commands to Triggers",{"type":8,"value":31567,"toc":32052},[31568,31571,31575,31580,31609,31668,31672,31675,31732,31745,31749,31762,31777,31781,31784,31804,31808,31818,31827,31846,31855,31859,31901,31911,31913,31964,31966,32025,32050],[11,31569,31565],{"id":31570},"binding-commands-to-triggers",[69,31572,31574],{"id":31573},"triggers-the-declarative-glue","Triggers: The Declarative Glue",[15,31576,405,31577,31579],{},[95,31578,30170],{}," wraps any boolean condition — a button, a sensor, an arbitrary check — so a command can be bound to it once, declaratively, during setup. From then on, the scheduler itself checks the condition every loop (step 3 of Lesson 25.3's scheduler loop) and queues or cancels the command as needed — no manual polling code required anywhere else.",[104,31581,31583],{"className":106,"code":31582,"language":108,"meta":48,"style":48},"\u002F\u002F From a controller button\nTrigger xButton = driverController.x();\n\n\u002F\u002F From an arbitrary condition — any BooleanSupplier (Lesson 19.1) works\nTrigger loaded = new Trigger(intake::isLoaded);\n",[95,31584,31585,31590,31595,31599,31604],{"__ignoreMap":48},[112,31586,31587],{"class":114,"line":115},[112,31588,31589],{},"\u002F\u002F From a controller button\n",[112,31591,31592],{"class":114,"line":49},[112,31593,31594],{},"Trigger xButton = driverController.x();\n",[112,31596,31597],{"class":114,"line":126},[112,31598,907],{"emptyLinePlaceholder":55},[112,31600,31601],{"class":114,"line":132},[112,31602,31603],{},"\u002F\u002F From an arbitrary condition — any BooleanSupplier (Lesson 19.1) works\n",[112,31605,31606],{"class":114,"line":138},[112,31607,31608],{},"Trigger loaded = new Trigger(intake::isLoaded);\n",[15,31610,31611,31612,4875,31615,31618,31619,31622,31623,322,31626,322,31629,322,31632,322,31635,322,31638,31641,31642,31644,31645,31648,31649,322,31652,322,31655,322,31658,31661,31662,31664,31665,31667],{},"In this chapter ",[95,31613,31614],{},"driverController",[95,31616,31617],{},"CommandXboxController",", from ",[95,31620,31621],{},"org.wpilib.command3.button",": its methods ",[95,31624,31625],{},"a()",[95,31627,31628],{},"b()",[95,31630,31631],{},"x()",[95,31633,31634],{},"y()",[95,31636,31637],{},"leftBumper()",[95,31639,31640],{},"rightBumper()"," and so on each return a ",[95,31643,30170],{}," for that button. (WPILib 2027 also has a generic ",[95,31646,31647],{},"CommandGamepad",", which names the four face buttons by position — ",[95,31650,31651],{},"faceDown()",[95,31653,31654],{},"faceRight()",[95,31656,31657],{},"faceLeft()",[95,31659,31660],{},"faceUp()"," — so the same code fits any gamepad. Those names were changed in May 2026, one sign this API is still alpha.) A ",[95,31663,30170],{}," is itself a ",[95,31666,25313],{},", so it can be passed anywhere a condition is expected.",[69,31669,31671],{"id":31670},"the-core-bindings","The Core Bindings",[15,31673,31674],{},"Each binding schedules a command in response to a specific kind of state change:",[104,31676,31678],{"className":106,"code":31677,"language":108,"meta":48,"style":48},"\u002F\u002F Schedules once, the instant the trigger becomes true (e.g. the button is first pressed)\ndriverController.y().onTrue(intake.retractCommand());\n\n\u002F\u002F Schedules while the trigger is true, cancels the instant it becomes false\ndriverController.b().whileTrue(intake.runIntakeCommand());\n\n\u002F\u002F Schedules once, the instant the trigger becomes false — the mirror of onTrue\ndriverController.a().onFalse(shooter.stopCommand());\n\n\u002F\u002F Schedules while the trigger is false, cancels the instant it becomes true\nloaded.whileFalse(leds.blinkCommand());\n",[95,31679,31680,31685,31690,31694,31699,31704,31708,31713,31718,31722,31727],{"__ignoreMap":48},[112,31681,31682],{"class":114,"line":115},[112,31683,31684],{},"\u002F\u002F Schedules once, the instant the trigger becomes true (e.g. the button is first pressed)\n",[112,31686,31687],{"class":114,"line":49},[112,31688,31689],{},"driverController.y().onTrue(intake.retractCommand());\n",[112,31691,31692],{"class":114,"line":126},[112,31693,907],{"emptyLinePlaceholder":55},[112,31695,31696],{"class":114,"line":132},[112,31697,31698],{},"\u002F\u002F Schedules while the trigger is true, cancels the instant it becomes false\n",[112,31700,31701],{"class":114,"line":138},[112,31702,31703],{},"driverController.b().whileTrue(intake.runIntakeCommand());\n",[112,31705,31706],{"class":114,"line":144},[112,31707,907],{"emptyLinePlaceholder":55},[112,31709,31710],{"class":114,"line":150},[112,31711,31712],{},"\u002F\u002F Schedules once, the instant the trigger becomes false — the mirror of onTrue\n",[112,31714,31715],{"class":114,"line":2276},[112,31716,31717],{},"driverController.a().onFalse(shooter.stopCommand());\n",[112,31719,31720],{"class":114,"line":2282},[112,31721,907],{"emptyLinePlaceholder":55},[112,31723,31724],{"class":114,"line":2288},[112,31725,31726],{},"\u002F\u002F Schedules while the trigger is false, cancels the instant it becomes true\n",[112,31728,31729],{"class":114,"line":5760},[112,31730,31731],{},"loaded.whileFalse(leds.blinkCommand());\n",[15,31733,31734,31737,31738,31740,31741,31744],{},[95,31735,31736],{},"onTrue"," fires once on the rising edge and doesn't re-fire unless the trigger goes false and true again. ",[95,31739,30388],{}," keeps a command running for as long as the condition holds, and cancels it the moment the condition ends — this is the natural fit for \"run the intake while this button is held down.\" ",[95,31742,31743],{},"whileFalse"," is its mirror image.",[69,31746,31748],{"id":31747},"composing-triggers","Composing Triggers",[15,31750,31751,31752,322,31755,325,31758,31761],{},"Triggers combine with ",[95,31753,31754],{},"and()",[95,31756,31757],{},"or()",[95,31759,31760],{},"negate()",", just like boolean expressions (Ch.5):",[104,31763,31765],{"className":106,"code":31764,"language":108,"meta":48,"style":48},"\u002F\u002F Only schedules when BOTH buttons are pressed together\ndriverController.x().and(driverController.y()).onTrue(climber.deployCommand());\n",[95,31766,31767,31772],{"__ignoreMap":48},[112,31768,31769],{"class":114,"line":115},[112,31770,31771],{},"\u002F\u002F Only schedules when BOTH buttons are pressed together\n",[112,31773,31774],{"class":114,"line":49},[112,31775,31776],{},"driverController.x().and(driverController.y()).onTrue(climber.deployCommand());\n",[69,31778,31780],{"id":31779},"chaining-multiple-bindings-on-one-trigger","Chaining Multiple Bindings on One Trigger",[15,31782,31783],{},"Binding methods return the same trigger they were called on, so several different bindings can be chained onto one trigger:",[104,31785,31787],{"className":106,"code":31786,"language":108,"meta":48,"style":48},"driverController.rightBumper()\n    .onTrue(hatch.grabCommand())      \u002F\u002F runs when pressed\n    .onFalse(hatch.releaseCommand()); \u002F\u002F runs when released\n",[95,31788,31789,31794,31799],{"__ignoreMap":48},[112,31790,31791],{"class":114,"line":115},[112,31792,31793],{},"driverController.rightBumper()\n",[112,31795,31796],{"class":114,"line":49},[112,31797,31798],{},"    .onTrue(hatch.grabCommand())      \u002F\u002F runs when pressed\n",[112,31800,31801],{"class":114,"line":126},[112,31802,31803],{},"    .onFalse(hatch.releaseCommand()); \u002F\u002F runs when released\n",[69,31805,31807],{"id":31806},"debouncing-filtering-out-noise","Debouncing: Filtering Out Noise",[15,31809,31810,31811,31814,31815,31817],{},"A digital sensor's raw signal can flicker rapidly right at the transition point — a ",[95,31812,31813],{},"debounce"," filters that out, requiring the condition to hold steady for a set duration before it's treated as a real change. Like every v3 duration, the time is a ",[95,31816,29655],{}," value (Lesson 25.2):",[104,31819,31821],{"className":106,"code":31820,"language":108,"meta":48,"style":48},"loaded.debounce(Seconds.of(0.1)).onTrue(leds.flashCommand()); \u002F\u002F needs 0.1 s of true first\n",[95,31822,31823],{"__ignoreMap":48},[112,31824,31825],{"class":114,"line":115},[112,31826,31820],{},[15,31828,31829,31830,31832,31833,31836,31837,31839,31840,22699,31843,23721],{},"By default, ",[95,31831,31813],{}," only filters the ",[25,31834,31835],{},"rising"," edge: the condition must stay true for 0.1 s before the trigger turns true, but a drop back to false passes through instantly. A sensor that flickers off and on can therefore still fire ",[95,31838,31736],{}," again after each fresh 0.1 s of true. To filter both directions, pass a debounce type from ",[95,31841,31842],{},"Debouncer.DebounceType",[95,31844,31845],{},"org.wpilib.math.filter",[104,31847,31849],{"className":106,"code":31848,"language":108,"meta":48,"style":48},"loaded.debounce(Seconds.of(0.1), DebounceType.BOTH).onTrue(leds.flashCommand());\n",[95,31850,31851],{"__ignoreMap":48},[112,31852,31853],{"class":114,"line":115},[112,31854,31848],{},[69,31856,31858],{"id":31857},"more-bindings-in-commands-v3","More Bindings in Commands v3",[19,31860,31861,31867,31875,31886,31892],{},[22,31862,31863,31866],{},[95,31864,31865],{},"toggleOnTrue(command)"," — each press starts the command if it's stopped, or cancels it if it's running.",[22,31868,31869,13110,31872,31874],{},[95,31870,31871],{},"retryWhileTrue(command)",[95,31873,30388],{},", but restarts the command if it ends while the condition is still true.",[22,31876,31877,537,31880,31883,31884,79],{},[95,31878,31879],{},"risingEdge()",[95,31881,31882],{},"fallingEdge()"," — new triggers that are true for exactly one loop when the condition changes; pair them with ",[95,31885,31736],{},[22,31887,31888,31891],{},[95,31889,31890],{},"multiPress(2, Seconds.of(0.5))"," — a new trigger that becomes true on a double-press within half a second.",[22,31893,31894,31897,31898,31900],{},[25,31895,31896],{},"Command-scoped bindings"," — a binding made ",[494,31899,2168],{}," a command's body only exists while that command runs, and anything it scheduled is canceled when that command ends. It's a clean way to say \"while aiming, fire whenever the turret is on target.\"",[15,31902,29640,31903,31906,31907,31910],{},[95,31904,31905],{},"multiPress"," (May 2026) and ",[95,31908,31909],{},"ifTrue(command)"," — which schedules the command on every loop the condition is true (September 2026) — are among the newest v3 additions and may still change.",[69,31912,462],{"id":461},[19,31914,31915,31925,31941,31951],{},[22,31916,31917,31922,31923,79],{},[25,31918,20315,31919,31921],{},[95,31920,31736],{}," to re-fire while a button stays held."," It only fires once, on the transition from false to true — for continuous behavior while held, use ",[95,31924,30388],{},[22,31926,31927,3708,31933,31935,31936,322,31938,31940],{},[25,31928,31929,31930,31932],{},"Confusing a ",[95,31931,30170],{},"'s boolean condition with the command it's bound to.",[95,31934,30170],{}," is just a wrapped condition; binding methods (",[95,31937,31736],{},[95,31939,30388],{},", etc.) are what actually connect it to a command.",[22,31942,31943,31946,31947,31950],{},[25,31944,31945],{},"Not debouncing a noisy digital sensor."," A sensor near its trip point can rapidly flicker true\u002Ffalse, causing repeated unwanted scheduling — ",[95,31948,31949],{},"debounce(...)"," exists specifically for this.",[22,31952,31953,31959,31960,31963],{},[25,31954,31955,31956,31958],{},"Assuming the default ",[95,31957,31813],{}," filters flicker in both directions."," It only delays the change to true; use ",[95,31961,31962],{},"DebounceType.BOTH"," when a quick drop to false must also be ignored.",[69,31965,501],{"id":500},[19,31967,31968,31980,31993,32003,32006,32015],{},[22,31969,405,31970,31972,31973,31975,31976,537,31978,79],{},[95,31971,30170],{}," wraps any boolean condition (a button, a sensor, an arbitrary check) so a command can be bound to it once, declaratively; controller buttons come from ",[95,31974,31617],{}," methods like ",[95,31977,31625],{},[95,31979,31640],{},[22,31981,31982,176,31984,31987,31988,176,31990,31992],{},[95,31983,31736],{},[95,31985,31986],{},"onFalse"," fire once on a transition; ",[95,31989,30388],{},[95,31991,31743],{}," run a command for as long as the condition holds and cancel it the moment it changes.",[22,31994,31995,31996,322,31998,322,32000,32002],{},"Triggers compose with ",[95,31997,31754],{},[95,31999,31757],{},[95,32001,31760],{}," — same boolean logic as Ch.5.",[22,32004,32005],{},"Binding methods return the same trigger, so multiple bindings can be chained onto one trigger.",[22,32007,32008,32011,32012,32014],{},[95,32009,32010],{},"debounce(Seconds.of(...))"," filters out flickering; by default only the rising edge is debounced, and ",[95,32013,31962],{}," filters both.",[22,32016,32017,32018,322,32021,32024],{},"v3 adds ",[95,32019,32020],{},"toggleOnTrue",[95,32022,32023],{},"retryWhileTrue",", edge and multi-press triggers, and command-scoped bindings.",[15,32026,544,32027,548,32029,32032,32033,2150,32035,322,32038,322,32041,322,32044,26754,32047,32049],{},[95,32028,17008],{},[95,32030,32031],{},"wpilib\u002Fcommand-based\u002F05-binding-commands-to-triggers.md"," (WPILIB 20.5); updated for Commands v3 from allwpilib ",[95,32034,101],{},[95,32036,32037],{},"commandsv3\u002F…\u002Fcommand3\u002FTrigger.java",[95,32039,32040],{},"button\u002FCommandXboxController.java",[95,32042,32043],{},"button\u002FCommandGamepad.java",[95,32045,32046],{},"wpimath\u002F…\u002Ffilter\u002FDebouncer.java",[25,32048,5351],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 12 (\"Event Loops & Triggers\")",[554,32051,556],{},{"title":48,"searchDepth":49,"depth":49,"links":32053},[32054,32055,32056,32057,32058,32059,32060,32061],{"id":31573,"depth":49,"text":31574},{"id":31670,"depth":49,"text":31671},{"id":31747,"depth":49,"text":31748},{"id":31779,"depth":49,"text":31780},{"id":31806,"depth":49,"text":31807},{"id":31857,"depth":49,"text":31858},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":32063,"status":31558},"25.6 — Binding Commands to Triggers (WPILIB 20.5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F6-binding-commands-to-triggers",{"title":31565,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.6-binding-commands-to-triggers","un0bYu9Sjidfabv7Hk_I_6RX21PRmAE7vGMHvpWOoms",{"id":32069,"title":32070,"body":32071,"description":48,"extension":51,"meta":33101,"navigation":55,"path":33104,"seo":33105,"stem":33106,"__hash__":33107},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.7-structuring-a-command-based-robot-project.md","Structuring a Command-Based Robot Project",{"type":8,"value":32072,"toc":33091},[32073,32076,32080,32090,32096,32108,32115,32119,32127,32218,32228,32234,32238,32255,32296,32307,32383,32389,32399,32403,32431,32447,32451,32454,32485,32541,32592,32598,32602,32617,32620,32754,32926,32936,32938,32989,32991,33059,33089],[11,32074,32070],{"id":32075},"structuring-a-command-based-robot-project",[69,32077,32079],{"id":32078},"the-standard-project-shape","The Standard Project Shape",[15,32081,32082,32083,32085,32086,32089],{},"WPILib 2027's official Commands v3 project template organizes a robot around a thin ",[95,32084,20602],{}," class, one class per ",[25,32087,32088],{},"opmode",", and two packages:",[104,32091,32094],{"className":32092,"code":32093,"language":6629},[6627],"Robot.java          the entry point: mechanisms, controllers, and the scheduler call\nExampleAuto.java    an autonomous opmode, marked @Autonomous\nExampleTeleop.java  a teleop opmode, marked @Teleop\nconstants\u002F          one small constants class per topic, like DriverConstants\nmechanisms\u002F         one file per mechanism, like ExampleMechanism\n",[95,32095,32093],{"__ignoreMap":48},[15,32097,1851,32098,32100,32101,322,32104,32107],{},[25,32099,32088],{}," is one selectable mode of robot behavior — \"Score and Back Up\" or \"Two-Piece Auto\" for autonomous, \"Driver Teleop\" for teleop. The drive team picks one on the Driver Station before enabling. Package names are lowercase (",[95,32102,32103],{},"constants",[95,32105,32106],{},"mechanisms","), like every Java package.",[15,32109,32110,32111,32114],{},"Alpha note: this ",[95,32112,32113],{},"OpModeRobot"," framework is new for 2027 (it's been in the template since June 2026), so details may still shift before the season.",[69,32116,32118],{"id":32117},"robot-deliberately-thin","Robot: Deliberately Thin",[15,32120,32121,32123,32124,32126],{},[95,32122,20602],{}," extends WPILib's ",[95,32125,32113],{},". It creates the mechanisms and controllers, sets the default commands that apply in every mode, and runs the scheduler — and almost nothing else:",[104,32128,32130],{"className":106,"code":32129,"language":108,"meta":48,"style":48},"public class Robot extends OpModeRobot\n{\n    final CommandXboxController driverController =\n        new CommandXboxController(DriverConstants.DRIVER_CONTROLLER_PORT);\n    final Intake intake = new Intake(driverController.a(), driverController.b());\n    final Drive drive = new Drive();\n    final Shooter shooter = new Shooter();\n\n    public Robot()\n    {\n        intake.setDefaultCommand(intake.stateMachineCommand()); \u002F\u002F Lesson 25.5's machine\n    }\n\n    @Override\n    public void robotPeriodic()\n    {\n        Scheduler.getDefault().run(); \u002F\u002F the most important line in the project\n    }\n}\n",[95,32131,32132,32137,32141,32146,32151,32156,32161,32166,32170,32175,32179,32184,32188,32192,32196,32201,32205,32210,32214],{"__ignoreMap":48},[112,32133,32134],{"class":114,"line":115},[112,32135,32136],{},"public class Robot extends OpModeRobot\n",[112,32138,32139],{"class":114,"line":49},[112,32140,123],{},[112,32142,32143],{"class":114,"line":126},[112,32144,32145],{},"    final CommandXboxController driverController =\n",[112,32147,32148],{"class":114,"line":132},[112,32149,32150],{},"        new CommandXboxController(DriverConstants.DRIVER_CONTROLLER_PORT);\n",[112,32152,32153],{"class":114,"line":138},[112,32154,32155],{},"    final Intake intake = new Intake(driverController.a(), driverController.b());\n",[112,32157,32158],{"class":114,"line":144},[112,32159,32160],{},"    final Drive drive = new Drive();\n",[112,32162,32163],{"class":114,"line":150},[112,32164,32165],{},"    final Shooter shooter = new Shooter();\n",[112,32167,32168],{"class":114,"line":2276},[112,32169,907],{"emptyLinePlaceholder":55},[112,32171,32172],{"class":114,"line":2282},[112,32173,32174],{},"    public Robot()\n",[112,32176,32177],{"class":114,"line":2288},[112,32178,135],{},[112,32180,32181],{"class":114,"line":5760},[112,32182,32183],{},"        intake.setDefaultCommand(intake.stateMachineCommand()); \u002F\u002F Lesson 25.5's machine\n",[112,32185,32186],{"class":114,"line":5766},[112,32187,147],{},[112,32189,32190],{"class":114,"line":5772},[112,32191,907],{"emptyLinePlaceholder":55},[112,32193,32194],{"class":114,"line":5777},[112,32195,21735],{},[112,32197,32198],{"class":114,"line":5783},[112,32199,32200],{},"    public void robotPeriodic()\n",[112,32202,32203],{"class":114,"line":5789},[112,32204,135],{},[112,32206,32207],{"class":114,"line":5794},[112,32208,32209],{},"        Scheduler.getDefault().run(); \u002F\u002F the most important line in the project\n",[112,32211,32212],{"class":114,"line":10057},[112,32213,147],{},[112,32215,32216],{"class":114,"line":10062},[112,32217,153],{},[15,32219,32220,32221,32223,32224,32227],{},"The fields are ",[95,32222,381],{},", so nothing can ever swap in a different intake, and they deliberately have no access modifier: package-private access (Ch.23) lets the opmode classes in the same package read ",[95,32225,32226],{},"robot.intake",", while code outside the package can't. The controller is declared first because the intake's constructor uses its buttons — field initializers run top to bottom.",[15,32229,32230,32231,32233],{},"Piling large amounts of imperative logic directly into ",[95,32232,18517],{}," fights the entire declarative philosophy (Lesson 25.1) — mode-specific setup belongs in the opmodes.",[69,32235,32237],{"id":32236},"opmodes-one-class-per-mode","OpModes: One Class per Mode",[15,32239,32240,32241,32244,32245,260,32248,32251,32252,32254],{},"An opmode is a class that implements WPILib's ",[95,32242,32243],{},"OpMode"," interface and is marked with an annotation — ",[95,32246,32247],{},"@Autonomous",[95,32249,32250],{},"@Teleop"," — so the framework finds it automatically. Its constructor receives the ",[95,32253,20602],{},", which is how it reaches the mechanisms:",[104,32256,32258],{"className":106,"code":32257,"language":108,"meta":48,"style":48},"@Teleop\npublic class DriverTeleop implements OpMode\n{\n    public DriverTeleop(Robot robot)\n    {\n        robot.driverController.rightBumper().whileTrue(robot.intake.ejectCommand());\n    }\n}\n",[95,32259,32260,32265,32270,32274,32279,32283,32288,32292],{"__ignoreMap":48},[112,32261,32262],{"class":114,"line":115},[112,32263,32264],{},"@Teleop\n",[112,32266,32267],{"class":114,"line":49},[112,32268,32269],{},"public class DriverTeleop implements OpMode\n",[112,32271,32272],{"class":114,"line":126},[112,32273,123],{},[112,32275,32276],{"class":114,"line":132},[112,32277,32278],{},"    public DriverTeleop(Robot robot)\n",[112,32280,32281],{"class":114,"line":138},[112,32282,135],{},[112,32284,32285],{"class":114,"line":144},[112,32286,32287],{},"        robot.driverController.rightBumper().whileTrue(robot.intake.ejectCommand());\n",[112,32289,32290],{"class":114,"line":150},[112,32291,147],{},[112,32293,32294],{"class":114,"line":2276},[112,32295,153],{},[15,32297,32298,32299,32302,32303,32306],{},"The framework constructs an opmode when it's ",[494,32300,32301],{},"selected"," on the Driver Station. Bindings made in its constructor belong to that opmode's scope (Lesson 25.3): they only work while it's selected, so each teleop opmode can map the buttons its own way. An autonomous opmode usually schedules its routine in ",[95,32304,32305],{},"start()",", which runs once, when the robot is enabled:",[104,32308,32310],{"className":106,"code":32309,"language":108,"meta":48,"style":48},"@Autonomous(name = \"Drive Then Shoot\")\npublic class DriveThenShoot implements OpMode\n{\n    private final Command routine;\n\n    public DriveThenShoot(Robot robot)\n    {\n        routine = Autos.driveThenShoot(robot.drive, robot.shooter);\n    }\n\n    @Override\n    public void start()\n    {\n        Scheduler.getDefault().schedule(routine);\n    }\n}\n",[95,32311,32312,32317,32322,32326,32331,32335,32340,32344,32349,32353,32357,32361,32366,32370,32375,32379],{"__ignoreMap":48},[112,32313,32314],{"class":114,"line":115},[112,32315,32316],{},"@Autonomous(name = \"Drive Then Shoot\")\n",[112,32318,32319],{"class":114,"line":49},[112,32320,32321],{},"public class DriveThenShoot implements OpMode\n",[112,32323,32324],{"class":114,"line":126},[112,32325,123],{},[112,32327,32328],{"class":114,"line":132},[112,32329,32330],{},"    private final Command routine;\n",[112,32332,32333],{"class":114,"line":138},[112,32334,907],{"emptyLinePlaceholder":55},[112,32336,32337],{"class":114,"line":144},[112,32338,32339],{},"    public DriveThenShoot(Robot robot)\n",[112,32341,32342],{"class":114,"line":150},[112,32343,135],{},[112,32345,32346],{"class":114,"line":2276},[112,32347,32348],{},"        routine = Autos.driveThenShoot(robot.drive, robot.shooter);\n",[112,32350,32351],{"class":114,"line":2282},[112,32352,147],{},[112,32354,32355],{"class":114,"line":2288},[112,32356,907],{"emptyLinePlaceholder":55},[112,32358,32359],{"class":114,"line":5760},[112,32360,21735],{},[112,32362,32363],{"class":114,"line":5766},[112,32364,32365],{},"    public void start()\n",[112,32367,32368],{"class":114,"line":5772},[112,32369,135],{},[112,32371,32372],{"class":114,"line":5777},[112,32373,32374],{},"        Scheduler.getDefault().schedule(routine);\n",[112,32376,32377],{"class":114,"line":5783},[112,32378,147],{},[112,32380,32381],{"class":114,"line":5789},[112,32382,153],{},[15,32384,32385,32386,32388],{},"Because the routine is scheduled inside the autonomous opmode, the scheduler cancels it automatically when autonomous ends — there's no separate \"cancel autonomous when teleop starts\" step. The ",[95,32387,9621],{}," shown on the Driver Station defaults to the class name if you leave it out.",[15,32390,32391,32392,32394,32395,32398],{},"Passing the ",[95,32393,20602],{}," into each opmode's constructor is ",[25,32396,32397],{},"dependency injection"," (first seen in Lesson 25.2's factories): each opmode is handed exactly what it works with, instead of reaching for global variables.",[69,32400,32402],{"id":32401},"constants-one-place-for-every-tunable-number","Constants: One Place for Every Tunable Number",[104,32404,32406],{"className":106,"code":32405,"language":108,"meta":48,"style":48},"public final class IntakeConstants\n{\n    public static final int MOTOR_CHANNEL = 5; \u002F\u002F PWM channel\n    public static final double INTAKE_SPEED = 0.8;\n}\n",[95,32407,32408,32413,32417,32422,32427],{"__ignoreMap":48},[112,32409,32410],{"class":114,"line":115},[112,32411,32412],{},"public final class IntakeConstants\n",[112,32414,32415],{"class":114,"line":49},[112,32416,123],{},[112,32418,32419],{"class":114,"line":126},[112,32420,32421],{},"    public static final int MOTOR_CHANNEL = 5; \u002F\u002F PWM channel\n",[112,32423,32424],{"class":114,"line":132},[112,32425,32426],{},"    public static final double INTAKE_SPEED = 0.8;\n",[112,32428,32429],{"class":114,"line":138},[112,32430,153],{},[15,32432,32433,32434,32436,32437,32440,32441,32443,32444,32446],{},"Every constant is ",[95,32435,11360],{}," and named in ALL_CAPS — the constants convention from Lesson 7.4, which WPILib 2027's own template uses too (",[95,32438,32439],{},"DRIVER_CONTROLLER_PORT","). The template gives each topic its own small class in the ",[95,32442,32103],{}," package; marking the class ",[95,32445,381],{}," means nothing can extend it. Changing one tunable value, like the intake speed, means editing exactly one line.",[69,32448,32450],{"id":32449},"choosing-how-to-define-a-reusable-command","Choosing How to Define a Reusable Command",[15,32452,32453],{},"For a command that's used in more than one place (a button binding, an autonomous routine, a self-test), a few options exist, each suited to a different case:",[19,32455,32456,32468,32477],{},[22,32457,32458,32461,32462,32464,32465,79],{},[25,32459,32460],{},"Instance factory method on a single mechanism"," (the ",[95,32463,29077],{}," factories from Lesson 25.2) — best for a command tied to exactly one mechanism: ",[95,32466,32467],{},"shooter.spinUpCommand()",[22,32469,32470,32473,32474,32476],{},[25,32471,32472],{},"Static factory method"," (Ch.21) — best when a command needs to coordinate ",[494,32475,18477],{}," mechanisms at once, so it doesn't naturally belong to any single one of them.",[22,32478,32479,32484],{},[25,32480,24422,32481],{},[95,32482,32483],{},"implements Command"," — best when a command needs its own genuine internal state (not mechanism state) or unusually complex logic.",[104,32486,32488],{"className":106,"code":32487,"language":108,"meta":48,"style":48},"public class Shooter implements Mechanism\n{\n    \u002F\u002F built with run(...), so it implicitly requires `this` shooter\n    public Command spinUpCommand()\n    {\n        return run(coroutine -> {\n            setSpeed(ShooterConstants.SPIN_SPEED);\n            coroutine.park();\n        }).whenExited(() -> setSpeed(0.0)).named(\"Spin Up\");\n    }\n}\n",[95,32489,32490,32495,32499,32504,32509,32513,32518,32523,32528,32533,32537],{"__ignoreMap":48},[112,32491,32492],{"class":114,"line":115},[112,32493,32494],{},"public class Shooter implements Mechanism\n",[112,32496,32497],{"class":114,"line":49},[112,32498,123],{},[112,32500,32501],{"class":114,"line":126},[112,32502,32503],{},"    \u002F\u002F built with run(...), so it implicitly requires `this` shooter\n",[112,32505,32506],{"class":114,"line":132},[112,32507,32508],{},"    public Command spinUpCommand()\n",[112,32510,32511],{"class":114,"line":138},[112,32512,135],{},[112,32514,32515],{"class":114,"line":144},[112,32516,32517],{},"        return run(coroutine -> {\n",[112,32519,32520],{"class":114,"line":150},[112,32521,32522],{},"            setSpeed(ShooterConstants.SPIN_SPEED);\n",[112,32524,32525],{"class":114,"line":2276},[112,32526,32527],{},"            coroutine.park();\n",[112,32529,32530],{"class":114,"line":2282},[112,32531,32532],{},"        }).whenExited(() -> setSpeed(0.0)).named(\"Spin Up\");\n",[112,32534,32535],{"class":114,"line":2288},[112,32536,147],{},[112,32538,32539],{"class":114,"line":5760},[112,32540,153],{},[104,32542,32544],{"className":106,"code":32543,"language":108,"meta":48,"style":48},"public final class Autos\n{\n    public static Command driveThenShoot(Drive drive, Shooter shooter)\n    {\n        return Command.sequence(\n            drive.driveForwardCommand().withTimeout(Seconds.of(2)),\n            shooter.shootCommand()\n        ).named(\"Drive Then Shoot\");\n    }\n}\n",[95,32545,32546,32551,32555,32560,32564,32569,32574,32579,32584,32588],{"__ignoreMap":48},[112,32547,32548],{"class":114,"line":115},[112,32549,32550],{},"public final class Autos\n",[112,32552,32553],{"class":114,"line":49},[112,32554,123],{},[112,32556,32557],{"class":114,"line":126},[112,32558,32559],{},"    public static Command driveThenShoot(Drive drive, Shooter shooter)\n",[112,32561,32562],{"class":114,"line":132},[112,32563,135],{},[112,32565,32566],{"class":114,"line":138},[112,32567,32568],{},"        return Command.sequence(\n",[112,32570,32571],{"class":114,"line":144},[112,32572,32573],{},"            drive.driveForwardCommand().withTimeout(Seconds.of(2)),\n",[112,32575,32576],{"class":114,"line":150},[112,32577,32578],{},"            shooter.shootCommand()\n",[112,32580,32581],{"class":114,"line":2276},[112,32582,32583],{},"        ).named(\"Drive Then Shoot\");\n",[112,32585,32586],{"class":114,"line":2282},[112,32587,147],{},[112,32589,32590],{"class":114,"line":2288},[112,32591,153],{},[15,32593,32594,32595,32597],{},"A multi-mechanism routine can also be written in the ",[95,32596,30016],{}," style from Lesson 25.2, so each mechanism is claimed only while its step runs.",[69,32599,32601],{"id":32600},"reading-commands-v2-code-2026-and-earlier","Reading Commands v2 Code (2026 and Earlier)",[15,32603,32604,32605,32608,32609,32612,32613,32616],{},"Commands v2 is what most existing team code — including older code of our own — still uses, and it's what most examples online show. This section is for ",[25,32606,32607],{},"recognizing"," v2 code when you read it, not for writing new code: new code in this course is v3. (In 2026 and earlier, v2 lives in the package ",[95,32610,32611],{},"edu.wpi.first.wpilibj2.command","; WPILib 2027 still ships it as ",[95,32614,32615],{},"org.wpilib.command2"," for teams that haven't moved over yet.)",[15,32618,32619],{},"Here is one v2 mechanism and one v2 command class, with notes on what each piece became:",[104,32621,32623],{"className":106,"code":32622,"language":108,"meta":48,"style":48},"\u002F\u002F Commands v2 (2026 and earlier): for recognizing, not for writing new code\npublic class Intake extends SubsystemBase    \u002F\u002F v3: implements Mechanism\n{\n    public Command runCommand()\n    {\n        \u002F\u002F v3: run(...) with park(), plus whenExited(...), plus .named(...)\n        return startEnd(() -> set(0.8), () -> set(0.0));\n    }\n}\n\npublic class FeedUntilLoaded extends Command  \u002F\u002F v3: one factory method with one body\n{\n    private final Intake intake;\n\n    public FeedUntilLoaded(Intake intake)\n    {\n        this.intake = intake;\n        addRequirements(intake);              \u002F\u002F v3: requirements come from the builder\n    }\n\n    @Override\n    public void initialize() { intake.set(0.6); }            \u002F\u002F v3: code before the loop\n\n    @Override\n    public boolean isFinished() { return intake.hasPiece(); } \u002F\u002F v3: the loop condition\n\n    @Override\n    public void end(boolean interrupted) { intake.set(0.0); } \u002F\u002F v3: whenExited(...)\n}\n",[95,32624,32625,32630,32635,32639,32644,32648,32653,32658,32662,32666,32670,32675,32679,32684,32688,32693,32697,32702,32707,32711,32715,32719,32724,32728,32732,32737,32741,32745,32750],{"__ignoreMap":48},[112,32626,32627],{"class":114,"line":115},[112,32628,32629],{},"\u002F\u002F Commands v2 (2026 and earlier): for recognizing, not for writing new code\n",[112,32631,32632],{"class":114,"line":49},[112,32633,32634],{},"public class Intake extends SubsystemBase    \u002F\u002F v3: implements Mechanism\n",[112,32636,32637],{"class":114,"line":126},[112,32638,123],{},[112,32640,32641],{"class":114,"line":132},[112,32642,32643],{},"    public Command runCommand()\n",[112,32645,32646],{"class":114,"line":138},[112,32647,135],{},[112,32649,32650],{"class":114,"line":144},[112,32651,32652],{},"        \u002F\u002F v3: run(...) with park(), plus whenExited(...), plus .named(...)\n",[112,32654,32655],{"class":114,"line":150},[112,32656,32657],{},"        return startEnd(() -> set(0.8), () -> set(0.0));\n",[112,32659,32660],{"class":114,"line":2276},[112,32661,147],{},[112,32663,32664],{"class":114,"line":2282},[112,32665,153],{},[112,32667,32668],{"class":114,"line":2288},[112,32669,907],{"emptyLinePlaceholder":55},[112,32671,32672],{"class":114,"line":5760},[112,32673,32674],{},"public class FeedUntilLoaded extends Command  \u002F\u002F v3: one factory method with one body\n",[112,32676,32677],{"class":114,"line":5766},[112,32678,123],{},[112,32680,32681],{"class":114,"line":5772},[112,32682,32683],{},"    private final Intake intake;\n",[112,32685,32686],{"class":114,"line":5777},[112,32687,907],{"emptyLinePlaceholder":55},[112,32689,32690],{"class":114,"line":5783},[112,32691,32692],{},"    public FeedUntilLoaded(Intake intake)\n",[112,32694,32695],{"class":114,"line":5789},[112,32696,135],{},[112,32698,32699],{"class":114,"line":5794},[112,32700,32701],{},"        this.intake = intake;\n",[112,32703,32704],{"class":114,"line":10057},[112,32705,32706],{},"        addRequirements(intake);              \u002F\u002F v3: requirements come from the builder\n",[112,32708,32709],{"class":114,"line":10062},[112,32710,147],{},[112,32712,32713],{"class":114,"line":13813},[112,32714,907],{"emptyLinePlaceholder":55},[112,32716,32717],{"class":114,"line":13818},[112,32718,21735],{},[112,32720,32721],{"class":114,"line":13824},[112,32722,32723],{},"    public void initialize() { intake.set(0.6); }            \u002F\u002F v3: code before the loop\n",[112,32725,32726],{"class":114,"line":13830},[112,32727,907],{"emptyLinePlaceholder":55},[112,32729,32730],{"class":114,"line":13835},[112,32731,21735],{},[112,32733,32734],{"class":114,"line":13840},[112,32735,32736],{},"    public boolean isFinished() { return intake.hasPiece(); } \u002F\u002F v3: the loop condition\n",[112,32738,32739],{"class":114,"line":13845},[112,32740,907],{"emptyLinePlaceholder":55},[112,32742,32743],{"class":114,"line":13850},[112,32744,21735],{},[112,32746,32747],{"class":114,"line":13856},[112,32748,32749],{},"    public void end(boolean interrupted) { intake.set(0.0); } \u002F\u002F v3: whenExited(...)\n",[112,32751,32752],{"class":114,"line":13861},[112,32753,153],{},[3819,32755,32756,32765],{},[3822,32757,32758],{},[3825,32759,32760,32762],{},[3828,32761,29397],{},[3828,32763,32764],{},"In v3 you write",[3838,32766,32767,32779,32802,32813,32831,32844,32864,32876,32888,32902,32913],{},[3825,32768,32769,32774],{},[3843,32770,32771],{},[95,32772,32773],{},"extends SubsystemBase",[3843,32775,32776,32778],{},[95,32777,29005],{}," (an interface)",[3825,32780,32781,32792],{},[3843,32782,32783,322,32785,322,32787,322,32789],{},[95,32784,29353],{},[95,32786,29366],{},[95,32788,29379],{},[95,32790,32791],{},"end(interrupted)",[3843,32793,32794,32795,32797,32798,176,32800],{},"one coroutine body: code before the loop, a loop ending in ",[95,32796,29322],{},", code after, plus ",[95,32799,29590],{},[95,32801,29599],{},[3825,32803,32804,32809],{},[3843,32805,32806],{},[95,32807,32808],{},"CommandScheduler.getInstance()",[3843,32810,32811],{},[95,32812,29101],{},[3825,32814,32815,32820],{},[3843,32816,32817],{},[95,32818,32819],{},"RobotContainer",[3843,32821,32822,32825,32826,176,32828,32830],{},[95,32823,32824],{},"Robot extends OpModeRobot",", plus ",[95,32827,32247],{},[95,32829,32250],{}," opmode classes",[3825,32832,32833,32837],{},[3843,32834,32835],{},[95,32836,29405],{},[3843,32838,32839,32840,322,32842],{},"requirements from the builder: ",[95,32841,29963],{},[95,32843,29966],{},[3825,32845,32846,32859],{},[3843,32847,32848,2150,32851,322,32854,7903,32856,32858],{},[95,32849,32850],{},"InterruptionBehavior",[95,32852,32853],{},"CANCEL_SELF",[95,32855,30305],{},[95,32857,30309],{}," in older code)",[3843,32860,32861,32862],{},"priorities: ",[95,32863,29445],{},[3825,32865,32866,32871],{},[3843,32867,32868],{},[95,32869,32870],{},"Commands.runOnce(() -> ..., mechanism)",[3843,32872,32873],{},[95,32874,32875],{},"mechanism.run(coroutine -> ...).named(\"...\")",[3825,32877,32878,32883],{},[3843,32879,32880],{},[95,32881,32882],{},"withTimeout(1.5)",[3843,32884,32885],{},[95,32886,32887],{},"withTimeout(Seconds.of(1.5))",[3825,32889,32890,32896],{},[3843,32891,32892,32893,32895],{},"a subsystem's ",[95,32894,17077],{}," method",[3843,32897,32898,32899,32901],{},"a default command (or ",[95,32900,30160],{}," for data only)",[3825,32903,32904,32910],{},[3843,32905,32906,32907],{},"cancel the auto command in ",[95,32908,32909],{},"teleopInit()",[3843,32911,32912],{},"nothing to write: scopes cancel it",[3825,32914,32915,32921],{},[3843,32916,32917,32918],{},"constants named like ",[95,32919,32920],{},"kMotorId",[3843,32922,32917,32923],{},[95,32924,32925],{},"MOTOR_CHANNEL",[15,32927,32928,32929,32932,32933,32935],{},"Two more v2 habits you'll spot: v2 commands don't have to be named, and v2 compositions like ",[95,32930,32931],{},"Commands.sequence(...)"," return a finished command, with no ",[95,32934,29825],{}," at the end.",[69,32937,462],{"id":461},[19,32939,32940,32952,32964,32973],{},[22,32941,32942,32948,32949,32951],{},[25,32943,32944,32945,32947],{},"Declaring mechanisms as ",[95,32946,179],{}," fields for easy access."," Global mechanisms let any code anywhere call their methods directly, bypassing the scheduler's resource management — opmodes reach them through the ",[95,32950,20602],{}," passed to their constructor instead.",[22,32953,32954,32957,32958,32960,32961,32963],{},[25,32955,32956],{},"Scheduling an autonomous routine in the opmode's constructor."," The constructor runs when the opmode is ",[494,32959,32301],{},", while the robot is still disabled; schedule the routine in ",[95,32962,32305],{},", which runs when the robot is enabled.",[22,32965,32966,32972],{},[25,32967,32968,32969,32971],{},"Scattering constants across many files instead of the ",[95,32970,32103],{}," package."," Changing one tunable value (like an intake speed) should mean editing exactly one line, not hunting across the codebase.",[22,32974,32975,32978,32979,322,32982,325,32985,32988],{},[25,32976,32977],{},"Pasting v2 code into a v3 project."," Names like ",[95,32980,32981],{},"SubsystemBase",[95,32983,32984],{},"Commands.runOnce",[95,32986,32987],{},"CommandScheduler"," don't exist in v3; translate the code with the table above instead of mixing the two frameworks.",[69,32990,501],{"id":500},[19,32992,32993,33015,33024,33033,33039,33045],{},[22,32994,32995,32996,32998,32999,33001,33002,176,33004,33006,33007,33009,33010,33012,33013,32971],{},"WPILib 2027's Commands v3 template has a thin ",[95,32997,20602],{}," (extends ",[95,33000,32113],{},"), one class per opmode (",[95,33003,32247],{},[95,33005,32250],{},", implementing ",[95,33008,32243],{},"), a ",[95,33011,32103],{}," package, and a ",[95,33014,32106],{},[22,33016,33017,33020,33021,33023],{},[95,33018,33019],{},"Robot.robotPeriodic()"," must call ",[95,33022,30476],{}," — nothing works without this line.",[22,33025,33026,33027,33029,33030,33032],{},"Each opmode receives the ",[95,33028,20602],{}," in its constructor (dependency injection); bindings made there only work while that opmode is selected, and autonomous routines are scheduled in ",[95,33031,32305],{}," and canceled automatically when the mode ends.",[22,33034,33035,33036,33038],{},"Constants are ",[95,33037,11360],{},", ALL_CAPS, grouped by topic.",[22,33040,33041,33042,33044],{},"Choose how to define a reusable command based on its shape: instance factory (one mechanism), static factory (several mechanisms), or a class that ",[95,33043,32483],{}," (real internal state or complex logic).",[22,33046,33047,33048,33050,33051,322,33054,325,33056,33058],{},"Most existing team code is Commands v2: recognize ",[95,33049,32981],{},", the four lifecycle methods, ",[95,33052,33053],{},"addRequirements",[95,33055,32987],{},[95,33057,32819],{},", and translate them to v3 rather than mixing frameworks.",[15,33060,544,33061,548,33063,33066,33067,33070,33071,33074,33075,2150,33077,322,33080,33082,33083,322,33086,1282],{},[95,33062,17008],{},[95,33064,33065],{},"wpilib\u002Fcommand-based\u002F04-subsystems.md"," (WPILIB 20.4), ",[95,33068,33069],{},"06-structuring-command-based-project.md"," (WPILIB 20.6), ",[95,33072,33073],{},"07-organizing-command-based.md"," (WPILIB 20.7); updated for Commands v3 from allwpilib ",[95,33076,101],{},[95,33078,33079],{},"wpilibjExamples\u002F…\u002Ftemplates\u002Fcommandv3\u002F",[95,33081,29197],{}," example, ",[95,33084,33085],{},"wpilibj\u002F…\u002Fframework\u002FOpModeRobot.java",[95,33087,33088],{},"wpilibj\u002F…\u002Fopmode\u002FOpMode.java",[554,33090,556],{},{"title":48,"searchDepth":49,"depth":49,"links":33092},[33093,33094,33095,33096,33097,33098,33099,33100],{"id":32078,"depth":49,"text":32079},{"id":32117,"depth":49,"text":32118},{"id":32236,"depth":49,"text":32237},{"id":32401,"depth":49,"text":32402},{"id":32449,"depth":49,"text":32450},{"id":32600,"depth":49,"text":32601},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":33102,"status":33103},"25.7 — Structuring a Command-Based Robot Project (WPILIB 20.4,6-7)","new — authored lesson (rewritten for the WPILib 2027 Commands v3 template; v2 reading section added)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F7-structuring-a-command-based-robot-project",{"title":32070,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.7-structuring-a-command-based-robot-project","_Fk3k8WnHOsO5uOS3OyaQYT1gWGDUQgA1h9b5BirDJI",{"id":33109,"title":33110,"body":33111,"description":33118,"extension":51,"meta":33709,"navigation":55,"path":33711,"seo":33712,"stem":33713,"__hash__":33714},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch26-architecture-takeaways\u002F26-architecture-takeaways.md","Architecture Takeaways",{"type":8,"value":33112,"toc":33701},[33113,33116,33119,33123,33129,33178,33182,33191,33276,33280,33283,33292,33368,33383,33389,33395,33541,33554,33643,33647,33650,33652,33676,33678,33692,33699],[11,33114,33110],{"id":33115},"architecture-takeaways",[15,33117,33118],{},"Java II opened (Ch.14) with why patterns matter at all. This chapter closes out Java II's core sequence by naming the general software-engineering principles that everything since — inheritance, interfaces, the IO-Layer Pattern, factories, builders, command-based itself — has actually been demonstrating in FRC-specific form. These aren't FRC-specific or Java-specific ideas; they're widely known across the software industry, which is exactly why they're worth naming explicitly.",[69,33120,33122],{"id":33121},"dry-dont-repeat-yourself","DRY: Don't Repeat Yourself",[15,33124,33125,33126,33128],{},"If the same logic (or the same literal value) appears in more than one place, a future change has to remember to update every copy — and it's easy to miss one. The fix is almost always one of the tools this curriculum already covered: pull shared behavior into a common superclass (Ch.17), a shared utility method, or a single ",[95,33127,11437],{}," class (Ch.25.7) instead of copy-pasting a magic number into five different files.",[104,33130,33132],{"className":106,"code":33131,"language":108,"meta":48,"style":48},"\u002F\u002F NOT DRY — the same speed value is hardcoded in three places\nintakeMotor.setThrottle(0.8);\nindexerMotor.setThrottle(0.8);\nfeederMotor.setThrottle(0.8);\n\n\u002F\u002F DRY — one named constant, one place to change it\nintakeMotor.setThrottle(IntakeConstants.ROLLER_SPEED);\nindexerMotor.setThrottle(IntakeConstants.ROLLER_SPEED);\nfeederMotor.setThrottle(IntakeConstants.ROLLER_SPEED);\n",[95,33133,33134,33139,33144,33149,33154,33158,33163,33168,33173],{"__ignoreMap":48},[112,33135,33136],{"class":114,"line":115},[112,33137,33138],{},"\u002F\u002F NOT DRY — the same speed value is hardcoded in three places\n",[112,33140,33141],{"class":114,"line":49},[112,33142,33143],{},"intakeMotor.setThrottle(0.8);\n",[112,33145,33146],{"class":114,"line":126},[112,33147,33148],{},"indexerMotor.setThrottle(0.8);\n",[112,33150,33151],{"class":114,"line":132},[112,33152,33153],{},"feederMotor.setThrottle(0.8);\n",[112,33155,33156],{"class":114,"line":138},[112,33157,907],{"emptyLinePlaceholder":55},[112,33159,33160],{"class":114,"line":144},[112,33161,33162],{},"\u002F\u002F DRY — one named constant, one place to change it\n",[112,33164,33165],{"class":114,"line":150},[112,33166,33167],{},"intakeMotor.setThrottle(IntakeConstants.ROLLER_SPEED);\n",[112,33169,33170],{"class":114,"line":2276},[112,33171,33172],{},"indexerMotor.setThrottle(IntakeConstants.ROLLER_SPEED);\n",[112,33174,33175],{"class":114,"line":2282},[112,33176,33177],{},"feederMotor.setThrottle(IntakeConstants.ROLLER_SPEED);\n",[69,33179,33181],{"id":33180},"yagni-you-aint-gonna-need-it","YAGNI: You Ain't Gonna Need It",[15,33183,33184,33185,33187,33188,33190],{},"Don't build flexibility or abstraction for a requirement that doesn't exist yet — every layer of abstraction (a ",[95,33186,26822],{},", Ch.22; a generic type, Ch.16; an extra interface) has a real cost in complexity, and that cost is only worth paying once the actual need shows up. A ",[95,33189,26822],{}," for a 2-parameter class, or a factory (Ch.21) that only ever returns one concrete implementation, is YAGNI in practice: solving a problem the code doesn't actually have yet, at the expense of a codebase that's harder to read today for a payoff that may never arrive.",[104,33192,33194],{"className":106,"code":33193,"language":108,"meta":48,"style":48},"\u002F\u002F YAGNI violation — a Builder for a class that only ever needs two values\npublic class FieldPosition\n{\n    public static class Builder\n    {\n        private double x, y;\n        public Builder x(double x) { this.x = x; return this; }\n        public Builder y(double y) { this.y = y; return this; }\n        public FieldPosition build() { return new FieldPosition(x, y); }\n    }\n    \u002F\u002F ...\n}\n\n\u002F\u002F YAGNI-respecting — a two-parameter constructor is all this ever needs\npublic class FieldPosition\n{\n    public FieldPosition(double x, double y) { \u002F* ... *\u002F }\n}\n",[95,33195,33196,33201,33206,33210,33214,33218,33223,33228,33233,33238,33242,33246,33250,33254,33259,33263,33267,33272],{"__ignoreMap":48},[112,33197,33198],{"class":114,"line":115},[112,33199,33200],{},"\u002F\u002F YAGNI violation — a Builder for a class that only ever needs two values\n",[112,33202,33203],{"class":114,"line":49},[112,33204,33205],{},"public class FieldPosition\n",[112,33207,33208],{"class":114,"line":126},[112,33209,123],{},[112,33211,33212],{"class":114,"line":132},[112,33213,26987],{},[112,33215,33216],{"class":114,"line":138},[112,33217,135],{},[112,33219,33220],{"class":114,"line":144},[112,33221,33222],{},"        private double x, y;\n",[112,33224,33225],{"class":114,"line":150},[112,33226,33227],{},"        public Builder x(double x) { this.x = x; return this; }\n",[112,33229,33230],{"class":114,"line":2276},[112,33231,33232],{},"        public Builder y(double y) { this.y = y; return this; }\n",[112,33234,33235],{"class":114,"line":2282},[112,33236,33237],{},"        public FieldPosition build() { return new FieldPosition(x, y); }\n",[112,33239,33240],{"class":114,"line":2288},[112,33241,147],{},[112,33243,33244],{"class":114,"line":5760},[112,33245,14871],{},[112,33247,33248],{"class":114,"line":5766},[112,33249,153],{},[112,33251,33252],{"class":114,"line":5772},[112,33253,907],{"emptyLinePlaceholder":55},[112,33255,33256],{"class":114,"line":5777},[112,33257,33258],{},"\u002F\u002F YAGNI-respecting — a two-parameter constructor is all this ever needs\n",[112,33260,33261],{"class":114,"line":5783},[112,33262,33205],{},[112,33264,33265],{"class":114,"line":5789},[112,33266,123],{},[112,33268,33269],{"class":114,"line":5794},[112,33270,33271],{},"    public FieldPosition(double x, double y) { \u002F* ... *\u002F }\n",[112,33273,33274],{"class":114,"line":10057},[112,33275,153],{},[69,33277,33279],{"id":33278},"solid-five-principles-one-letter-each","SOLID: Five Principles, One Letter Each",[15,33281,33282],{},"SOLID isn't a single idea — it's an acronym for five distinct principles, each addressing a different way a class or module's design can go wrong. All five show up somewhere in this curriculum already, even though they weren't named until now:",[15,33284,33285,33288,33289,33291],{},[25,33286,33287],{},"S — Single Responsibility."," A class should have one, and only one, reason to change. A ",[95,33290,25778],{}," (Ch.25) that only manages one piece of hardware is a direct application of this — its only job is that hardware, not also handling button bindings or autonomous logic.",[104,33293,33295],{"className":106,"code":33294,"language":108,"meta":48,"style":48},"\u002F\u002F Violates SRP — two unrelated reasons to change live in the same class\npublic class MatchReport\n{\n    public double averageCycleTime(double[] cycleTimes) { \u002F* ... *\u002F }\n    public void printToConsole(double average) { \u002F* ... *\u002F }\n}\n\n\u002F\u002F Follows SRP — each class now has exactly one reason to change\npublic class CycleTimeCalculator\n{\n    public double averageCycleTime(double[] cycleTimes) { \u002F* ... *\u002F }\n}\npublic class ReportPrinter\n{\n    public void printToConsole(double average) { \u002F* ... *\u002F }\n}\n",[95,33296,33297,33302,33307,33311,33316,33321,33325,33329,33334,33339,33343,33347,33351,33356,33360,33364],{"__ignoreMap":48},[112,33298,33299],{"class":114,"line":115},[112,33300,33301],{},"\u002F\u002F Violates SRP — two unrelated reasons to change live in the same class\n",[112,33303,33304],{"class":114,"line":49},[112,33305,33306],{},"public class MatchReport\n",[112,33308,33309],{"class":114,"line":126},[112,33310,123],{},[112,33312,33313],{"class":114,"line":132},[112,33314,33315],{},"    public double averageCycleTime(double[] cycleTimes) { \u002F* ... *\u002F }\n",[112,33317,33318],{"class":114,"line":138},[112,33319,33320],{},"    public void printToConsole(double average) { \u002F* ... *\u002F }\n",[112,33322,33323],{"class":114,"line":144},[112,33324,153],{},[112,33326,33327],{"class":114,"line":150},[112,33328,907],{"emptyLinePlaceholder":55},[112,33330,33331],{"class":114,"line":2276},[112,33332,33333],{},"\u002F\u002F Follows SRP — each class now has exactly one reason to change\n",[112,33335,33336],{"class":114,"line":2282},[112,33337,33338],{},"public class CycleTimeCalculator\n",[112,33340,33341],{"class":114,"line":2288},[112,33342,123],{},[112,33344,33345],{"class":114,"line":5760},[112,33346,33315],{},[112,33348,33349],{"class":114,"line":5766},[112,33350,153],{},[112,33352,33353],{"class":114,"line":5772},[112,33354,33355],{},"public class ReportPrinter\n",[112,33357,33358],{"class":114,"line":5777},[112,33359,123],{},[112,33361,33362],{"class":114,"line":5783},[112,33363,33320],{},[112,33365,33366],{"class":114,"line":5789},[112,33367,153],{},[15,33369,33370,33373,33374,33376,33377,33379,33380,33382],{},[25,33371,33372],{},"O — Open\u002FClosed."," A module should be open for extension, but closed for modification — you should be able to add new behavior without editing code that already works. The IO-Layer Pattern (Ch.20) is a textbook example: adding a brand-new ",[95,33375,26014],{}," implementation never requires touching ",[95,33378,9838],{},"'s own logic, since both implementations honor the same ",[95,33381,24209],{}," contract.",[15,33384,33385,33388],{},[25,33386,33387],{},"L — Liskov Substitution."," A subclass should be usable anywhere its superclass is expected, without breaking anything. This is exactly the is-a substitution test from Ch.17.1 — if substituting a subclass object somewhere a superclass is expected changes the correctness of the code, the inheritance relationship was wrong to begin with.",[15,33390,33391,33394],{},[25,33392,33393],{},"I — Interface Segregation (Ch.19)."," Don't force a class to implement methods it doesn't actually need, just because they're bundled into one large interface. Several small, focused interfaces (each describing one real capability) are preferable to one bloated interface everything is forced to implement in full.",[104,33396,33398],{"className":106,"code":33397,"language":108,"meta":48,"style":48},"\u002F\u002F Violates ISP — every implementer is forced to have a setAngle() method,\n\u002F\u002F even ones that can't rotate\npublic interface PoweredDevice\n{\n    void setThrottle(double speed);\n    void setAngle(double degrees);\n}\n\npublic class Roller implements PoweredDevice\n{\n    public void setThrottle(double speed) { \u002F* ... *\u002F }\n\n    public void setAngle(double degrees) \u002F\u002F forced, unused\n    {\n        throw new UnsupportedOperationException(\"can't rotate\");\n    }\n}\n\n\u002F\u002F Follows ISP — split into focused interfaces; implement only what you actually support\npublic interface Throttled\n{\n    void setThrottle(double speed);\n}\npublic interface Rotatable\n{\n    void setAngle(double degrees);\n}\n\npublic class Roller implements Throttled\n{\n    public void setThrottle(double speed) { \u002F* ... *\u002F }\n}\n",[95,33399,33400,33405,33410,33415,33419,33424,33429,33433,33437,33442,33446,33451,33455,33460,33464,33469,33473,33477,33481,33486,33491,33495,33499,33503,33508,33512,33516,33520,33524,33529,33533,33537],{"__ignoreMap":48},[112,33401,33402],{"class":114,"line":115},[112,33403,33404],{},"\u002F\u002F Violates ISP — every implementer is forced to have a setAngle() method,\n",[112,33406,33407],{"class":114,"line":49},[112,33408,33409],{},"\u002F\u002F even ones that can't rotate\n",[112,33411,33412],{"class":114,"line":126},[112,33413,33414],{},"public interface PoweredDevice\n",[112,33416,33417],{"class":114,"line":132},[112,33418,123],{},[112,33420,33421],{"class":114,"line":138},[112,33422,33423],{},"    void setThrottle(double speed);\n",[112,33425,33426],{"class":114,"line":144},[112,33427,33428],{},"    void setAngle(double degrees);\n",[112,33430,33431],{"class":114,"line":150},[112,33432,153],{},[112,33434,33435],{"class":114,"line":2276},[112,33436,907],{"emptyLinePlaceholder":55},[112,33438,33439],{"class":114,"line":2282},[112,33440,33441],{},"public class Roller implements PoweredDevice\n",[112,33443,33444],{"class":114,"line":2288},[112,33445,123],{},[112,33447,33448],{"class":114,"line":5760},[112,33449,33450],{},"    public void setThrottle(double speed) { \u002F* ... *\u002F }\n",[112,33452,33453],{"class":114,"line":5766},[112,33454,907],{"emptyLinePlaceholder":55},[112,33456,33457],{"class":114,"line":5772},[112,33458,33459],{},"    public void setAngle(double degrees) \u002F\u002F forced, unused\n",[112,33461,33462],{"class":114,"line":5777},[112,33463,135],{},[112,33465,33466],{"class":114,"line":5783},[112,33467,33468],{},"        throw new UnsupportedOperationException(\"can't rotate\");\n",[112,33470,33471],{"class":114,"line":5789},[112,33472,147],{},[112,33474,33475],{"class":114,"line":5794},[112,33476,153],{},[112,33478,33479],{"class":114,"line":10057},[112,33480,907],{"emptyLinePlaceholder":55},[112,33482,33483],{"class":114,"line":10062},[112,33484,33485],{},"\u002F\u002F Follows ISP — split into focused interfaces; implement only what you actually support\n",[112,33487,33488],{"class":114,"line":13813},[112,33489,33490],{},"public interface Throttled\n",[112,33492,33493],{"class":114,"line":13818},[112,33494,123],{},[112,33496,33497],{"class":114,"line":13824},[112,33498,33423],{},[112,33500,33501],{"class":114,"line":13830},[112,33502,153],{},[112,33504,33505],{"class":114,"line":13835},[112,33506,33507],{},"public interface Rotatable\n",[112,33509,33510],{"class":114,"line":13840},[112,33511,123],{},[112,33513,33514],{"class":114,"line":13845},[112,33515,33428],{},[112,33517,33518],{"class":114,"line":13850},[112,33519,153],{},[112,33521,33522],{"class":114,"line":13856},[112,33523,907],{"emptyLinePlaceholder":55},[112,33525,33526],{"class":114,"line":13861},[112,33527,33528],{},"public class Roller implements Throttled\n",[112,33530,33531],{"class":114,"line":26421},[112,33532,123],{},[112,33534,33535],{"class":114,"line":26427},[112,33536,33450],{},[112,33538,33539],{"class":114,"line":26432},[112,33540,153],{},[15,33542,33543,33546,33547,33549,33550,33553],{},[25,33544,33545],{},"D — Dependency Inversion."," Code should depend on abstractions (interfaces), not concrete implementations. Every constructor that accepts an ",[95,33548,24209],{}," instead of hardcoding ",[95,33551,33552],{},"new IntakeIOReal()"," directly (Ch.20\u002F21), and every static factory returning an interface type rather than a specific class (Ch.21), is dependency inversion in action.",[104,33555,33557],{"className":106,"code":33556,"language":108,"meta":48,"style":48},"\u002F\u002F Violates DIP — IntakeController is hardcoded to one concrete implementation\npublic class IntakeController\n{\n    private final IntakeIOReal io = new IntakeIOReal(); \u002F\u002F depends on a concrete class\n    public void run(double speed) { io.setThrottle(speed); }\n}\n\n\u002F\u002F Follows DIP — IntakeController depends on an abstraction, not a concrete class\npublic class IntakeController\n{\n    private final IntakeIO io;\n\n    public IntakeController(IntakeIO io) \u002F\u002F any IntakeIO implementation works\n    {\n        this.io = io;\n    }\n\n    public void run(double speed) { io.setThrottle(speed); }\n}\n",[95,33558,33559,33564,33569,33573,33578,33583,33587,33591,33596,33600,33604,33609,33613,33618,33622,33627,33631,33635,33639],{"__ignoreMap":48},[112,33560,33561],{"class":114,"line":115},[112,33562,33563],{},"\u002F\u002F Violates DIP — IntakeController is hardcoded to one concrete implementation\n",[112,33565,33566],{"class":114,"line":49},[112,33567,33568],{},"public class IntakeController\n",[112,33570,33571],{"class":114,"line":126},[112,33572,123],{},[112,33574,33575],{"class":114,"line":132},[112,33576,33577],{},"    private final IntakeIOReal io = new IntakeIOReal(); \u002F\u002F depends on a concrete class\n",[112,33579,33580],{"class":114,"line":138},[112,33581,33582],{},"    public void run(double speed) { io.setThrottle(speed); }\n",[112,33584,33585],{"class":114,"line":144},[112,33586,153],{},[112,33588,33589],{"class":114,"line":150},[112,33590,907],{"emptyLinePlaceholder":55},[112,33592,33593],{"class":114,"line":2276},[112,33594,33595],{},"\u002F\u002F Follows DIP — IntakeController depends on an abstraction, not a concrete class\n",[112,33597,33598],{"class":114,"line":2282},[112,33599,33568],{},[112,33601,33602],{"class":114,"line":2288},[112,33603,123],{},[112,33605,33606],{"class":114,"line":5760},[112,33607,33608],{},"    private final IntakeIO io;\n",[112,33610,33611],{"class":114,"line":5766},[112,33612,907],{"emptyLinePlaceholder":55},[112,33614,33615],{"class":114,"line":5772},[112,33616,33617],{},"    public IntakeController(IntakeIO io) \u002F\u002F any IntakeIO implementation works\n",[112,33619,33620],{"class":114,"line":5777},[112,33621,135],{},[112,33623,33624],{"class":114,"line":5783},[112,33625,33626],{},"        this.io = io;\n",[112,33628,33629],{"class":114,"line":5789},[112,33630,147],{},[112,33632,33633],{"class":114,"line":5794},[112,33634,907],{"emptyLinePlaceholder":55},[112,33636,33637],{"class":114,"line":10057},[112,33638,33582],{},[112,33640,33641],{"class":114,"line":10062},[112,33642,153],{},[69,33644,33646],{"id":33645},"why-name-these-at-all","Why Name These at All",[15,33648,33649],{},"None of DRY, YAGNI, or SOLID are FRC-specific or even Java-specific — they're widely-used vocabulary across the whole software industry, which is exactly the \"common language\" benefit Ch.14 opened with. Being able to say \"this violates single responsibility\" or \"that's YAGNI\" communicates a specific, well-understood critique in a few words, to any programmer familiar with these terms — not just people who've read this particular curriculum.",[69,33651,462],{"id":461},[19,33653,33654,33660,33670],{},[22,33655,33656,33659],{},[25,33657,33658],{},"Applying DRY so aggressively that unrelated code gets forced together."," Two pieces of code that happen to look similar today, but for unrelated reasons, don't necessarily belong in one shared abstraction — premature DRY-ing can create awkward, tangled dependencies between things that should stay separate.",[22,33661,33662,33665,33666,33669],{},[25,33663,33664],{},"Treating YAGNI as an excuse to never plan ahead."," YAGNI argues against building unneeded flexibility ",[494,33667,33668],{},"now"," — it doesn't mean ignoring architecture altogether; the IO-Layer Pattern (Ch.20) is worth its overhead in FRC precisely because simulation and hardware-swapping are real, common needs, not speculative ones.",[22,33671,33672,33675],{},[25,33673,33674],{},"Only remembering the \"S\" of SOLID."," The common shorthand (\"one class, one responsibility\") is genuinely just Single Responsibility — SOLID names four more distinct principles beyond that one.",[69,33677,501],{"id":500},[19,33679,33680,33683,33686,33689],{},[22,33681,33682],{},"DRY: don't duplicate logic or values — a single source of truth (a constant, a shared method, a superclass) means one place to fix or change something.",[22,33684,33685],{},"YAGNI: don't build abstraction or flexibility for a need that doesn't exist yet — every layer of indirection has a real cost, worth paying only once it's actually needed.",[22,33687,33688],{},"SOLID is five separate principles — Single Responsibility, Open\u002FClosed, Liskov Substitution, Interface Segregation, Dependency Inversion — each already demonstrated somewhere in this curriculum's FRC examples.",[22,33690,33691],{},"These principles are industry-standard vocabulary, not FRC- or Java-specific — naming them precisely is itself a form of the \"common language\" benefit patterns provide (Ch.14).",[15,33693,544,33694,548,33696,33698],{},[95,33695,18431],{},[95,33697,18587],{},", slide 13 (\"Architecture Takeaways\") — original deck content, expanded here since SOLID is a real five-principle acronym the original slide only partially named",[554,33700,556],{},{"title":48,"searchDepth":49,"depth":49,"links":33702},[33703,33704,33705,33706,33707,33708],{"id":33121,"depth":49,"text":33122},{"id":33180,"depth":49,"text":33181},{"id":33278,"depth":49,"text":33279},{"id":33645,"depth":49,"text":33646},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":33710,"status":570},"26 — Architecture Takeaways (DRY\u002FYAGNI\u002FSOLID) (no citation — deck-original content; neither WPILib nor T5817 teach these as named general principles)","\u002Fshockwave-curriculum\u002Flessons\u002Fch26-architecture-takeaways\u002F26-architecture-takeaways",{"title":33110,"description":33118},"shockwave-curriculum\u002Flessons\u002Fch26-architecture-takeaways\u002F26-architecture-takeaways","91dZnz3uUnhLzhuNhpOKMkjHKFFGuU93rWV5d0601Ms",{"id":33716,"title":33717,"body":33718,"description":33931,"extension":51,"meta":33932,"navigation":55,"path":33934,"seo":33935,"stem":33936,"__hash__":33937},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch27-program-design-and-abstraction\u002F27.1-abstraction-and-program-design.md","Abstraction and Program Design",{"type":8,"value":33719,"toc":33922},[33720,33723,33729,33733,33755,33759,33771,33775,33800,33804,33820,33840,33847,33851,33869,33871,33898,33900,33914],[11,33721,33717],{"id":33722},"abstraction-and-program-design",[15,33724,33725,33728],{},[25,33726,33727],{},"⚠ Optional chapter."," This chapter covers general, from-scratch object-oriented design thinking that applies to any Java code, not just FRC robot code — conceptually it could sit anywhere after the basics of classes and objects (Ch.7), and is placed here, after the core Java I\u002FII sequence, as optional additional depth. It's informational, not a required gateway, since real FRC teams build on top of WPILib's already-imposed architecture (command-based, Ch.25) regardless.",[69,33730,33732],{"id":33731},"designing-before-writing-object-oriented-design","Designing Before Writing: Object-Oriented Design",[15,33734,33735,33736,33738,33739,33742,33743,322,33746,325,33748,33751,33752,33754],{},"Before writing a single class, it helps to first decide ",[494,33737,26276],{}," classes a program actually needs, and what data\u002Fbehavior each one owns. A reliable trick: read the problem description and look for the ",[25,33740,33741],{},"nouns"," — they're usually your classes. Given \"the robot has a drivetrain, an intake that picks up game pieces, and a shooter that scores them,\" the nouns ",[95,33744,33745],{},"drivetrain",[95,33747,25472],{},[95,33749,33750],{},"shooter"," are exactly the ",[95,33753,20446],{}," subclasses (Ch.17\u002F20) a real codebase would end up with.",[69,33756,33758],{"id":33757},"uml-class-diagrams","UML Class Diagrams",[15,33760,405,33761,33764,33765,33767,33768,33770],{},[25,33762,33763],{},"UML class diagram"," is a simple box-based sketch of a class — its attributes (instance variables) and methods, with ",[95,33766,1258],{}," marking private members and ",[95,33769,935],{}," marking public ones. These diagrams don't need to be formal; a whiteboard sketch before writing code is often enough to catch a design problem before it's baked into actual Java.",[69,33772,33774],{"id":33773},"data-abstraction-naming-data-without-its-details","Data Abstraction: Naming Data Without Its Details",[15,33776,33777,33780,33781,33783,33784,33787,33788,14274,33790,33792,33793,33796,33797,33799],{},[25,33778,33779],{},"Data abstraction"," separates a data type's abstract properties from the concrete details of how it's represented — you can use an ",[95,33782,9838],{}," object without knowing exactly how its internal state is stored. Ch.7 already introduced the specific vocabulary this curriculum uses for this: ",[25,33785,33786],{},"instance variables"," (unique per object — each ",[95,33789,9838],{},[95,33791,10261],{}," flag) and ",[25,33794,33795],{},"class\u002Fstatic variables"," (shared across every instance — a running count of how many ",[95,33798,9838],{}," objects exist).",[69,33801,33803],{"id":33802},"procedural-abstraction-naming-a-process-without-its-details","Procedural Abstraction: Naming a Process Without Its Details",[15,33805,33806,33809,33810,33812,33813,33815,33816,33819],{},[25,33807,33808],{},"Procedural abstraction"," gives a process a name, letting it be used by knowing ",[494,33811,4416],{}," it does without needing to know ",[494,33814,24117],{}," — calling ",[95,33817,33818],{},"intake.retract()"," doesn't require knowing exactly how the retraction is implemented underneath. This is exactly the value of a well-named method (Ch.4\u002F7): three real benefits fall out of it:",[19,33821,33822,33828,33834],{},[22,33823,33824,33827],{},[25,33825,33826],{},"Organization"," — breaking a large behavior into smaller, named methods keeps any one piece of code manageable.",[22,33829,33830,33833],{},[25,33831,33832],{},"Reuse"," — a method written once can be called from many places, instead of duplicating the same logic (Ch.26's DRY, in disguise).",[22,33835,33836,33839],{},[25,33837,33838],{},"Maintainability"," — smaller, well-named methods are far easier to read, debug, and reason about than one sprawling method doing everything.",[15,33841,33842,33843,33846],{},"Procedural abstraction also means a method's ",[494,33844,33845],{},"internal"," implementation can change freely — made faster, refactored, rewritten — without breaking any code that calls it, as long as the method's signature and its observable behavior stay the same. Adding parameters extends this even further, letting one method generalize across a whole range of inputs instead of needing a separate near-duplicate method for each specific case.",[69,33848,33850],{"id":33849},"applying-this-to-an-frc-robot","Applying This to an FRC Robot",[15,33852,33853,33854,33856,33857,322,33859,322,33861,322,33863,33865,33866,33868],{},"Before writing ",[95,33855,18517],{},", sketching out \"what are the nouns\" for an actual robot — ",[95,33858,365],{},[95,33860,9838],{},[95,33862,20639],{},[95,33864,11675],{}," — and roughly what data\u002Fbehavior each needs, is exactly the kind of upfront design this lesson describes. It's the same thinking that led to the ",[95,33867,20446],{}," abstraction in Ch.17 and Ch.20 in the first place — those weren't arbitrary class boundaries, they came from identifying the real, distinct \"nouns\" in a robot's actual hardware.",[69,33870,462],{"id":461},[19,33872,33873,33879,33888],{},[22,33874,33875,33878],{},[25,33876,33877],{},"Skipping design entirely and writing code directly."," Even a rough five-minute sketch of \"what classes do I need, what does each own\" catches structural mistakes far more cheaply than discovering them after a class already has fifteen unrelated responsibilities.",[22,33880,33881,33884,33885,33887],{},[25,33882,33883],{},"Confusing data abstraction with encapsulation."," They're related but distinct: data abstraction is about naming data without exposing its representation; encapsulation (Ch.7\u002F23) is the specific mechanism (",[95,33886,9905],{}," fields, public accessors) that enforces it.",[22,33889,33890,33893,33894,33897],{},[25,33891,33892],{},"Assuming procedural abstraction only matters for long methods."," Even a short method benefits — naming a two-line calculation ",[95,33895,33896],{},"calculateShooterRPM(distance)"," documents intent in a way the raw calculation alone never does.",[69,33899,501],{"id":500},[19,33901,33902,33905,33908,33911],{},[22,33903,33904],{},"Object-oriented design starts by identifying the nouns in a problem description — they're usually the classes a program needs.",[22,33906,33907],{},"A UML class diagram is a simple, informal way to sketch a class's attributes and methods before writing real code.",[22,33909,33910],{},"Data abstraction separates what data represents from how it's stored; procedural abstraction separates what a method does from how it's implemented.",[22,33912,33913],{},"Procedural abstraction's real payoff: organization, code reuse, and the freedom to change a method's internals without breaking its callers.",[15,33915,544,33916,548,33918,33921],{},[95,33917,547],{},[95,33919,33920],{},"unit-3-class-creation\u002F3.01-abstraction-and-program-design.md"," (CSA 3.1)",{"title":48,"searchDepth":49,"depth":49,"links":33923},[33924,33925,33926,33927,33928,33929,33930],{"id":33731,"depth":49,"text":33732},{"id":33757,"depth":49,"text":33758},{"id":33773,"depth":49,"text":33774},{"id":33802,"depth":49,"text":33803},{"id":33849,"depth":49,"text":33850},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},"⚠ Optional chapter. This chapter covers general, from-scratch object-oriented design thinking that applies to any Java code, not just FRC robot code — conceptually it could sit anywhere after the basics of classes and objects (Ch.7), and is placed here, after the core Java I\u002FII sequence, as optional additional depth. It's informational, not a required gateway, since real FRC teams build on top of WPILib's already-imposed architecture (command-based, Ch.25) regardless.",{"outlineRef":33933,"status":15483},"27.1 — Abstraction and Program Design (CSA 3.1)","\u002Fshockwave-curriculum\u002Flessons\u002Fch27-program-design-and-abstraction\u002F1-abstraction-and-program-design",{"title":33717,"description":33931},"shockwave-curriculum\u002Flessons\u002Fch27-program-design-and-abstraction\u002F27.1-abstraction-and-program-design","gT-5M_nnFKZyirLGlEjKF8Hzy6e9SStHXEalqSzRFcQ",{"id":33939,"title":33940,"body":33941,"description":34081,"extension":51,"meta":34082,"navigation":55,"path":34084,"seo":34085,"stem":34086,"__hash__":34087},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch27-program-design-and-abstraction\u002F27.2-impact-of-program-design.md","Impact of Program Design",{"type":8,"value":33942,"toc":34073},[33943,33946,33951,33955,33961,33965,33975,33979,33986,34004,34015,34019,34022,34024,34044,34046,34065],[11,33944,33940],{"id":33945},"impact-of-program-design",[15,33947,33948,33950],{},[25,33949,33727],{}," Like 27.1, this is general software-engineering context rather than FRC-specific mechanics.",[69,33952,33954],{"id":33953},"system-reliability","System Reliability",[15,33956,33957,33960],{},[25,33958,33959],{},"System reliability"," means a program performs its intended task correctly, under stated conditions, without failure. On a competition robot, reliability isn't abstract — code that only works \"most of the time\" is code that costs matches. Testing under a real range of conditions (a dead battery, a jammed mechanism, a sensor that's disconnected) is what catches failures before they happen on the field rather than during a match.",[69,33962,33964],{"id":33963},"code-has-real-consequences","Code Has Real Consequences",[15,33966,33967,33968,537,33971,33974],{},"Software increasingly has direct impacts on people, not just abstract \"users\" — which is why computing professionals follow codes of ethics such as the ACM Code of Ethics, whose principles include ",[494,33969,33970],{},"Avoid harm",[494,33972,33973],{},"Respect privacy",". Programs affect society, the economy, and culture, and those effects can be beneficial, harmful, or both — sometimes in ways their authors never intended. An FRC robot is a literal example of code controlling a real physical machine: a bug in motor-output code isn't just a wrong number on a screen, it's a real mechanism moving in an unexpected or unsafe way. This is exactly why WPILib's safety defaults exist (motors disabled unless explicitly commanded, a watchdog that stops the robot if code stops responding) — real design decisions made because the code's failures have real physical consequences.",[69,33976,33978],{"id":33977},"legal-and-licensing-considerations","Legal and Licensing Considerations",[15,33980,33981,33982,33985],{},"Programmers reuse other people's code constantly — libraries, examples, WPILib itself, code other teams have published. ",[25,33983,33984],{},"All source code is licensed under its author's terms",", and those terms apply whether or not the code costs anything:",[19,33987,33988,33998],{},[22,33989,33990,33993,33994,33997],{},[25,33991,33992],{},"Open-source code"," is free to use ",[494,33995,33996],{},"under its license"," — and licenses differ. Many require you to keep the author's credit and license notice; some require you to share your own changes under the same license.",[22,33999,34000,34003],{},[25,34001,34002],{},"Code that isn't published as open source"," generally requires the owner's permission — and often payment — before you can incorporate it into your program.",[15,34005,34006,34007,34010,34011,34014],{},"Following those terms matters for two reasons. It's a ",[25,34008,34009],{},"legal"," obligation: licenses are enforceable, and ignoring one can make it unlawful to use or share the program you built. And it's an ",[25,34012,34013],{},"ethical"," one: respecting the work, and the wishes, of the people who wrote the code. That's also why every lesson in this curriculum credits its sources on its \"Derived from\" line. Newer questions are arising too — code produced by AI tools can reproduce licensed code, so where code came from still matters.",[69,34016,34018],{"id":34017},"ethical-questions-in-ai-and-automation","Ethical Questions in AI and Automation",[15,34020,34021],{},"As software takes on more autonomous decision-making — self-driving cars being the most commonly cited example — genuinely hard ethical questions arise: who's responsible when an autonomous system has to make a split-second decision with real consequences? These aren't questions with a clean technical answer, but they're worth being aware of as automation (including AI-assisted coding itself) becomes a bigger part of how software gets built.",[69,34023,462],{"id":461},[19,34025,34026,34032,34038],{},[22,34027,34028,34031],{},[25,34029,34030],{},"Treating \"it compiled\" as equivalent to \"it's reliable.\""," Compiling successfully only means the code is syntactically valid — reliability requires actually testing behavior under realistic (and edge-case) conditions.",[22,34033,34034,34037],{},[25,34035,34036],{},"Reusing code without checking its license."," Every piece of code — open source included — comes with license terms. Easy to copy-paste doesn't mean free of obligations.",[22,34039,34040,34043],{},[25,34041,34042],{},"Assuming design choices are ethically neutral."," A default behavior, a permission granted too broadly, or an untested edge case can carry real consequences for whoever the software ultimately affects.",[69,34045,501],{"id":500},[19,34047,34048,34051,34059,34062],{},[22,34049,34050],{},"System reliability means performing correctly under real, tested conditions — not just \"it worked once.\"",[22,34052,34053,34054,322,34056,34058],{},"Software affects society, the economy, and culture — beneficially or harmfully, often beyond its intended use — which is why codes of ethics (e.g. ACM: ",[494,34055,33970],{},[494,34057,33973],{},") exist. This is especially concrete for FRC, where code directly controls physical hardware.",[22,34060,34061],{},"All source code is licensed under its respective terms — open source is free to use only under its license, other code needs permission — and following those terms is both a legal and an ethical obligation.",[22,34063,34064],{},"Increasingly autonomous software (AI included) raises genuine ethical questions worth being aware of, even without a clean technical answer.",[15,34066,544,34067,548,34069,34072],{},[95,34068,547],{},[95,34070,34071],{},"unit-3-class-creation\u002F3.02-impact-of-program-design.md"," (CSA 3.2)",{"title":48,"searchDepth":49,"depth":49,"links":34074},[34075,34076,34077,34078,34079,34080],{"id":33953,"depth":49,"text":33954},{"id":33963,"depth":49,"text":33964},{"id":33977,"depth":49,"text":33978},{"id":34017,"depth":49,"text":34018},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},"⚠ Optional chapter. Like 27.1, this is general software-engineering context rather than FRC-specific mechanics.",{"outlineRef":34083,"status":15483,"noWorkedExample":55},"27.2 — Impact of Program Design (CSA 3.2)","\u002Fshockwave-curriculum\u002Flessons\u002Fch27-program-design-and-abstraction\u002F2-impact-of-program-design",{"title":33940,"description":34081},"shockwave-curriculum\u002Flessons\u002Fch27-program-design-and-abstraction\u002F27.2-impact-of-program-design","8ucrxjeuDNpyH1C8cdJoUF1MLSlm-YsD_EVmCHneZi8",{"id":34089,"title":34090,"body":34091,"description":34618,"extension":51,"meta":34619,"navigation":55,"path":34621,"seo":34622,"stem":34623,"__hash__":34624},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.1-searching-algorithms.md","Searching Algorithms",{"type":8,"value":34092,"toc":34610},[34093,34096,34101,34105,34111,34165,34176,34179,34183,34186,34260,34282,34286,34303,34406,34430,34434,34452,34506,34513,34529,34531,34565,34567,34600,34608],[11,34094,34090],{"id":34095},"searching-algorithms",[15,34097,34098,34100],{},[25,34099,33727],{}," This chapter deepens the array\u002F2D-array work from Ch.9\u002FCh.10 with two classic algorithms — informational, not required for FRC programming itself.",[69,34102,34104],{"id":34103},"linear-sequential-search","Linear (Sequential) Search",[15,34106,34107,34110],{},[25,34108,34109],{},"Linear search"," checks each element in order until it finds the target or runs out of elements — the same \"check every element\" shape from Ch.9.5, applied specifically to finding a value:",[104,34112,34114],{"className":106,"code":34113,"language":108,"meta":48,"style":48},"public static int sequentialSearch(int[] canBusIds, int target)\n{\n    for (int j = 0; j \u003C canBusIds.length; j++)\n    {\n        if (canBusIds[j] == target)\n        {\n            return j;\n        }\n    }\n    return -1; \u002F\u002F not found\n}\n",[95,34115,34116,34121,34125,34130,34134,34139,34143,34148,34152,34156,34161],{"__ignoreMap":48},[112,34117,34118],{"class":114,"line":115},[112,34119,34120],{},"public static int sequentialSearch(int[] canBusIds, int target)\n",[112,34122,34123],{"class":114,"line":49},[112,34124,123],{},[112,34126,34127],{"class":114,"line":126},[112,34128,34129],{},"    for (int j = 0; j \u003C canBusIds.length; j++)\n",[112,34131,34132],{"class":114,"line":132},[112,34133,135],{},[112,34135,34136],{"class":114,"line":138},[112,34137,34138],{},"        if (canBusIds[j] == target)\n",[112,34140,34141],{"class":114,"line":144},[112,34142,11303],{},[112,34144,34145],{"class":114,"line":150},[112,34146,34147],{},"            return j;\n",[112,34149,34150],{"class":114,"line":2276},[112,34151,11313],{},[112,34153,34154],{"class":114,"line":2282},[112,34155,147],{},[112,34157,34158],{"class":114,"line":2288},[112,34159,34160],{},"    return -1; \u002F\u002F not found\n",[112,34162,34163],{"class":114,"line":5760},[112,34164,153],{},[15,34166,34167,34168,34170,34171,3181,34173,34175],{},"Searching for a ",[95,34169,361],{}," (like an autonomous route name) needs ",[95,34172,7836],{},[95,34174,1921],{}," (Lesson 6.1\u002F13) — comparing object content, not identity.",[15,34177,34178],{},"Linear search's slowest case is a target that isn't present at all — the loop has to check every single element before concluding that. Its fastest case is the target sitting at index 0.",[69,34180,34182],{"id":34181},"linear-search-over-a-2d-array","Linear Search Over a 2D Array",[15,34184,34185],{},"Extending linear search to a 2D array (Ch.10) just means looping through every row and searching within it — the same nested-loop shape from Ch.10.3:",[104,34187,34189],{"className":106,"code":34188,"language":108,"meta":48,"style":48},"private static final double TOLERANCE = 1e-9;\n\npublic static boolean containsFault(double[][] moduleCurrents, double faultValue)\n{\n    for (int row = 0; row \u003C moduleCurrents.length; row++)\n    {\n        for (int col = 0; col \u003C moduleCurrents[row].length; col++)\n        {\n            if (Math.abs(moduleCurrents[row][col] - faultValue) \u003C TOLERANCE)\n            {\n                return true;\n            }\n        }\n    }\n    return false;\n}\n",[95,34190,34191,34196,34200,34205,34209,34213,34217,34222,34226,34231,34235,34240,34244,34248,34252,34256],{"__ignoreMap":48},[112,34192,34193],{"class":114,"line":115},[112,34194,34195],{},"private static final double TOLERANCE = 1e-9;\n",[112,34197,34198],{"class":114,"line":49},[112,34199,907],{"emptyLinePlaceholder":55},[112,34201,34202],{"class":114,"line":126},[112,34203,34204],{},"public static boolean containsFault(double[][] moduleCurrents, double faultValue)\n",[112,34206,34207],{"class":114,"line":132},[112,34208,123],{},[112,34210,34211],{"class":114,"line":138},[112,34212,15634],{},[112,34214,34215],{"class":114,"line":144},[112,34216,135],{},[112,34218,34219],{"class":114,"line":150},[112,34220,34221],{},"        for (int col = 0; col \u003C moduleCurrents[row].length; col++)\n",[112,34223,34224],{"class":114,"line":2276},[112,34225,11303],{},[112,34227,34228],{"class":114,"line":2282},[112,34229,34230],{},"            if (Math.abs(moduleCurrents[row][col] - faultValue) \u003C TOLERANCE)\n",[112,34232,34233],{"class":114,"line":2288},[112,34234,16009],{},[112,34236,34237],{"class":114,"line":5760},[112,34238,34239],{},"                return true;\n",[112,34241,34242],{"class":114,"line":5766},[112,34243,16019],{},[112,34245,34246],{"class":114,"line":5772},[112,34247,11313],{},[112,34249,34250],{"class":114,"line":5777},[112,34251,147],{},[112,34253,34254],{"class":114,"line":5783},[112,34255,16240],{},[112,34257,34258],{"class":114,"line":5789},[112,34259,153],{},[15,34261,34262,34263,959,34266,34268,34269,34271,34272,34275,34276,34278,34279,34281],{},"Two details worth calling out: the inner loop bound is ",[95,34264,34265],{},"moduleCurrents[row].length",[95,34267,15379],{}," — a jagged 2D array (Ch.10) doesn't guarantee every row is the same length, so sizing the inner loop off row 0 alone can skip elements in a longer row, or throw ",[95,34270,12136],{}," on a shorter one. And the comparison uses a small ",[95,34273,34274],{},"TOLERANCE"," constant instead of ",[95,34277,1921],{}," — comparing ",[95,34280,631],{},"s for exact equality is exactly the trap Lesson 2.4 warns about, and it applies here too.",[69,34283,34285],{"id":34284},"binary-search-only-works-on-sorted-data","Binary Search: Only Works on Sorted Data",[15,34287,34288,34291,34292,34295,34296,176,34299,34302],{},[25,34289,34290],{},"Binary search"," is dramatically faster than linear search, but only works on data that's already ",[25,34293,34294],{},"sorted"," — like looking up a name in a phone book by jumping to roughly the right spot, instead of checking every page from the start. It keeps ",[95,34297,34298],{},"left",[95,34300,34301],{},"right"," bounds, checks the middle element, and eliminates half the remaining range every time:",[104,34304,34306],{"className":106,"code":34305,"language":108,"meta":48,"style":48},"public static int binarySearch(int[] sortedTemps, int target)\n{\n    int left = 0;\n    int right = sortedTemps.length - 1;\n    while (left \u003C= right)\n    {\n        int middle = (left + right) \u002F 2;\n        if (target \u003C sortedTemps[middle])\n        {\n            right = middle - 1; \u002F\u002F target must be in the left half\n        }\n        else if (target > sortedTemps[middle])\n        {\n            left = middle + 1;  \u002F\u002F target must be in the right half\n        }\n        else\n        {\n            return middle;      \u002F\u002F found it\n        }\n    }\n    return -1; \u002F\u002F left > right means the range is exhausted — not found\n}\n",[95,34307,34308,34313,34317,34321,34326,34331,34335,34340,34345,34349,34354,34358,34363,34367,34372,34376,34380,34384,34389,34393,34397,34402],{"__ignoreMap":48},[112,34309,34310],{"class":114,"line":115},[112,34311,34312],{},"public static int binarySearch(int[] sortedTemps, int target)\n",[112,34314,34315],{"class":114,"line":49},[112,34316,123],{},[112,34318,34319],{"class":114,"line":126},[112,34320,16328],{},[112,34322,34323],{"class":114,"line":132},[112,34324,34325],{},"    int right = sortedTemps.length - 1;\n",[112,34327,34328],{"class":114,"line":138},[112,34329,34330],{},"    while (left \u003C= right)\n",[112,34332,34333],{"class":114,"line":144},[112,34334,135],{},[112,34336,34337],{"class":114,"line":150},[112,34338,34339],{},"        int middle = (left + right) \u002F 2;\n",[112,34341,34342],{"class":114,"line":2276},[112,34343,34344],{},"        if (target \u003C sortedTemps[middle])\n",[112,34346,34347],{"class":114,"line":2282},[112,34348,11303],{},[112,34350,34351],{"class":114,"line":2288},[112,34352,34353],{},"            right = middle - 1; \u002F\u002F target must be in the left half\n",[112,34355,34356],{"class":114,"line":5760},[112,34357,11313],{},[112,34359,34360],{"class":114,"line":5766},[112,34361,34362],{},"        else if (target > sortedTemps[middle])\n",[112,34364,34365],{"class":114,"line":5772},[112,34366,11303],{},[112,34368,34369],{"class":114,"line":5777},[112,34370,34371],{},"            left = middle + 1;  \u002F\u002F target must be in the right half\n",[112,34373,34374],{"class":114,"line":5783},[112,34375,11313],{},[112,34377,34378],{"class":114,"line":5789},[112,34379,26446],{},[112,34381,34382],{"class":114,"line":5794},[112,34383,11303],{},[112,34385,34386],{"class":114,"line":10057},[112,34387,34388],{},"            return middle;      \u002F\u002F found it\n",[112,34390,34391],{"class":114,"line":10062},[112,34392,11313],{},[112,34394,34395],{"class":114,"line":13813},[112,34396,147],{},[112,34398,34399],{"class":114,"line":13818},[112,34400,34401],{},"    return -1; \u002F\u002F left > right means the range is exhausted — not found\n",[112,34403,34404],{"class":114,"line":13824},[112,34405,153],{},[15,34407,34408,34409,322,34411,34414,34415,176,34417,34419,34420,34423,34424,34427,34428,79],{},"For a ",[95,34410,9142],{},[95,34412,34413],{},"compareTo"," (Ch.6.1) replaces ",[95,34416,5257],{},[95,34418,7919],{}," (which only work on primitives): ",[95,34421,34422],{},"str.compareTo(other)"," returns negative, zero, or positive depending on whether ",[95,34425,34426],{},"str"," sorts before, equal to, or after ",[95,34429,9053],{},[69,34431,34433],{"id":34432},"why-binary-search-is-so-much-faster","Why Binary Search Is So Much Faster",[15,34435,34436,34437,34440,34441,34443,34444,34447,34448,34451],{},"Linear search's worst case takes ",[95,34438,34439],{},"n"," comparisons for ",[95,34442,34439],{}," elements. Binary search's worst case only takes roughly ",[95,34445,34446],{},"log₂(n)"," — each comparison eliminates ",[494,34449,34450],{},"half"," the remaining data, not just one element:",[3819,34453,34454,34467],{},[3822,34455,34456],{},[3825,34457,34458,34461,34464],{},[3828,34459,34460],{},"Elements (n)",[3828,34462,34463],{},"Linear Search",[3828,34465,34466],{},"Binary Search",[3838,34468,34469,34478,34487,34496],{},[3825,34470,34471,34474,34476],{},[3843,34472,34473],{},"8",[3843,34475,34473],{},[3843,34477,1757],{},[3825,34479,34480,34483,34485],{},[3843,34481,34482],{},"16",[3843,34484,34482],{},[3843,34486,607],{},[3825,34488,34489,34492,34494],{},[3843,34490,34491],{},"100",[3843,34493,34491],{},[3843,34495,3863],{},[3825,34497,34498,34501,34503],{},[3843,34499,34500],{},"500",[3843,34502,34500],{},[3843,34504,34505],{},"~9",[15,34507,34508,34509,34512],{},"Doubling the data size costs linear search twice the work, but only costs binary search ",[494,34510,34511],{},"one more comparison",". This growth-rate distinction — O(n) vs. O(log n) in formal terms — is why sorted, frequently-searched data (a large lookup table, a big sorted config file) is worth keeping sorted specifically so binary search stays available.",[15,34514,34515],{},[494,34516,34517,34518,34521,34522,34524,34525,34528],{},"(Aside: ",[95,34519,34520],{},"(left + right) \u002F 2"," can theoretically overflow ",[95,34523,603],{}," on an enormous array; the overflow-safe form is ",[95,34526,34527],{},"left + (right - left) \u002F 2",". Not a concern at these array sizes, but worth knowing it exists.)",[69,34530,462],{"id":461},[19,34532,34533,34539,34551],{},[22,34534,34535,34538],{},[25,34536,34537],{},"Running binary search on unsorted data."," It will return wrong or missing results — binary search's entire correctness depends on the data already being sorted.",[22,34540,34541,34544,34545,34547,34548,34550],{},[25,34542,34543],{},"Assuming binary search requires integers."," It works on anything with a well-defined ordering — ",[95,34546,361],{},"s via ",[95,34549,34413],{},", for instance.",[22,34552,34553,34556,34557,34560,34561,34564],{},[25,34554,34555],{},"Forgetting the loop-ending condition."," Binary search's ",[95,34558,34559],{},"while (left \u003C= right)"," stops the moment the range is exhausted (",[95,34562,34563],{},"left > right",") — a search for something not present must still terminate, not loop forever.",[69,34566,501],{"id":500},[19,34568,34569,34575,34581,34597],{},[22,34570,34571,34572,34574],{},"Linear search checks every element in order; its worst case (not found) requires checking all ",[95,34573,34439],{}," elements.",[22,34576,34577,34578,34580],{},"Binary search only works on sorted data, but eliminates half the remaining range with each comparison — roughly ",[95,34579,34446],{}," comparisons worst case, vastly faster for large data sets.",[22,34582,1396,34583,176,34585,199,34588,34590,34591,176,34593,176,34595,79],{},[95,34584,7836],{},[95,34586,34587],{},"compareTo()",[95,34589,361],{}," comparisons in either algorithm, never ",[95,34592,1921],{},[95,34594,5257],{},[95,34596,7919],{},[22,34598,34599],{},"The gap between linear and binary search's growth rates is exactly why sorted data (Lesson 28.2 covers how to get it that way) is worth maintaining when it's searched often.",[15,34601,544,34602,548,34604,34607],{},[95,34603,547],{},[95,34605,34606],{},"unit-4-data-collections\u002F4.14-searching-algorithms.md"," (CSA 4.14)",[554,34609,556],{},{"title":48,"searchDepth":49,"depth":49,"links":34611},[34612,34613,34614,34615,34616,34617],{"id":34103,"depth":49,"text":34104},{"id":34181,"depth":49,"text":34182},{"id":34284,"depth":49,"text":34285},{"id":34432,"depth":49,"text":34433},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},"⚠ Optional chapter. This chapter deepens the array\u002F2D-array work from Ch.9\u002FCh.10 with two classic algorithms — informational, not required for FRC programming itself.",{"outlineRef":34620,"status":15483},"28.1 — Searching Algorithms (CSA 4.14)","\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F1-searching-algorithms",{"title":34090,"description":34618},"shockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.1-searching-algorithms","RGLFDfXDb-fkRDMEKRlsdpNbnmNTcPjEV8yGcDDS4iY",{"id":34626,"title":34627,"body":34628,"description":33727,"extension":51,"meta":35071,"navigation":55,"path":35073,"seo":35074,"stem":35075,"__hash__":35076},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.2-sorting-algorithms.md","Sorting Algorithms",{"type":8,"value":34629,"toc":35062},[34630,34633,34637,34641,34644,34648,34654,34741,34751,34754,34758,34764,34842,34852,34856,34865,34911,34915,34918,34966,35002,35004,35033,35035,35052,35060],[11,34631,34627],{"id":34632},"sorting-algorithms",[15,34634,34635],{},[25,34636,33727],{},[69,34638,34640],{"id":34639},"why-sort-at-all","Why Sort at All",[15,34642,34643],{},"Binary search (Lesson 28.1) needs sorted data to work, and sorted match-scouting data, sensor logs, or leaderboard scores are simply easier for a human to read. Two straightforward sorting algorithms cover the core idea; a third, more efficient one (merge sort) is covered in Lesson 28.4.",[69,34645,34647],{"id":34646},"selection-sort","Selection Sort",[15,34649,34650,34653],{},[25,34651,34652],{},"Selection sort"," repeatedly finds the smallest remaining value and swaps it into its correct, final position — first position 0, then position 1, and so on:",[104,34655,34657],{"className":106,"code":34656,"language":108,"meta":48,"style":48},"public static void selectionSort(double[] sensorReadings)\n{\n    for (int j = 0; j \u003C sensorReadings.length - 1; j++)\n    {\n        \u002F\u002F assume the current position holds the smallest remaining value\n        int minIndex = j;\n        for (int k = j + 1; k \u003C sensorReadings.length; k++)\n        {\n            if (sensorReadings[k] \u003C sensorReadings[minIndex])\n            {\n                minIndex = k; \u002F\u002F found something smaller — remember its index\n            }\n        }\n        double temp = sensorReadings[j];\n        sensorReadings[j] = sensorReadings[minIndex];\n        sensorReadings[minIndex] = temp;\n    }\n}\n",[95,34658,34659,34664,34668,34673,34677,34682,34687,34692,34696,34701,34705,34710,34714,34718,34723,34728,34733,34737],{"__ignoreMap":48},[112,34660,34661],{"class":114,"line":115},[112,34662,34663],{},"public static void selectionSort(double[] sensorReadings)\n",[112,34665,34666],{"class":114,"line":49},[112,34667,123],{},[112,34669,34670],{"class":114,"line":126},[112,34671,34672],{},"    for (int j = 0; j \u003C sensorReadings.length - 1; j++)\n",[112,34674,34675],{"class":114,"line":132},[112,34676,135],{},[112,34678,34679],{"class":114,"line":138},[112,34680,34681],{},"        \u002F\u002F assume the current position holds the smallest remaining value\n",[112,34683,34684],{"class":114,"line":144},[112,34685,34686],{},"        int minIndex = j;\n",[112,34688,34689],{"class":114,"line":150},[112,34690,34691],{},"        for (int k = j + 1; k \u003C sensorReadings.length; k++)\n",[112,34693,34694],{"class":114,"line":2276},[112,34695,11303],{},[112,34697,34698],{"class":114,"line":2282},[112,34699,34700],{},"            if (sensorReadings[k] \u003C sensorReadings[minIndex])\n",[112,34702,34703],{"class":114,"line":2288},[112,34704,16009],{},[112,34706,34707],{"class":114,"line":5760},[112,34708,34709],{},"                minIndex = k; \u002F\u002F found something smaller — remember its index\n",[112,34711,34712],{"class":114,"line":5766},[112,34713,16019],{},[112,34715,34716],{"class":114,"line":5772},[112,34717,11313],{},[112,34719,34720],{"class":114,"line":5777},[112,34721,34722],{},"        double temp = sensorReadings[j];\n",[112,34724,34725],{"class":114,"line":5783},[112,34726,34727],{},"        sensorReadings[j] = sensorReadings[minIndex];\n",[112,34729,34730],{"class":114,"line":5789},[112,34731,34732],{},"        sensorReadings[minIndex] = temp;\n",[112,34734,34735],{"class":114,"line":5794},[112,34736,147],{},[112,34738,34739],{"class":114,"line":10057},[112,34740,153],{},[15,34742,34743,34744,34747,34748,34750],{},"This is Ch.9.5's running min\u002Fmax pattern, tracking the index of the best value seen so far instead of the value itself, done once per position: the outer loop tracks which position is being filled next; the inner loop always starts at ",[95,34745,34746],{},"j + 1",", since everything before ",[95,34749,5478],{}," is already sorted and shouldn't be re-scanned.",[15,34752,34753],{},"Selection sort takes the same amount of work regardless of the data's initial order — it always scans the entire unsorted remainder to find the minimum, every single pass.",[69,34755,34757],{"id":34756},"insertion-sort","Insertion Sort",[15,34759,34760,34763],{},[25,34761,34762],{},"Insertion sort"," instead takes each element and inserts it into its correct position among the already-sorted elements to its left, shifting larger values right to make room:",[104,34765,34767],{"className":106,"code":34766,"language":108,"meta":48,"style":48},"public static void insertionSort(double[] sensorReadings)\n{\n    for (int j = 1; j \u003C sensorReadings.length; j++)\n    {\n        double temp = sensorReadings[j];\n        int possibleIndex = j;\n        while (possibleIndex > 0 && temp \u003C sensorReadings[possibleIndex - 1])\n        {\n            \u002F\u002F shift right\n            sensorReadings[possibleIndex] = sensorReadings[possibleIndex - 1];\n            possibleIndex--;\n        }\n        \u002F\u002F place temp in its final spot for this pass\n        sensorReadings[possibleIndex] = temp;\n    }\n}\n",[95,34768,34769,34774,34778,34783,34787,34791,34796,34801,34805,34810,34815,34820,34824,34829,34834,34838],{"__ignoreMap":48},[112,34770,34771],{"class":114,"line":115},[112,34772,34773],{},"public static void insertionSort(double[] sensorReadings)\n",[112,34775,34776],{"class":114,"line":49},[112,34777,123],{},[112,34779,34780],{"class":114,"line":126},[112,34781,34782],{},"    for (int j = 1; j \u003C sensorReadings.length; j++)\n",[112,34784,34785],{"class":114,"line":132},[112,34786,135],{},[112,34788,34789],{"class":114,"line":138},[112,34790,34722],{},[112,34792,34793],{"class":114,"line":144},[112,34794,34795],{},"        int possibleIndex = j;\n",[112,34797,34798],{"class":114,"line":150},[112,34799,34800],{},"        while (possibleIndex > 0 && temp \u003C sensorReadings[possibleIndex - 1])\n",[112,34802,34803],{"class":114,"line":2276},[112,34804,11303],{},[112,34806,34807],{"class":114,"line":2282},[112,34808,34809],{},"            \u002F\u002F shift right\n",[112,34811,34812],{"class":114,"line":2288},[112,34813,34814],{},"            sensorReadings[possibleIndex] = sensorReadings[possibleIndex - 1];\n",[112,34816,34817],{"class":114,"line":5760},[112,34818,34819],{},"            possibleIndex--;\n",[112,34821,34822],{"class":114,"line":5766},[112,34823,11313],{},[112,34825,34826],{"class":114,"line":5772},[112,34827,34828],{},"        \u002F\u002F place temp in its final spot for this pass\n",[112,34830,34831],{"class":114,"line":5777},[112,34832,34833],{},"        sensorReadings[possibleIndex] = temp;\n",[112,34835,34836],{"class":114,"line":5783},[112,34837,147],{},[112,34839,34840],{"class":114,"line":5789},[112,34841,153],{},[15,34843,34844,34845,34848,34849,34851],{},"Unlike selection sort, insertion sort is ",[25,34846,34847],{},"adaptive"," — if the data is already (or nearly) sorted, the ",[95,34850,7977],{}," loop's condition fails almost immediately for most elements, doing very little actual shifting. Data that's already sorted descending is insertion sort's worst case, since every element has to shift all the way to the front.",[69,34853,34855],{"id":34854},"comparing-the-two","Comparing the Two",[15,34857,34858,34859,34440,34862,34864],{},"Both algorithms have similar overall growth (roughly ",[95,34860,34861],{},"n²",[95,34863,34439],{}," elements, in the worst case) — but they behave differently depending on the input:",[3819,34866,34867,34877],{},[3822,34868,34869],{},[3825,34870,34871,34873,34875],{},[3828,34872],{},[3828,34874,34647],{},[3828,34876,34757],{},[3838,34878,34879,34890,34900],{},[3825,34880,34881,34884,34887],{},[3843,34882,34883],{},"Already sorted ascending",[3843,34885,34886],{},"No speedup — same work every time",[3843,34888,34889],{},"Much faster — adaptive",[3825,34891,34892,34895,34897],{},[3843,34893,34894],{},"Already sorted descending",[3843,34896,34886],{},[3843,34898,34899],{},"Worst case — maximum shifting",[3825,34901,34902,34905,34908],{},[3843,34903,34904],{},"Typical use",[3843,34906,34907],{},"Simple, predictable cost",[3843,34909,34910],{},"Good when data is already mostly sorted",[69,34912,34914],{"id":34913},"in-real-code","In Real Code",[15,34916,34917],{},"Real Java code almost never hand-writes selection or insertion sort — they're taught here to build the underlying intuition, not because production code should use them. The standard library already provides a sort, and it's both correct and far more heavily optimized than a hand-rolled version:",[104,34919,34921],{"className":106,"code":34920,"language":108,"meta":48,"style":48},"int[] readings = {31, 19, 42, 8, 3};\nArrays.sort(readings); \u002F\u002F sorts the array in place, ascending\n\nList\u003CString> names = new ArrayList\u003C>(List.of(\"Shooter\", \"Intake\", \"Climber\"));\nCollections.sort(names);   \u002F\u002F sorts a List in place\nnames.sort(null);          \u002F\u002F list.sort(...) does the same thing\n\n\u002F\u002F sort by a derived value instead of natural order\nnames.sort(Comparator.comparing(String::length));\n",[95,34922,34923,34928,34933,34937,34942,34947,34952,34956,34961],{"__ignoreMap":48},[112,34924,34925],{"class":114,"line":115},[112,34926,34927],{},"int[] readings = {31, 19, 42, 8, 3};\n",[112,34929,34930],{"class":114,"line":49},[112,34931,34932],{},"Arrays.sort(readings); \u002F\u002F sorts the array in place, ascending\n",[112,34934,34935],{"class":114,"line":126},[112,34936,907],{"emptyLinePlaceholder":55},[112,34938,34939],{"class":114,"line":132},[112,34940,34941],{},"List\u003CString> names = new ArrayList\u003C>(List.of(\"Shooter\", \"Intake\", \"Climber\"));\n",[112,34943,34944],{"class":114,"line":138},[112,34945,34946],{},"Collections.sort(names);   \u002F\u002F sorts a List in place\n",[112,34948,34949],{"class":114,"line":144},[112,34950,34951],{},"names.sort(null);          \u002F\u002F list.sort(...) does the same thing\n",[112,34953,34954],{"class":114,"line":150},[112,34955,907],{"emptyLinePlaceholder":55},[112,34957,34958],{"class":114,"line":2276},[112,34959,34960],{},"\u002F\u002F sort by a derived value instead of natural order\n",[112,34962,34963],{"class":114,"line":2282},[112,34964,34965],{},"names.sort(Comparator.comparing(String::length));\n",[15,34967,34968,176,34971,176,34974,34977,34978,34981,34982,2150,34984,34986,34987,34989,34990,34993,34994,34997,34998,35001],{},[95,34969,34970],{},"Arrays.sort",[95,34972,34973],{},"Collections.sort",[95,34975,34976],{},"list.sort"," with no extra argument rely on the elements' ",[25,34979,34980],{},"natural ordering"," — for that to work, the element type must implement ",[95,34983,19551],{},[95,34985,361],{}," and the wrapper classes already do; ",[95,34988,34413],{},", Ch.6.1, is exactly what they compare with). ",[95,34991,34992],{},"Comparator.comparing(...)"," builds a custom ordering on the fly, for cases where natural ordering isn't what's wanted (like sorting by length instead of alphabetically). And printing an array directly (",[95,34995,34996],{},"System.out.println(readings)",") never shows its contents usefully — ",[95,34999,35000],{},"Arrays.toString(readings)"," is the everyday way to see what's actually inside one.",[69,35003,462],{"id":461},[19,35005,35006,35014,35027],{},[22,35007,35008,35013],{},[25,35009,35010,35011,79],{},"Starting selection sort's inner loop at index 0 instead of ",[95,35012,34746],{}," That re-scans (and can undo) already-correctly-placed elements from earlier passes.",[22,35015,35016,35019,35020,35023,35024,35026],{},[25,35017,35018],{},"Stopping insertion sort's outer loop one element too early."," The loop must run through the entire array (",[95,35021,35022],{},"j \u003C length","), not ",[95,35025,12099],{},", or the very last element never gets inserted into its sorted position.",[22,35028,35029,35032],{},[25,35030,35031],{},"Assuming either algorithm's runtime depends on input order the same way."," Selection sort's cost is fixed regardless of order; insertion sort's genuinely isn't — that's the entire point of calling it adaptive.",[69,35034,501],{"id":500},[19,35036,35037,35040,35043,35049],{},[22,35038,35039],{},"Selection sort repeatedly finds the minimum of the remaining unsorted portion and swaps it into place — same cost regardless of initial order.",[22,35041,35042],{},"Insertion sort inserts each element into its correct position among already-sorted elements to its left, shifting as needed — adaptive, much faster on nearly-sorted data.",[22,35044,35045,35046,35048],{},"Both run roughly ",[95,35047,34861],{}," in the worst case, but real-world performance can differ significantly depending on how sorted the input already is.",[22,35050,35051],{},"Sorted data unlocks binary search (Lesson 28.1) — one reason sorting matters beyond just readability.",[15,35053,544,35054,548,35056,35059],{},[95,35055,547],{},[95,35057,35058],{},"unit-4-data-collections\u002F4.15-sorting-algorithms.md"," (CSA 4.15)",[554,35061,556],{},{"title":48,"searchDepth":49,"depth":49,"links":35063},[35064,35065,35066,35067,35068,35069,35070],{"id":34639,"depth":49,"text":34640},{"id":34646,"depth":49,"text":34647},{"id":34756,"depth":49,"text":34757},{"id":34854,"depth":49,"text":34855},{"id":34913,"depth":49,"text":34914},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":35072,"status":15483},"28.2 — Sorting Algorithms (CSA 4.15)","\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F2-sorting-algorithms",{"title":34627,"description":33727},"shockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.2-sorting-algorithms","qvhCLO_rp9aR0INms3BOdVVlDeDWiJ1yVgwqPzaipso",{"id":35078,"title":35079,"body":35080,"description":33727,"extension":51,"meta":35370,"navigation":55,"path":35372,"seo":35373,"stem":35374,"__hash__":35375},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.3-recursion.md","Recursion",{"type":8,"value":35081,"toc":35362},[35082,35085,35089,35093,35098,35126,35137,35141,35152,35205,35220,35224,35236,35242,35245,35251,35259,35263,35280,35282,35333,35335,35352,35360],[11,35083,35079],{"id":35084},"recursion",[15,35086,35087],{},[25,35088,33727],{},[69,35090,35092],{"id":35091},"a-method-that-calls-itself","A Method That Calls Itself",[15,35094,35095,35097],{},[25,35096,35079],{}," is when a method calls itself — another form of repetition, alongside loops (Ch.5). Without care, this goes wrong immediately:",[104,35099,35101],{"className":106,"code":35100,"language":108,"meta":48,"style":48},"public static void neverEnd()\n{\n    System.out.println(\"This never stops!\");\n    neverEnd(); \u002F\u002F calls itself again, forever\n}\n",[95,35102,35103,35108,35112,35117,35122],{"__ignoreMap":48},[112,35104,35105],{"class":114,"line":115},[112,35106,35107],{},"public static void neverEnd()\n",[112,35109,35110],{"class":114,"line":49},[112,35111,123],{},[112,35113,35114],{"class":114,"line":126},[112,35115,35116],{},"    System.out.println(\"This never stops!\");\n",[112,35118,35119],{"class":114,"line":132},[112,35120,35121],{},"    neverEnd(); \u002F\u002F calls itself again, forever\n",[112,35123,35124],{"class":114,"line":138},[112,35125,153],{},[15,35127,35128,35129,35132,35133,35136],{},"This is ",[25,35130,35131],{},"infinite recursion"," — it eventually crashes with ",[95,35134,35135],{},"StackOverflowError",", since a program can only recurse so deep before running out of space to track all those in-progress calls.",[69,35138,35140],{"id":35139},"two-required-ingredients","Two Required Ingredients",[15,35142,35143,35144,35147,35148,35151],{},"Every well-behaved recursive method needs at least one ",[25,35145,35146],{},"base case"," (a condition that stops the recursion and returns directly, no further self-call) and at least one ",[25,35149,35150],{},"recursive call"," (that moves the problem closer to the base case). The classic example, factorial:",[104,35153,35155],{"className":106,"code":35154,"language":108,"meta":48,"style":48},"public static int factorial(int n)\n{\n    if (n == 0)         \u002F\u002F base case — the smallest input this method answers directly\n    {\n        return 1;\n    }\n    else\n    {\n        return n * factorial(n - 1); \u002F\u002F recursive call — moves toward the base case\n    }\n}\n",[95,35156,35157,35162,35166,35171,35175,35180,35184,35188,35192,35197,35201],{"__ignoreMap":48},[112,35158,35159],{"class":114,"line":115},[112,35160,35161],{},"public static int factorial(int n)\n",[112,35163,35164],{"class":114,"line":49},[112,35165,123],{},[112,35167,35168],{"class":114,"line":126},[112,35169,35170],{},"    if (n == 0)         \u002F\u002F base case — the smallest input this method answers directly\n",[112,35172,35173],{"class":114,"line":132},[112,35174,135],{},[112,35176,35177],{"class":114,"line":138},[112,35178,35179],{},"        return 1;\n",[112,35181,35182],{"class":114,"line":144},[112,35183,147],{},[112,35185,35186],{"class":114,"line":150},[112,35187,14213],{},[112,35189,35190],{"class":114,"line":2276},[112,35191,135],{},[112,35193,35194],{"class":114,"line":2282},[112,35195,35196],{},"        return n * factorial(n - 1); \u002F\u002F recursive call — moves toward the base case\n",[112,35198,35199],{"class":114,"line":2288},[112,35200,147],{},[112,35202,35203],{"class":114,"line":5760},[112,35204,153],{},[15,35206,35207,35208,35211,35212,35215,35216,35219],{},"Every recursive call should shrink the problem: ",[95,35209,35210],{},"factorial","'s call passes ",[95,35213,35214],{},"n - 1",", one step closer to the ",[95,35217,35218],{},"n == 0"," base case that eventually stops the recursion.",[69,35221,35223],{"id":35222},"tracing-the-call-stack","Tracing: The Call Stack",[15,35225,35226,35227,35229,35230,35232,35233,738],{},"Every method call — recursive or not — gets pushed onto the ",[25,35228,17066],{}," (Ch.12) with its own independent copy of local variables and parameters; the call stack is what lets each in-progress call remember exactly where to resume once the call it made returns. Recursion is just the same mechanics applied to a method calling itself repeatedly, so the stack ends up holding several frames for the same method at once, each with its own copy of ",[95,35231,34439],{},". Tracing ",[95,35234,35235],{},"factorial(3)",[104,35237,35240],{"className":35238,"code":35239,"language":6629},[6627],"factorial(3) returns 3 * factorial(2)\nfactorial(2) returns 2 * factorial(1)\nfactorial(1) returns 1 * factorial(0)\nfactorial(0) returns 1\n",[95,35241,35239],{"__ignoreMap":48},[15,35243,35244],{},"Then substituting values back upward from the base case:",[104,35246,35249],{"className":35247,"code":35248,"language":6629},[6627],"factorial(1) returns 1 * factorial(0) = 1 * 1 = 1\nfactorial(2) returns 2 * factorial(1) = 2 * 1 = 2\nfactorial(3) returns 3 * factorial(2) = 3 * 2 = 6\n",[95,35250,35248],{"__ignoreMap":48},[15,35252,35253,35255,35256,79],{},[95,35254,35235],{}," returns ",[95,35257,35258],{},"6",[69,35260,35262],{"id":35261},"why-bother-recursion-for-trees","Why Bother? Recursion for Trees",[15,35264,35265,35266,35269,35270,35272,35273,35276,35277,35279],{},"Any loop can, in principle, be rewritten recursively, and vice versa — so why use recursion at all? It shines on ",[25,35267,35268],{},"branching"," structures (computer scientists call these \"trees\") rather than simple linear ones. A useful mental model: a ",[95,35271,5188],{}," loop for a linear structure like an array (Ch.9), nested loops for a 2D array (Ch.10), and recursion for something that branches — like calculating the total number of subsystems nested inside an equipment group that can itself contain further nested groups, where each nested group is ",[494,35274,35275],{},"the same problem",", just smaller. A ",[95,35278,5188],{}," loop naturally handles \"walk through this flat list\"; it struggles to naturally express \"walk through this, and every branch inside it, and every branch inside those.\"",[69,35281,462],{"id":461},[19,35283,35284,35294,35318,35324],{},[22,35285,35286,35289,35290,35293],{},[25,35287,35288],{},"Forgetting the base case entirely."," Without one, every recursive method is really just ",[95,35291,35292],{},"neverEnd()"," in disguise — infinite recursion and a crash.",[22,35295,35296,476,35299,35301,35302,35304,35305,35307,35308,35310,35311,35313,35314,35317],{},[25,35297,35298],{},"A base case that can be skipped right over.",[95,35300,35210],{},"'s base case only checks ",[95,35303,35218],{}," — call it with a negative ",[95,35306,34439],{}," (or with a step size that never lands exactly on the base value) and the recursive call sails past ",[95,35309,1365],{}," without ever matching it, recursing until ",[95,35312,35135],{},". A safer check is often a range, like ",[95,35315,35316],{},"n \u003C= 0",", rather than an exact match.",[22,35319,35320,35323],{},[25,35321,35322],{},"A recursive call that doesn't actually shrink the problem."," If the argument passed to the next call doesn't move closer to the base case, the recursion never terminates, even with a base case defined.",[22,35325,35326,35329,35330,35332],{},[25,35327,35328],{},"Confusing \"recursion is elegant here\" with \"recursion is required here.\""," Simple linear traversal (an array, a ",[95,35331,361],{},") is usually clearer and more efficient as a loop — recursion earns its keep on genuinely branching structures.",[69,35334,501],{"id":500},[19,35336,35337,35340,35343,35346],{},[22,35338,35339],{},"Recursion is a method calling itself — repetition, like a loop, but structured around self-calls instead of a loop construct.",[22,35341,35342],{},"Every correct recursive method needs a base case (stops the recursion) and a recursive call that moves toward it.",[22,35344,35345],{},"Each recursive call gets its own independent local variables\u002Fparameters, tracked via the call stack — tracing means writing out each call, then substituting values back up from the base case.",[22,35347,35348,35349,35351],{},"Recursion is most valuable for branching (\"tree\") structures — a simple ",[95,35350,5188],{}," loop remains the better tool for flat, linear ones.",[15,35353,544,35354,548,35356,35359],{},[95,35355,547],{},[95,35357,35358],{},"unit-4-data-collections\u002F4.16-recursion.md"," (CSA 4.16)",[554,35361,556],{},{"title":48,"searchDepth":49,"depth":49,"links":35363},[35364,35365,35366,35367,35368,35369],{"id":35091,"depth":49,"text":35092},{"id":35139,"depth":49,"text":35140},{"id":35222,"depth":49,"text":35223},{"id":35261,"depth":49,"text":35262},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},{"outlineRef":35371,"status":15483},"28.3 — Recursion (CSA 4.16)","\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F3-recursion",{"title":35079,"description":33727},"shockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.3-recursion","JE9qi2XoCvA-ad9F-PxMUX5X2E6G2tedU6mCnwm7US8",{"id":35377,"title":35378,"body":35379,"description":35918,"extension":51,"meta":35919,"navigation":55,"path":35921,"seo":35922,"stem":35923,"__hash__":35924},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.4-recursive-searching-and-sorting.md","Recursive Searching and Sorting",{"type":8,"value":35380,"toc":35911},[35381,35384,35389,35393,35404,35508,35525,35529,35547,35561,35636,35646,35785,35809,35816,35822,35828,35832,35838,35855,35857,35880,35882,35901,35909],[11,35382,35378],{"id":35383},"recursive-searching-and-sorting",[15,35385,35386,35388],{},[25,35387,33727],{}," Combines Lessons 28.1-28.3: the same searching\u002Fsorting ideas, rewritten recursively.",[69,35390,35392],{"id":35391},"recursive-binary-search","Recursive Binary Search",[15,35394,35395,35396,176,35398,35400,35401,35403],{},"The iterative binary search from Lesson 28.1 tracks ",[95,35397,34298],{},[95,35399,34301],{}," bounds in loop variables. A recursive version instead passes the shrinking range as parameters, with the range itself doing the job a ",[95,35402,7977],{}," loop's condition did before:",[104,35405,35407],{"className":106,"code":35406,"language":108,"meta":48,"style":48},"public static int recursiveBinarySearch(int[] elements, int start, int end, int target)\n{\n    if (end \u003C start)                          \u002F\u002F base case 1: range is empty — not found\n    {\n        return -1;\n    }\n    int middle = (start + end) \u002F 2;\n    if (target == elements[middle])            \u002F\u002F base case 2: found it\n    {\n        return middle;\n    }\n    else if (target \u003C elements[middle])\n    {\n        \u002F\u002F search the left half\n        return recursiveBinarySearch(elements, start, middle - 1, target);\n    }\n    else\n    {\n        \u002F\u002F search the right half\n        return recursiveBinarySearch(elements, middle + 1, end, target);\n    }\n}\n",[95,35408,35409,35414,35418,35423,35427,35432,35436,35441,35446,35450,35455,35459,35464,35468,35473,35478,35482,35486,35490,35495,35500,35504],{"__ignoreMap":48},[112,35410,35411],{"class":114,"line":115},[112,35412,35413],{},"public static int recursiveBinarySearch(int[] elements, int start, int end, int target)\n",[112,35415,35416],{"class":114,"line":49},[112,35417,123],{},[112,35419,35420],{"class":114,"line":126},[112,35421,35422],{},"    if (end \u003C start)                          \u002F\u002F base case 1: range is empty — not found\n",[112,35424,35425],{"class":114,"line":132},[112,35426,135],{},[112,35428,35429],{"class":114,"line":138},[112,35430,35431],{},"        return -1;\n",[112,35433,35434],{"class":114,"line":144},[112,35435,147],{},[112,35437,35438],{"class":114,"line":150},[112,35439,35440],{},"    int middle = (start + end) \u002F 2;\n",[112,35442,35443],{"class":114,"line":2276},[112,35444,35445],{},"    if (target == elements[middle])            \u002F\u002F base case 2: found it\n",[112,35447,35448],{"class":114,"line":2282},[112,35449,135],{},[112,35451,35452],{"class":114,"line":2288},[112,35453,35454],{},"        return middle;\n",[112,35456,35457],{"class":114,"line":5760},[112,35458,147],{},[112,35460,35461],{"class":114,"line":5766},[112,35462,35463],{},"    else if (target \u003C elements[middle])\n",[112,35465,35466],{"class":114,"line":5772},[112,35467,135],{},[112,35469,35470],{"class":114,"line":5777},[112,35471,35472],{},"        \u002F\u002F search the left half\n",[112,35474,35475],{"class":114,"line":5783},[112,35476,35477],{},"        return recursiveBinarySearch(elements, start, middle - 1, target);\n",[112,35479,35480],{"class":114,"line":5789},[112,35481,147],{},[112,35483,35484],{"class":114,"line":5794},[112,35485,14213],{},[112,35487,35488],{"class":114,"line":10057},[112,35489,135],{},[112,35491,35492],{"class":114,"line":10062},[112,35493,35494],{},"        \u002F\u002F search the right half\n",[112,35496,35497],{"class":114,"line":13813},[112,35498,35499],{},"        return recursiveBinarySearch(elements, middle + 1, end, target);\n",[112,35501,35502],{"class":114,"line":13818},[112,35503,147],{},[112,35505,35506],{"class":114,"line":13824},[112,35507,153],{},[15,35509,35510,35511,35514,35515,35518,35519,35521,35522,35524],{},"This has ",[25,35512,35513],{},"two base cases",": a match at the middle, or an exhausted range. Removing the ",[95,35516,35517],{},"end \u003C start"," check wouldn't cause a true infinite loop — Java would run out of room first: a not-found search keeps calling itself into an already-empty range until it crashes with ",[95,35520,35135],{}," (or, if the array is empty to begin with, an immediate ",[95,35523,12136],{},") — exactly the missing-base-case bug from Lesson 28.3.",[69,35526,35528],{"id":35527},"merge-sort-a-third-sorting-algorithm","Merge Sort: A Third Sorting Algorithm",[15,35530,35531,35532,35534,35535,4875,35538,35541,35542,3181,35545,23721],{},"Selection sort and insertion sort (Lesson 28.2) both cost roughly ",[95,35533,34861],{}," in the worst case. ",[25,35536,35537],{},"Merge sort",[25,35539,35540],{},"divide-and-conquer"," algorithm — like binary search, it splits the problem in half repeatedly, which makes it substantially faster on large data (roughly ",[95,35543,35544],{},"n log n",[95,35546,34861],{},[30144,35548,35549,35552,35555],{},[22,35550,35551],{},"Split the array into two halves.",[22,35553,35554],{},"Recursively sort each half (a single-element array is trivially already sorted — the base case).",[22,35556,35557,35560],{},[25,35558,35559],{},"Merge"," the two now-sorted halves back together, in order.",[104,35562,35564],{"className":106,"code":35563,"language":108,"meta":48,"style":48},"public static void mergeSort(int[] elements)\n{\n    int n = elements.length;\n    int[] temp = new int[n]; \u002F\u002F scratch space used during merging\n    mergeSortHelper(elements, 0, n - 1, temp);\n}\n\nprivate static void mergeSortHelper(int[] elements, int from, int to, int[] temp)\n{\n    if (from >= to) return; \u002F\u002F base case: a range of 0 or 1 elements is already sorted\n    int middle = (from + to) \u002F 2;\n    mergeSortHelper(elements, from, middle, temp);      \u002F\u002F recursively sort the left half\n    mergeSortHelper(elements, middle + 1, to, temp);    \u002F\u002F recursively sort the right half\n    merge(elements, from, middle, to, temp);            \u002F\u002F combine the two sorted halves\n}\n",[95,35565,35566,35571,35575,35580,35585,35590,35594,35598,35603,35607,35612,35617,35622,35627,35632],{"__ignoreMap":48},[112,35567,35568],{"class":114,"line":115},[112,35569,35570],{},"public static void mergeSort(int[] elements)\n",[112,35572,35573],{"class":114,"line":49},[112,35574,123],{},[112,35576,35577],{"class":114,"line":126},[112,35578,35579],{},"    int n = elements.length;\n",[112,35581,35582],{"class":114,"line":132},[112,35583,35584],{},"    int[] temp = new int[n]; \u002F\u002F scratch space used during merging\n",[112,35586,35587],{"class":114,"line":138},[112,35588,35589],{},"    mergeSortHelper(elements, 0, n - 1, temp);\n",[112,35591,35592],{"class":114,"line":144},[112,35593,153],{},[112,35595,35596],{"class":114,"line":150},[112,35597,907],{"emptyLinePlaceholder":55},[112,35599,35600],{"class":114,"line":2276},[112,35601,35602],{},"private static void mergeSortHelper(int[] elements, int from, int to, int[] temp)\n",[112,35604,35605],{"class":114,"line":2282},[112,35606,123],{},[112,35608,35609],{"class":114,"line":2288},[112,35610,35611],{},"    if (from >= to) return; \u002F\u002F base case: a range of 0 or 1 elements is already sorted\n",[112,35613,35614],{"class":114,"line":5760},[112,35615,35616],{},"    int middle = (from + to) \u002F 2;\n",[112,35618,35619],{"class":114,"line":5766},[112,35620,35621],{},"    mergeSortHelper(elements, from, middle, temp);      \u002F\u002F recursively sort the left half\n",[112,35623,35624],{"class":114,"line":5772},[112,35625,35626],{},"    mergeSortHelper(elements, middle + 1, to, temp);    \u002F\u002F recursively sort the right half\n",[112,35628,35629],{"class":114,"line":5777},[112,35630,35631],{},"    merge(elements, from, middle, to, temp);            \u002F\u002F combine the two sorted halves\n",[112,35633,35634],{"class":114,"line":5783},[112,35635,153],{},[15,35637,35638,35641,35642,35645],{},[95,35639,35640],{},"merge"," itself isn't recursive — it's the ordinary loop-based step that does the actual combining, using ",[95,35643,35644],{},"temp"," as scratch space so it isn't overwriting the very values it still needs to compare:",[104,35647,35649],{"className":106,"code":35648,"language":108,"meta":48,"style":48},"private static void merge(int[] elements, int from, int mid, int to, int[] temp)\n{\n    int i = from;     \u002F\u002F next unmerged element in the left half\n    int j = mid + 1;  \u002F\u002F next unmerged element in the right half\n    int k = from;      \u002F\u002F next open slot in temp\n\n    while (i \u003C= mid && j \u003C= to)\n    {\n        if (elements[i] \u003C= elements[j])\n        {\n            temp[k++] = elements[i++];\n        }\n        else\n        {\n            temp[k++] = elements[j++];\n        }\n    }\n    while (i \u003C= mid)   \u002F\u002F copy over whatever's left of the left half\n    {\n        temp[k++] = elements[i++];\n    }\n    while (j \u003C= to)    \u002F\u002F copy over whatever's left of the right half\n    {\n        temp[k++] = elements[j++];\n    }\n    for (int m = from; m \u003C= to; m++) \u002F\u002F copy the merged range back into elements\n    {\n        elements[m] = temp[m];\n    }\n}\n",[95,35650,35651,35656,35660,35665,35670,35675,35679,35684,35688,35693,35697,35702,35706,35710,35714,35719,35723,35727,35732,35736,35741,35745,35750,35754,35759,35763,35768,35772,35777,35781],{"__ignoreMap":48},[112,35652,35653],{"class":114,"line":115},[112,35654,35655],{},"private static void merge(int[] elements, int from, int mid, int to, int[] temp)\n",[112,35657,35658],{"class":114,"line":49},[112,35659,123],{},[112,35661,35662],{"class":114,"line":126},[112,35663,35664],{},"    int i = from;     \u002F\u002F next unmerged element in the left half\n",[112,35666,35667],{"class":114,"line":132},[112,35668,35669],{},"    int j = mid + 1;  \u002F\u002F next unmerged element in the right half\n",[112,35671,35672],{"class":114,"line":138},[112,35673,35674],{},"    int k = from;      \u002F\u002F next open slot in temp\n",[112,35676,35677],{"class":114,"line":144},[112,35678,907],{"emptyLinePlaceholder":55},[112,35680,35681],{"class":114,"line":150},[112,35682,35683],{},"    while (i \u003C= mid && j \u003C= to)\n",[112,35685,35686],{"class":114,"line":2276},[112,35687,135],{},[112,35689,35690],{"class":114,"line":2282},[112,35691,35692],{},"        if (elements[i] \u003C= elements[j])\n",[112,35694,35695],{"class":114,"line":2288},[112,35696,11303],{},[112,35698,35699],{"class":114,"line":5760},[112,35700,35701],{},"            temp[k++] = elements[i++];\n",[112,35703,35704],{"class":114,"line":5766},[112,35705,11313],{},[112,35707,35708],{"class":114,"line":5772},[112,35709,26446],{},[112,35711,35712],{"class":114,"line":5777},[112,35713,11303],{},[112,35715,35716],{"class":114,"line":5783},[112,35717,35718],{},"            temp[k++] = elements[j++];\n",[112,35720,35721],{"class":114,"line":5789},[112,35722,11313],{},[112,35724,35725],{"class":114,"line":5794},[112,35726,147],{},[112,35728,35729],{"class":114,"line":10057},[112,35730,35731],{},"    while (i \u003C= mid)   \u002F\u002F copy over whatever's left of the left half\n",[112,35733,35734],{"class":114,"line":10062},[112,35735,135],{},[112,35737,35738],{"class":114,"line":13813},[112,35739,35740],{},"        temp[k++] = elements[i++];\n",[112,35742,35743],{"class":114,"line":13818},[112,35744,147],{},[112,35746,35747],{"class":114,"line":13824},[112,35748,35749],{},"    while (j \u003C= to)    \u002F\u002F copy over whatever's left of the right half\n",[112,35751,35752],{"class":114,"line":13830},[112,35753,135],{},[112,35755,35756],{"class":114,"line":13835},[112,35757,35758],{},"        temp[k++] = elements[j++];\n",[112,35760,35761],{"class":114,"line":13840},[112,35762,147],{},[112,35764,35765],{"class":114,"line":13845},[112,35766,35767],{},"    for (int m = from; m \u003C= to; m++) \u002F\u002F copy the merged range back into elements\n",[112,35769,35770],{"class":114,"line":13850},[112,35771,135],{},[112,35773,35774],{"class":114,"line":13856},[112,35775,35776],{},"        elements[m] = temp[m];\n",[112,35778,35779],{"class":114,"line":13861},[112,35780,147],{},[112,35782,35783],{"class":114,"line":26421},[112,35784,153],{},[15,35786,35787,35789,35790,35792,35793,35795,35796,35798,35799,35801,35802,35805,35806,35808],{},[95,35788,35640],{}," walks both sorted halves with two pointers (",[95,35791,5244],{}," for the left half, ",[95,35794,5478],{}," for the right), always taking the smaller of the two elements it's currently pointing at into ",[95,35797,35644],{},". Once one half runs out, whatever's left of the other half is already in order, so it just gets copied straight over. The last step copies the merged range from ",[95,35800,35644],{}," back into ",[95,35803,35804],{},"elements",", since ",[95,35807,35804],{}," is the array being sorted in place.",[15,35810,35811,35812,35815],{},"Tracing the split-then-merge structure for ",[95,35813,35814],{},"{86, 3, 43, 5}",", using nested braces:",[104,35817,35820],{"className":35818,"code":35819,"language":6629},[6627],"Split:  { {86, 3} , {43, 5} }\nSplit:  { { {86}, {3} } , { {43}, {5} } }   \u003C- single elements: base case reached\nMerge:  { {3, 86} , {5, 43} }\nMerge:  { 3, 5, 43, 86 }\n",[95,35821,35819],{"__ignoreMap":48},[15,35823,35824,35825,35827],{},"Like selection sort, merge sort's structure doesn't depend on the input's initial order — it always splits and merges the same way. But because its divide-and-conquer approach scales so much better than ",[95,35826,34861],{}," sorting, it's the fastest of the three algorithms in this curriculum, most of the time, especially as the data set grows.",[69,35829,35831],{"id":35830},"iterative-vs-recursive-same-algorithm-different-shape","Iterative vs. Recursive: Same Algorithm, Different Shape",[15,35833,35834,35835,35837],{},"Binary search exists in both forms (Lesson 28.1's iterative version, this lesson's recursive one) — a good concrete reminder of Lesson 28.3's point that many algorithms can be written either way. Iteration is usually preferred in real code (no risk of ",[95,35836,35135],{},", generally a bit more efficient) — but a recursive version can be more compact and can make a divide-and-conquer structure (like merge sort's) much more natural to express than an iterative equivalent would be.",[15,35839,35840],{},[494,35841,35842,35843,35845,35846,537,35849,35852,35853,1566],{},"(Aside: like Lesson 28.1's ",[95,35844,34520],{},", this lesson's ",[95,35847,35848],{},"(start + end) \u002F 2",[95,35850,35851],{},"(from + to) \u002F 2"," have the same theoretical overflow-safe alternative, ",[95,35854,34527],{},[69,35856,462],{"id":461},[19,35858,35859,35865,35874],{},[22,35860,35861,35864],{},[25,35862,35863],{},"Forgetting either base case in recursive binary search."," Both the \"found it\" and \"range exhausted\" cases are needed — missing the exhausted-range check risks infinite recursion on a not-found search.",[22,35866,35867,35870,35871,35873],{},[25,35868,35869],{},"Merging without first ensuring both halves are actually sorted."," Merge sort's ",[95,35872,35640],{}," step assumes its two inputs are already individually sorted — that's exactly what the recursive calls before it guarantee.",[22,35875,35876,35879],{},[25,35877,35878],{},"Assuming recursive is always \"better\" than iterative, or vice versa."," Each has real tradeoffs (stack depth risk vs. code clarity) — the right choice depends on the specific algorithm and data size.",[69,35881,501],{"id":500},[19,35883,35884,35887,35890,35898],{},[22,35885,35886],{},"Recursive binary search replaces loop-tracked bounds with a shrinking range passed as parameters, and needs two base cases: a match, or an exhausted range.",[22,35888,35889],{},"Merge sort is a recursive, divide-and-conquer sort: split in half, recursively sort each half (base case: 1 element), then merge the sorted halves back together.",[22,35891,35892,35893,5154,35895,35897],{},"Merge sort scales better than selection\u002Finsertion sort on large data (",[95,35894,35544],{},[95,35896,34861],{},"), and its performance doesn't depend on the input's initial order.",[22,35899,35900],{},"The same algorithm can often be written iteratively or recursively — the choice is a real tradeoff, not a universal \"better\" answer either way.",[15,35902,544,35903,548,35905,35908],{},[95,35904,547],{},[95,35906,35907],{},"unit-4-data-collections\u002F4.17-recursive-searching-and-sorting.md"," (CSA 4.17)",[554,35910,556],{},{"title":48,"searchDepth":49,"depth":49,"links":35912},[35913,35914,35915,35916,35917],{"id":35391,"depth":49,"text":35392},{"id":35527,"depth":49,"text":35528},{"id":35830,"depth":49,"text":35831},{"id":461,"depth":49,"text":462},{"id":500,"depth":49,"text":501},"⚠ Optional chapter. Combines Lessons 28.1-28.3: the same searching\u002Fsorting ideas, rewritten recursively.",{"outlineRef":35920,"status":15483},"28.4 — Recursive Searching and Sorting (CSA 4.17)","\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F4-recursive-searching-and-sorting",{"title":35378,"description":35918},"shockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.4-recursive-searching-and-sorting","ojiDXTkcnpIAzlAaeKYaJ1oTU1sXBpqXSLlrKt01YKw",{"id":35926,"title":35927,"body":35928,"description":35949,"extension":51,"meta":35950,"navigation":55,"path":35951,"seo":35952,"stem":35953,"__hash__":35954},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch29-git-and-github-basics\u002F29.1-coming-soon.md","Git & GitHub Basics — Coming Soon",{"type":8,"value":35929,"toc":35947},[35930,35933],[11,35931,35927],{"id":35932},"git-github-basics-coming-soon",[15,35934,35935,35938,35939,35942,35943,35946],{},[25,35936,35937],{},"Status:"," placeholder chapter, not authored yet. Pulled from ",[95,35940,35941],{},"mechacoder-full-deck.html","\ninto ",[95,35944,35945],{},"curriculum-ledger.html"," as ch.29 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":35948},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.29 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch29-git-and-github-basics\u002F1-coming-soon",{"title":35927,"description":35949},"shockwave-curriculum\u002Flessons\u002Fch29-git-and-github-basics\u002F29.1-coming-soon","M80FQl3ZkysV11VnHHsw-c5nyOXe3uWR9LIfeCWGIl8",{"id":35956,"title":35957,"body":35958,"description":35974,"extension":51,"meta":35975,"navigation":55,"path":35976,"seo":35977,"stem":35978,"__hash__":35979},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch30-git-history-and-merging\u002F30.1-coming-soon.md","Git — History & Merging — Coming Soon",{"type":8,"value":35959,"toc":35972},[35960,35963],[11,35961,35957],{"id":35962},"git-history-merging-coming-soon",[15,35964,35965,35938,35967,35942,35969,35971],{},[25,35966,35937],{},[95,35968,35941],{},[95,35970,35945],{}," as ch.30 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":35973},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.30 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch30-git-history-and-merging\u002F1-coming-soon",{"title":35957,"description":35974},"shockwave-curriculum\u002Flessons\u002Fch30-git-history-and-merging\u002F30.1-coming-soon","0W3bu2Me9piXXQ2MU9MnSwW7jUcHJmS0jfmkbNR8QyU",{"id":35981,"title":35982,"body":35983,"description":35999,"extension":51,"meta":36000,"navigation":55,"path":36001,"seo":36002,"stem":36003,"__hash__":36004},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch31-dev-environment-and-tooling\u002F31.1-coming-soon.md","Dev Environment & Tooling — Coming Soon",{"type":8,"value":35984,"toc":35997},[35985,35988],[11,35986,35982],{"id":35987},"dev-environment-tooling-coming-soon",[15,35989,35990,35938,35992,35942,35994,35996],{},[25,35991,35937],{},[95,35993,35941],{},[95,35995,35945],{}," as ch.31 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":35998},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.31 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch31-dev-environment-and-tooling\u002F1-coming-soon",{"title":35982,"description":35999},"shockwave-curriculum\u002Flessons\u002Fch31-dev-environment-and-tooling\u002F31.1-coming-soon","WpBIbU9fVXk_mwyqTHFIDlJTrEPBrqbqh9U7u2INiBU",{"id":36006,"title":36007,"body":36008,"description":36024,"extension":51,"meta":36025,"navigation":55,"path":36026,"seo":36027,"stem":36028,"__hash__":36029},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch32-unit-testing\u002F32.1-coming-soon.md","Unit Testing — Coming Soon",{"type":8,"value":36009,"toc":36022},[36010,36013],[11,36011,36007],{"id":36012},"unit-testing-coming-soon",[15,36014,36015,35938,36017,35942,36019,36021],{},[25,36016,35937],{},[95,36018,35941],{},[95,36020,35945],{}," as ch.32 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36023},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.32 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch32-unit-testing\u002F1-coming-soon",{"title":36007,"description":36024},"shockwave-curriculum\u002Flessons\u002Fch32-unit-testing\u002F32.1-coming-soon","krv1mHUxxP_GQszyFHcnsWKitL79FJTU_gmePxXrsIU",{"id":36031,"title":36032,"body":36033,"description":36049,"extension":51,"meta":36050,"navigation":55,"path":36051,"seo":36052,"stem":36053,"__hash__":36054},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch33-advantagekit-autologging\u002F33.1-coming-soon.md","AdvantageKit — AutoLogging — Coming Soon",{"type":8,"value":36034,"toc":36047},[36035,36038],[11,36036,36032],{"id":36037},"advantagekit-autologging-coming-soon",[15,36039,36040,35938,36042,35942,36044,36046],{},[25,36041,35937],{},[95,36043,35941],{},[95,36045,35945],{}," as ch.33 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36048},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.33 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch33-advantagekit-autologging\u002F1-coming-soon",{"title":36032,"description":36049},"shockwave-curriculum\u002Flessons\u002Fch33-advantagekit-autologging\u002F33.1-coming-soon","spoNagkq5hdYTZ0yQ-P3IuIGmL1Ktv_V9fRwYfujpLQ",{"id":36056,"title":36057,"body":36058,"description":36074,"extension":51,"meta":36075,"navigation":55,"path":36076,"seo":36077,"stem":36078,"__hash__":36079},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch34-log-replay\u002F34.1-coming-soon.md","Log Replay — Coming Soon",{"type":8,"value":36059,"toc":36072},[36060,36063],[11,36061,36057],{"id":36062},"log-replay-coming-soon",[15,36064,36065,35938,36067,35942,36069,36071],{},[25,36066,35937],{},[95,36068,35941],{},[95,36070,35945],{}," as ch.34 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36073},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.34 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch34-log-replay\u002F1-coming-soon",{"title":36057,"description":36074},"shockwave-curriculum\u002Flessons\u002Fch34-log-replay\u002F34.1-coming-soon","xgT1sABD2-1MJmFDGkbBid7vJuEqta641bi43kY5U_w",{"id":36081,"title":36082,"body":36083,"description":36099,"extension":51,"meta":36100,"navigation":55,"path":36101,"seo":36102,"stem":36103,"__hash__":36104},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch35-advantagescope-i-visualization\u002F35.1-coming-soon.md","AdvantageScope I: Visualization — Coming Soon",{"type":8,"value":36084,"toc":36097},[36085,36088],[11,36086,36082],{"id":36087},"advantagescope-i-visualization-coming-soon",[15,36089,36090,35938,36092,35942,36094,36096],{},[25,36091,35937],{},[95,36093,35941],{},[95,36095,35945],{}," as ch.35 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36098},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.35 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch35-advantagescope-i-visualization\u002F1-coming-soon",{"title":36082,"description":36099},"shockwave-curriculum\u002Flessons\u002Fch35-advantagescope-i-visualization\u002F35.1-coming-soon","BX1LcLs2zKIRFnQjOxLMIVCms_rgec36zjt98dUnh2Y",{"id":36106,"title":36107,"body":36108,"description":36124,"extension":51,"meta":36125,"navigation":55,"path":36126,"seo":36127,"stem":36128,"__hash__":36129},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch36-advantagescope-ii-custom-3d-assets\u002F36.1-coming-soon.md","AdvantageScope II: Custom 3D Assets — Coming Soon",{"type":8,"value":36109,"toc":36122},[36110,36113],[11,36111,36107],{"id":36112},"advantagescope-ii-custom-3d-assets-coming-soon",[15,36114,36115,35938,36117,35942,36119,36121],{},[25,36116,35937],{},[95,36118,35941],{},[95,36120,35945],{}," as ch.36 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36123},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.36 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch36-advantagescope-ii-custom-3d-assets\u002F1-coming-soon",{"title":36107,"description":36124},"shockwave-curriculum\u002Flessons\u002Fch36-advantagescope-ii-custom-3d-assets\u002F36.1-coming-soon","Qeov6DR_HjzJPA4kBoxrXU6AaNgTmZui6noDGVpG5ng",{"id":36131,"title":36132,"body":36133,"description":36149,"extension":51,"meta":36150,"navigation":55,"path":36151,"seo":36152,"stem":36153,"__hash__":36154},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch37-autonomous-i\u002F37.1-coming-soon.md","Autonomous I — Coming Soon",{"type":8,"value":36134,"toc":36147},[36135,36138],[11,36136,36132],{"id":36137},"autonomous-i-coming-soon",[15,36139,36140,35938,36142,35942,36144,36146],{},[25,36141,35937],{},[95,36143,35941],{},[95,36145,35945],{}," as ch.37 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36148},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.37 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch37-autonomous-i\u002F1-coming-soon",{"title":36132,"description":36149},"shockwave-curriculum\u002Flessons\u002Fch37-autonomous-i\u002F37.1-coming-soon","EPLFRNClsViJoQFtbe6f9McYqBM9sZEWNAG-TiJc5Og",{"id":36156,"title":36157,"body":36158,"description":36174,"extension":51,"meta":36175,"navigation":55,"path":36176,"seo":36177,"stem":36178,"__hash__":36179},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch38-autonomous-ii-pathplanner-and-trajectories\u002F38.1-coming-soon.md","Autonomous II: PathPlanner & Trajectories — Coming Soon",{"type":8,"value":36159,"toc":36172},[36160,36163],[11,36161,36157],{"id":36162},"autonomous-ii-pathplanner-trajectories-coming-soon",[15,36164,36165,35938,36167,35942,36169,36171],{},[25,36166,35937],{},[95,36168,35941],{},[95,36170,35945],{}," as ch.38 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36173},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.38 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch38-autonomous-ii-pathplanner-and-trajectories\u002F1-coming-soon",{"title":36157,"description":36174},"shockwave-curriculum\u002Flessons\u002Fch38-autonomous-ii-pathplanner-and-trajectories\u002F38.1-coming-soon","SQN8PGhvaHnKtm1dU5SF7zuqLONkbc61Lg_cdpoUDsM",{"id":36181,"title":36182,"body":36183,"description":36199,"extension":51,"meta":36200,"navigation":55,"path":36201,"seo":36202,"stem":36203,"__hash__":36204},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch39-control-fundamentals\u002F39.1-coming-soon.md","Control Fundamentals — Coming Soon",{"type":8,"value":36184,"toc":36197},[36185,36188],[11,36186,36182],{"id":36187},"control-fundamentals-coming-soon",[15,36189,36190,35938,36192,35942,36194,36196],{},[25,36191,35937],{},[95,36193,35941],{},[95,36195,35945],{}," as ch.39 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36198},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.39 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch39-control-fundamentals\u002F1-coming-soon",{"title":36182,"description":36199},"shockwave-curriculum\u002Flessons\u002Fch39-control-fundamentals\u002F39.1-coming-soon","TT7Zmbb1lJ45jAkP_FQdVt0qZkmxNTzWk0MnFuwTF50",{"id":36206,"title":36207,"body":36208,"description":36224,"extension":51,"meta":36225,"navigation":55,"path":36226,"seo":36227,"stem":36228,"__hash__":36229},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch40-motion-profiles\u002F40.1-coming-soon.md","Motion Profiles — Coming Soon",{"type":8,"value":36209,"toc":36222},[36210,36213],[11,36211,36207],{"id":36212},"motion-profiles-coming-soon",[15,36214,36215,35938,36217,35942,36219,36221],{},[25,36216,35937],{},[95,36218,35941],{},[95,36220,35945],{}," as ch.40 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36223},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.40 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch40-motion-profiles\u002F1-coming-soon",{"title":36207,"description":36224},"shockwave-curriculum\u002Flessons\u002Fch40-motion-profiles\u002F40.1-coming-soon","NhrGUcwG7OU105vTdRAV_KvPX3C2hbgVIjOJPe_myiQ",{"id":36231,"title":36232,"body":36233,"description":36249,"extension":51,"meta":36250,"navigation":55,"path":36251,"seo":36252,"stem":36253,"__hash__":36254},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch41-hardware-fundamentals\u002F41.1-coming-soon.md","Hardware Fundamentals — Coming Soon",{"type":8,"value":36234,"toc":36247},[36235,36238],[11,36236,36232],{"id":36237},"hardware-fundamentals-coming-soon",[15,36239,36240,35938,36242,35942,36244,36246],{},[25,36241,35937],{},[95,36243,35941],{},[95,36245,35945],{}," as ch.41 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36248},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.41 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch41-hardware-fundamentals\u002F1-coming-soon",{"title":36232,"description":36249},"shockwave-curriculum\u002Flessons\u002Fch41-hardware-fundamentals\u002F41.1-coming-soon","kttwOTGKjLgSRr9PcG9A2sPauf4-YKPxVkopx8hXFvE",{"id":36256,"title":36257,"body":36258,"description":36274,"extension":51,"meta":36275,"navigation":55,"path":36276,"seo":36277,"stem":36278,"__hash__":36279},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch42-photonvision\u002F42.1-coming-soon.md","PhotonVision — Coming Soon",{"type":8,"value":36259,"toc":36272},[36260,36263],[11,36261,36257],{"id":36262},"photonvision-coming-soon",[15,36264,36265,35938,36267,35942,36269,36271],{},[25,36266,35937],{},[95,36268,35941],{},[95,36270,35945],{}," as ch.42 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36273},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.42 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch42-photonvision\u002F1-coming-soon",{"title":36257,"description":36274},"shockwave-curriculum\u002Flessons\u002Fch42-photonvision\u002F42.1-coming-soon","1HBCN3KMJFWhYm4KGfFnGWOOxx42zFZ_mBkiJUVKgbg",{"id":36281,"title":36282,"body":36283,"description":36299,"extension":51,"meta":36300,"navigation":55,"path":36301,"seo":36302,"stem":36303,"__hash__":36304},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch43-apriltags-and-pose\u002F43.1-coming-soon.md","AprilTags & Pose — Coming Soon",{"type":8,"value":36284,"toc":36297},[36285,36288],[11,36286,36282],{"id":36287},"apriltags-pose-coming-soon",[15,36289,36290,35938,36292,35942,36294,36296],{},[25,36291,35937],{},[95,36293,35941],{},[95,36295,35945],{}," as ch.43 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36298},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.43 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch43-apriltags-and-pose\u002F1-coming-soon",{"title":36282,"description":36299},"shockwave-curriculum\u002Flessons\u002Fch43-apriltags-and-pose\u002F43.1-coming-soon","ldbsoniEmAn8CnpwGalpBmHuRMVbq_rPUazzWuK6nj8",{"id":36306,"title":36307,"body":36308,"description":36324,"extension":51,"meta":36325,"navigation":55,"path":36326,"seo":36327,"stem":36328,"__hash__":36329},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch44-subsystems-i\u002F44.1-coming-soon.md","Subsystems I — Coming Soon",{"type":8,"value":36309,"toc":36322},[36310,36313],[11,36311,36307],{"id":36312},"subsystems-i-coming-soon",[15,36314,36315,35938,36317,35942,36319,36321],{},[25,36316,35937],{},[95,36318,35941],{},[95,36320,35945],{}," as ch.44 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36323},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.44 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch44-subsystems-i\u002F1-coming-soon",{"title":36307,"description":36324},"shockwave-curriculum\u002Flessons\u002Fch44-subsystems-i\u002F44.1-coming-soon","xV8OV_rbBnVvGQxeuH8EuMtNJOdD3zLIOBkc8QhN5II",{"id":36331,"title":36332,"body":36333,"description":36349,"extension":51,"meta":36350,"navigation":55,"path":36351,"seo":36352,"stem":36353,"__hash__":36354},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch45-subsystems-ii-advanced\u002F45.1-coming-soon.md","Subsystems II — Advanced — Coming Soon",{"type":8,"value":36334,"toc":36347},[36335,36338],[11,36336,36332],{"id":36337},"subsystems-ii-advanced-coming-soon",[15,36339,36340,35938,36342,35942,36344,36346],{},[25,36341,35937],{},[95,36343,35941],{},[95,36345,35945],{}," as ch.45 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36348},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.45 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch45-subsystems-ii-advanced\u002F1-coming-soon",{"title":36332,"description":36349},"shockwave-curriculum\u002Flessons\u002Fch45-subsystems-ii-advanced\u002F45.1-coming-soon","-w_0_3ykKGX5OMf983zV9QL_1MsNiz781OtYHGJWnwI",{"id":36356,"title":36357,"body":36358,"description":36374,"extension":51,"meta":36375,"navigation":55,"path":36376,"seo":36377,"stem":36378,"__hash__":36379},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch46-team-utilities-i\u002F46.1-coming-soon.md","Team Utilities I — Coming Soon",{"type":8,"value":36359,"toc":36372},[36360,36363],[11,36361,36357],{"id":36362},"team-utilities-i-coming-soon",[15,36364,36365,35938,36367,35942,36369,36371],{},[25,36366,35937],{},[95,36368,35941],{},[95,36370,35945],{}," as ch.46 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36373},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.46 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch46-team-utilities-i\u002F1-coming-soon",{"title":36357,"description":36374},"shockwave-curriculum\u002Flessons\u002Fch46-team-utilities-i\u002F46.1-coming-soon","48jruSubU_qrwLRTP-ej8RLGcNj62e-QdXLDqShZDc4",{"id":36381,"title":36382,"body":36383,"description":36399,"extension":51,"meta":36400,"navigation":55,"path":36401,"seo":36402,"stem":36403,"__hash__":36404},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch47-field-constants\u002F47.1-coming-soon.md","Field Constants — Coming Soon",{"type":8,"value":36384,"toc":36397},[36385,36388],[11,36386,36382],{"id":36387},"field-constants-coming-soon",[15,36389,36390,35938,36392,35942,36394,36396],{},[25,36391,35937],{},[95,36393,35941],{},[95,36395,35945],{}," as ch.47 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36398},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.47 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch47-field-constants\u002F1-coming-soon",{"title":36382,"description":36399},"shockwave-curriculum\u002Flessons\u002Fch47-field-constants\u002F47.1-coming-soon","a8ktZc3WozG6_JwDyFEAI3z8rI2LeP0hXY9bN-aFEW0",{"id":36406,"title":36407,"body":36408,"description":36424,"extension":51,"meta":36425,"navigation":55,"path":36426,"seo":36427,"stem":36428,"__hash__":36429},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch48-troubleshooting-i-runtime-debug\u002F48.1-coming-soon.md","Troubleshooting I — Runtime Debug — Coming Soon",{"type":8,"value":36409,"toc":36422},[36410,36413],[11,36411,36407],{"id":36412},"troubleshooting-i-runtime-debug-coming-soon",[15,36414,36415,35938,36417,35942,36419,36421],{},[25,36416,35937],{},[95,36418,35941],{},[95,36420,35945],{}," as ch.48 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36423},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.48 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch48-troubleshooting-i-runtime-debug\u002F1-coming-soon",{"title":36407,"description":36424},"shockwave-curriculum\u002Flessons\u002Fch48-troubleshooting-i-runtime-debug\u002F48.1-coming-soon","_4XiuTZOChP577VuOuT8yceslKTaWGotQPfcpQYY5fc",{"id":36431,"title":36432,"body":36433,"description":36449,"extension":51,"meta":36450,"navigation":55,"path":36451,"seo":36452,"stem":36453,"__hash__":36454},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch49-troubleshooting-ii-can-and-sim\u002F49.1-coming-soon.md","Troubleshooting II: CAN & Sim — Coming Soon",{"type":8,"value":36434,"toc":36447},[36435,36438],[11,36436,36432],{"id":36437},"troubleshooting-ii-can-sim-coming-soon",[15,36439,36440,35938,36442,35942,36444,36446],{},[25,36441,35937],{},[95,36443,35941],{},[95,36445,35945],{}," as ch.49 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36448},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.49 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch49-troubleshooting-ii-can-and-sim\u002F1-coming-soon",{"title":36432,"description":36449},"shockwave-curriculum\u002Flessons\u002Fch49-troubleshooting-ii-can-and-sim\u002F49.1-coming-soon","unI0IwJa4Vq84ME-J6VWSbAc8O7TrAOrPJGidYgiHd4",{"id":36456,"title":36457,"body":36458,"description":36474,"extension":51,"meta":36475,"navigation":55,"path":36476,"seo":36477,"stem":36478,"__hash__":36479},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch50-vendor-libraries-talonfx\u002F50.1-coming-soon.md","Vendor Libraries: TalonFX — Coming Soon",{"type":8,"value":36459,"toc":36472},[36460,36463],[11,36461,36457],{"id":36462},"vendor-libraries-talonfx-coming-soon",[15,36464,36465,35938,36467,35942,36469,36471],{},[25,36466,35937],{},[95,36468,35941],{},[95,36470,35945],{}," as ch.50 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36473},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.50 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch50-vendor-libraries-talonfx\u002F1-coming-soon",{"title":36457,"description":36474},"shockwave-curriculum\u002Flessons\u002Fch50-vendor-libraries-talonfx\u002F50.1-coming-soon","1tShFd6NcBTkIuFtydPVN-2xPSvfWSIWtco0Jp-Ahhk",{"id":36481,"title":36482,"body":36483,"description":36499,"extension":51,"meta":36500,"navigation":55,"path":36501,"seo":36502,"stem":36503,"__hash__":36504},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch51-robot-alerts\u002F51.1-coming-soon.md","Robot Alerts — Coming Soon",{"type":8,"value":36484,"toc":36497},[36485,36488],[11,36486,36482],{"id":36487},"robot-alerts-coming-soon",[15,36489,36490,35938,36492,35942,36494,36496],{},[25,36491,35937],{},[95,36493,35941],{},[95,36495,35945],{}," as ch.51 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36498},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.51 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch51-robot-alerts\u002F1-coming-soon",{"title":36482,"description":36499},"shockwave-curriculum\u002Flessons\u002Fch51-robot-alerts\u002F51.1-coming-soon","Z2WiXQpicwCc4bm0SwPxrMeuroLNco-1UUFrEVoCSxU",{"id":36506,"title":36507,"body":36508,"description":36524,"extension":51,"meta":36525,"navigation":55,"path":36526,"seo":36527,"stem":36528,"__hash__":36529},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch52-wpilib-commands\u002F52.1-coming-soon.md","WPILib Commands — Coming Soon",{"type":8,"value":36509,"toc":36522},[36510,36513],[11,36511,36507],{"id":36512},"wpilib-commands-coming-soon",[15,36514,36515,35938,36517,35942,36519,36521],{},[25,36516,35937],{},[95,36518,35941],{},[95,36520,35945],{}," as ch.52 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36523},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.52 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch52-wpilib-commands\u002F1-coming-soon",{"title":36507,"description":36524},"shockwave-curriculum\u002Flessons\u002Fch52-wpilib-commands\u002F52.1-coming-soon","KFzP0K-rOiqivxBmQp6-frv-pEC0fYGs3cqbn7qEX1o",{"id":36531,"title":36532,"body":36533,"description":36549,"extension":51,"meta":36550,"navigation":55,"path":36551,"seo":36552,"stem":36553,"__hash__":36554},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch53-wpilib-geometry\u002F53.1-coming-soon.md","WPILib Geometry — Coming Soon",{"type":8,"value":36534,"toc":36547},[36535,36538],[11,36536,36532],{"id":36537},"wpilib-geometry-coming-soon",[15,36539,36540,35938,36542,35942,36544,36546],{},[25,36541,35937],{},[95,36543,35941],{},[95,36545,35945],{}," as ch.53 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36548},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.53 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch53-wpilib-geometry\u002F1-coming-soon",{"title":36532,"description":36549},"shockwave-curriculum\u002Flessons\u002Fch53-wpilib-geometry\u002F53.1-coming-soon","mF5JxRfkrR2HwXw4ER9LwnzYi6DwB7YriGn5zayFM5g",{"id":36556,"title":36557,"body":36558,"description":36574,"extension":51,"meta":36575,"navigation":55,"path":36576,"seo":36577,"stem":36578,"__hash__":36579},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch54-networktables\u002F54.1-coming-soon.md","NetworkTables — Coming Soon",{"type":8,"value":36559,"toc":36572},[36560,36563],[11,36561,36557],{"id":36562},"networktables-coming-soon",[15,36564,36565,35938,36567,35942,36569,36571],{},[25,36566,35937],{},[95,36568,35941],{},[95,36570,35945],{}," as ch.54 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36573},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.54 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch54-networktables\u002F1-coming-soon",{"title":36557,"description":36574},"shockwave-curriculum\u002Flessons\u002Fch54-networktables\u002F54.1-coming-soon","QgC6BvwxvNw3dDOIRnZ2nDWKB-ne6weBH25QAVqFPi4",{"id":36581,"title":36582,"body":36583,"description":36599,"extension":51,"meta":36600,"navigation":55,"path":36601,"seo":36602,"stem":36603,"__hash__":36604},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch55-command-scheduler\u002F55.1-coming-soon.md","Command Scheduler — Coming Soon",{"type":8,"value":36584,"toc":36597},[36585,36588],[11,36586,36582],{"id":36587},"command-scheduler-coming-soon",[15,36589,36590,35938,36592,35942,36594,36596],{},[25,36591,35937],{},[95,36593,35941],{},[95,36595,35945],{}," as ch.55 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36598},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.55 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch55-command-scheduler\u002F1-coming-soon",{"title":36582,"description":36599},"shockwave-curriculum\u002Flessons\u002Fch55-command-scheduler\u002F55.1-coming-soon","fkNl5L5cNx6U6RPevOT85fKF-bu6-3yyNYRDXCzaRCg",{"id":36606,"title":36607,"body":36608,"description":36624,"extension":51,"meta":36625,"navigation":55,"path":36626,"seo":36627,"stem":36628,"__hash__":36629},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch56-wpilib-timers\u002F56.1-coming-soon.md","WPILib Timers — Coming Soon",{"type":8,"value":36609,"toc":36622},[36610,36613],[11,36611,36607],{"id":36612},"wpilib-timers-coming-soon",[15,36614,36615,35938,36617,35942,36619,36621],{},[25,36616,35937],{},[95,36618,35941],{},[95,36620,35945],{}," as ch.56 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36623},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.56 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch56-wpilib-timers\u002F1-coming-soon",{"title":36607,"description":36624},"shockwave-curriculum\u002Flessons\u002Fch56-wpilib-timers\u002F56.1-coming-soon","j53gGS9XX5XYY1Jnx3xax3GsrbD8Td7yFVBDeWhWqII",{"id":36631,"title":36632,"body":36633,"description":36649,"extension":51,"meta":36650,"navigation":55,"path":36651,"seo":36652,"stem":36653,"__hash__":36654},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch57-wpilib-triggers\u002F57.1-coming-soon.md","WPILib Triggers — Coming Soon",{"type":8,"value":36634,"toc":36647},[36635,36638],[11,36636,36632],{"id":36637},"wpilib-triggers-coming-soon",[15,36639,36640,35938,36642,35942,36644,36646],{},[25,36641,35937],{},[95,36643,35941],{},[95,36645,35945],{}," as ch.57 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36648},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.57 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch57-wpilib-triggers\u002F1-coming-soon",{"title":36632,"description":36649},"shockwave-curriculum\u002Flessons\u002Fch57-wpilib-triggers\u002F57.1-coming-soon","tr1mylUItEAtKeIM3P-dciBfUXMgdpZercpu6GRZRn0",{"id":36656,"title":36657,"body":36658,"description":36674,"extension":51,"meta":36675,"navigation":55,"path":36676,"seo":36677,"stem":36678,"__hash__":36679},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch58-vendor-units-and-conversions\u002F58.1-coming-soon.md","Vendor Units & Conversions — Coming Soon",{"type":8,"value":36659,"toc":36672},[36660,36663],[11,36661,36657],{"id":36662},"vendor-units-conversions-coming-soon",[15,36664,36665,35938,36667,35942,36669,36671],{},[25,36666,35937],{},[95,36668,35941],{},[95,36670,35945],{}," as ch.58 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":36673},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.58 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch58-vendor-units-and-conversions\u002F1-coming-soon",{"title":36657,"description":36674},"shockwave-curriculum\u002Flessons\u002Fch58-vendor-units-and-conversions\u002F58.1-coming-soon","2OHHF-0EcaVd9T8-rM4dCXRNlRyQm25w59obJ9a2ggk",1792718177229]