[{"data":1,"prerenderedAt":284},["ShallowReactive",2],{"tag-labels":3,"site-header":4,"article-java-operators-en":72},{},{"featuredPost":5,"navigations":29},{"id":6,"title":7,"title_id":8,"slug":9,"excerpt":10,"excerpt_id":11,"has_translation":12,"published_at":13,"reading_time":14,"hidden_from_listing":15,"tags":16,"thumbnail_image":21,"og_image":22,"series":23,"authors":28},110,"When You Pick a Framework Just to Look Different","Ketika Pilih Framework Cuma Biar Kelihatan Beda","ketika-pilih-framework-cuma-biar-kelihatan-beda","The last time you chose a new framework or library, was it because your problem needed that tool, or because it sounded cool and few people around you were using it? That question is uncomfortable. Technology decisions are often made for reasons that never appear in any technical document.","Terakhir kali kamu milih framework atau library baru, itu karena masalahmu butuh alat itu, atau karena alatnya kedengaran keren dan belum banyak yang pakai? Pertanyaan ini nggak enak dijawab. Soalnya keputusan teknologi sering diambil dengan alasan yang nggak pernah ditulis di dokumen teknis mana pun.",true,"2026-10-06T15:25:21.000Z",5,false,[17,18,19,20],"karier","framework","opini","pengalaman",null,"\u002Fog\u002Fketika-pilih-framework-cuma-biar-kelihatan-beda.png",{"id":24,"title":25,"title_id":26,"slug":27},9,"Articles","Artikel","all",[],[30,46,67],{"collection":31,"item":32},"series",{"__typename":31,"title":25,"title_id":26,"slug":27,"children_series":33},[34,38,42],{"title":35,"title_id":36,"slug":37},"Artificial Intelligence","Kecerdasan Artifisial","kecerdasan-artifisial",{"title":39,"title_id":40,"slug":41},"Programming Fundamentals","Konsep Dasar Pemrograman","konsep-dasar-pemrograman",{"title":43,"title_id":44,"slug":45},"Algorithms and Data Structures","Algoritma dan Struktur Data","algoritma-struktur-data",{"collection":31,"item":47},{"__typename":31,"title":48,"title_id":48,"slug":49,"children_series":50},"Tutorial","tutorial",[51,55,59,63],{"title":52,"title_id":53,"slug":54},"Learning Python","Belajar Python","belajar-python",{"title":56,"title_id":57,"slug":58},"Learning Go","Belajar Golang","belajar-golang",{"title":60,"title_id":61,"slug":62},"Learning Java","Belajar Java","belajar-java",{"title":64,"title_id":65,"slug":66},"Learning Pascal","Belajar Pascal","belajar-pascal",{"collection":31,"item":68},{"__typename":31,"title":69,"title_id":69,"slug":70,"children_series":71},"Lab","lab",[],{"article":73,"renderedBody":171,"renderedTakeaway":172,"latestArticles":173,"toc":264},{"id":74,"title":75,"title_id":76,"slug":77,"excerpt":78,"excerpt_id":79,"has_translation":12,"published_at":80,"reading_time":14,"hidden_from_listing":15,"tags":81,"thumbnail_image":21,"og_image":84,"series":85,"authors":163,"seoTitle":21,"seoDescription":21,"body_locale":166,"available_locales":167,"body":169,"takeway":170,"prerequisite":21},137,"Java Operators: the Average That Came Out a Whole Number","Operator Java: Rata-Rata yang Keluar Sebagai Bilangan Bulat","java-operators","Three scores, one division, and the average prints as 82. Both operands are `int`, so the fraction is cut off, and the obvious cast prints `82.0` without fixing anything.","Tiga nilai, satu pembagian, dan rata-ratanya tercetak 82. Kedua operand-nya `int`, jadi pecahannya dipotong, dan cast yang paling wajar malah mencetak `82.0` tanpa memperbaiki apa pun.","2026-11-06T01:00:00.000Z",[82,83],"java","operator","\u002Fog\u002Fjava-operators.png",{"id":86,"title":87,"title_id":88,"slug":89,"description":90,"description_id":91,"articles":92,"children_series":152,"parent_series":153},22,"Variables, Types, and Operations","Variabel, Tipe Data, dan Operasi","java-variabel-tipe-data","In Java the type has to be clear from the start. We go through the primitive types, then integers and floats in more depth.","Tipe data di Java harus jelas dari awal. Kita bahas tipe data dasar, plus integer dan float lebih dalam.",[93,115,131,147],{"id":94,"title":95,"title_id":96,"slug":97,"excerpt":98,"excerpt_id":99,"has_translation":12,"published_at":100,"reading_time":101,"hidden_from_listing":15,"tags":102,"thumbnail_image":21,"og_image":106,"series":107,"authors":108},56,"Data Types in the Java Language","Tipe Data pada Bahasa Java","tipe-data-pada-bahasa-java","A data type is an attribute that sticks to a piece of data and decides how that data can be treated.","Tipe data adalah atribut yang menempel pada sebuah data untuk menentukan perlakuan terhadap data tersebut.","2022-12-29T00:00:00.000Z",3,[82,103,104,105],"tipe-data","konsep","dasar","\u002Fog\u002Ftipe-data-pada-bahasa-java.png",{"id":86,"title":87,"title_id":88,"slug":89},[109],{"authors_id":110},{"id":111,"name":112,"slug":113,"role":114,"profile_picture":21},1,"Daffa Izzuddin","izzudd","Writer",{"id":116,"title":117,"title_id":118,"slug":119,"excerpt":120,"excerpt_id":121,"has_translation":12,"published_at":122,"reading_time":123,"hidden_from_listing":15,"tags":124,"thumbnail_image":21,"og_image":126,"series":127,"authors":128},57,"Getting to Know the Integer Data Type in Java","Mengenal Tipe Data Integer pada Java","mengenal-tipe-data-integer-pada-java","Integer, as the name suggests, is a data type that only holds whole numbers (negative, zero, and positive).","Integer, sesuai namanya merupakan tipe data yang hanya bisa menampung bilangan bulat saja (negatif, nol, dan positif)","2023-01-13T00:00:00.000Z",6,[82,103,125],"integer","\u002Fog\u002Fmengenal-tipe-data-integer-pada-java.png",{"id":86,"title":87,"title_id":88,"slug":89},[129],{"authors_id":130},{"id":111,"name":112,"slug":113,"role":114,"profile_picture":21},{"id":132,"title":133,"title_id":134,"slug":135,"excerpt":136,"excerpt_id":137,"has_translation":12,"published_at":138,"reading_time":139,"hidden_from_listing":15,"tags":140,"thumbnail_image":21,"og_image":142,"series":143,"authors":144},58,"Getting to Know the Float Data Type in Java","Mengenal Tipe Data Float pada Java","mengenal-tipe-data-float-pada-java","Float, or floating point, is a data type that holds decimal and fractional number literals.","Float atau floating point merupakan tipe data yang dapat menampung literal bilangan desimal dan pecahan.","2023-02-15T00:00:00.000Z",4,[82,103,141],"float","\u002Fog\u002Fmengenal-tipe-data-float-pada-java.png",{"id":86,"title":87,"title_id":88,"slug":89},[145],{"authors_id":146},{"id":111,"name":112,"slug":113,"role":114,"profile_picture":21},{"id":74,"title":75,"title_id":76,"slug":77,"excerpt":78,"excerpt_id":79,"has_translation":12,"published_at":80,"reading_time":14,"hidden_from_listing":15,"tags":81,"thumbnail_image":21,"og_image":84,"series":148,"authors":149},{"id":86,"title":87,"title_id":88,"slug":89},[150],{"authors_id":151},{"id":111,"name":112,"slug":113,"role":114,"profile_picture":21},[],{"id":154,"title":60,"title_id":61,"slug":62,"parent_series":155,"children_series":156},13,{"id":111,"title":48,"title_id":48,"slug":49},[157,162],{"id":158,"title":159,"title_id":160,"slug":161,"cover_image":21},21,"Getting Started with Java","Berkenalan dengan Java","java-intro",{"id":86,"title":87,"title_id":88,"slug":89,"cover_image":21},[164],{"authors_id":165},{"id":111,"name":112,"slug":113,"role":114,"profile_picture":21},"en",[166,168],"id","\nYou add three test scores, divide by three, and print the result. The program prints `82`. The number that should have come out was 82.33. Nothing raised an error and nothing warned you. The compiler accepted every line, and 82 is a believable score, which is exactly why it went unnoticed.\n\nThis article uses one small file. You will compile it, run it, look at the wrong number, change one thing, and run it again.\n\n## The program that prints 82\n\nSave this as `Average.java`. It holds three scores, adds them in a loop, and divides the sum by the length of the array.\n\n```java\n\u002F\u002F Average.java\npublic class Average {\n    public static void main(String[] args) {\n        int[] scores = {80, 75, 92};\n        int sum = 0;\n        for (int score : scores) {\n            sum += score;\n        }\n        int average = sum \u002F scores.length;\n        System.out.println(\"sum: \" + sum);\n        System.out.println(\"average: \" + average);\n    }\n}\n```\n\nCompile it and run it with two commands:\n\n```console\njavac Average.java\njava Average\n```\n\nYou should see this:\n\n```\nsum: 247\naverage: 82\n```\n\nThe sum is right, because 80 + 75 + 92 is 247. The average is not, because 247 \u002F 3 is 82.33. The line `int average = sum \u002F scores.length;` reads like the textbook formula, so a reviewer sees a sum divided by a count and moves on. The output is a whole number in a plausible range. Nothing about `82` looks broken.\n\n## What `\u002F` does when both sides are int\n\nThe JVM decides the type of a division from its two operands. Here `sum` is an `int` and `scores.length` is an `int`, so `\u002F` performs integer division and the result is an `int`. An `int` has no room for a fraction, so the fraction is dropped.\n\nDropped is not the same as rounded. It is **cut off**. `247 \u002F 3` is `82`, and `5 \u002F 2` is `2`, where rounding would have given you 3. The program never sees the .33 at all.\n\nThe `%` operator hands you the part that was dropped. `247 % 3` is `1`: three goes into 247 eighty-two times, and one is left over. Put the pair together and nothing is lost, since 82 * 3 + 1 is 247.\n\n## Cast before the division, not after\n\nThe obvious repair is to ask for a `double`. Change the line to this:\n\n`double average = (double) (sum \u002F scores.length);`\n\nIt compiles without a warning and prints `82.0`. That looks like a double, and a double looks precise, but it is not the average. The parentheses make the division run first, in `int`, and the result is 82. The cast then widens 82 to 82.0. The damage was done before the cast got a turn.\n\nThe cast has to sit on an operand: `(double) sum \u002F scores.length`. A cast binds tighter than `\u002F`, so `sum` becomes a `double` first. With one `double` on the left, Java widens the other operand to match and divides in floating point. The result is `82.33333333333333`.\n\nHere is the fixed file. It changes the type of `average`, moves the cast onto `sum`, and adds one line that prints the remainder explained above.\n\n```java\n\u002F\u002F Average.java\npublic class Average {\n    public static void main(String[] args) {\n        int[] scores = {80, 75, 92};\n        int sum = 0;\n        for (int score : scores) {\n            sum += score;\n        }\n        double average = (double) sum \u002F scores.length;\n        System.out.println(\"sum: \" + sum);\n        System.out.println(\"average: \" + average);\n        System.out.println(\"remainder: \" + sum % scores.length);\n    }\n}\n```\n\nRun the same two commands:\n\n```\nsum: 247\naverage: 82.33333333333333\nremainder: 1\n```\n\n## Precedence and the rest of the operators\n\nMultiplication, division and remainder bind tighter than addition and subtraction. So `1 + 2 * 3` is `7`, while `(1 + 2) * 3` is `9`. Parentheses change which operation runs first. The cast bug is the same kind of mistake: the order Java evaluates things in decides the answer.\n\nInteger division shows up outside averages too. `10 \u002F 3` is `3`. Make one operand a `double` and `10.0 \u002F 3` is `3.3333333333333335`. One `.0` on one side turns a whole number into a long fraction.\n\nLook at both long results again. `82.33333333333333` and `3.3333333333333335` do not end the way you would write them on paper. That leads to the one thing this article does not settle.\n\n## What this does not cover\n\nA `double` cannot hold every decimal exactly. It stores binary fractions, and a value like 0.1 has no exact binary form. Add two of them and you can see the gap: `0.1 + 0.2` is `0.30000000000000004`.\n\nFor money, that gap matters, and Java has `BigDecimal` for it. We will not use it here. An average of scores is not money. The error sits far past any digit a reader of a score would care about, so `double` is the right tool for this program.\n\n## Before the next article\n\nChange one score so the three add up to 246: use 80, 75 and 91. Run the starter version, then the fixed version. This is what I measured. The truncating version prints `82`, and the cast version prints `82.0`. They agree, and neither answer looks wrong, because 246 divides by 3 exactly.\n\nA data set that divides evenly hides the bug. Your task is to explain, in your own words, why the bug comes back the moment the sum is not divisible by the count.\n\nIf a result looks right on one input, which input would make it wrong?\n","- `int \u002F int` is integer division: the fraction is cut off, not rounded, so `247 \u002F 3` is `82`.\n- `%` returns what the division dropped: `247 % 3` is `1`.\n- Casting the result (`(double) (sum \u002F count)`) prints `82.0`, because the division already happened in `int`.\n- Cast one operand (`(double) sum \u002F count`) to divide in floating point and get `82.33333333333333`.\n- A `double` cannot hold every decimal, since `0.1 + 0.2` is `0.30000000000000004`, which is why money uses `BigDecimal`.\n- A test input that divides evenly, like 246 by 3, hides the bug in both versions.","\u003Cp>You add three test scores, divide by three, and print the result. The program prints \u003Ccode>82\u003C\u002Fcode>. The number that should have come out was 82.33. Nothing raised an error and nothing warned you. The compiler accepted every line, and 82 is a believable score, which is exactly why it went unnoticed.\u003C\u002Fp>\n\u003Cp>This article uses one small file. You will compile it, run it, look at the wrong number, change one thing, and run it again.\u003C\u002Fp>\n\u003Ch2 id=\"the-program-that-prints-82\">The program that prints 82\u003C\u002Fh2>\n\u003Cp>Save this as \u003Ccode>Average.java\u003C\u002Fcode>. It holds three scores, adds them in a loop, and divides the sum by the length of the array.\u003C\u002Fp>\n\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">JAVA\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"%2F%2F%20Average.java%0Apublic%20class%20Average%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20int%5B%5D%20scores%20%3D%20%7B80%2C%2075%2C%2092%7D%3B%0A%20%20%20%20%20%20%20%20int%20sum%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for%20(int%20score%20%3A%20scores)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20sum%20%2B%3D%20score%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20int%20average%20%3D%20sum%20%2F%20scores.length%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22sum%3A%20%22%20%2B%20sum)%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22average%3A%20%22%20%2B%20average)%3B%0A%20%20%20%20%7D%0A%7D\" title=\"Salin kode\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Copy\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\">\u003Ccode>\u002F\u002F Average.java\npublic class Average {\n    public static void main(String[] args) {\n        int[] scores = {80, 75, 92};\n        int sum = 0;\n        for (int score : scores) {\n            sum += score;\n        }\n        int average = sum \u002F scores.length;\n        System.out.println(\"sum: \" + sum);\n        System.out.println(\"average: \" + average);\n    }\n}\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>Compile it and run it with two commands:\u003C\u002Fp>\n\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">CONSOLE\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"javac%20Average.java%0Ajava%20Average\" title=\"Salin kode\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Copy\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\">\u003Ccode>javac Average.java\njava Average\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>You should see this:\u003C\u002Fp>\n\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">TEXT\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"sum%3A%20247%0Aaverage%3A%2082\" title=\"Salin kode\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Copy\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\">\u003Ccode>sum: 247\naverage: 82\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>The sum is right, because 80 + 75 + 92 is 247. The average is not, because 247 \u002F 3 is 82.33. The line \u003Ccode>int average = sum \u002F scores.length;\u003C\u002Fcode> reads like the textbook formula, so a reviewer sees a sum divided by a count and moves on. The output is a whole number in a plausible range. Nothing about \u003Ccode>82\u003C\u002Fcode> looks broken.\u003C\u002Fp>\n\u003Ch2 id=\"what-does-when-both-sides-are-int\">What \u003Ccode>\u002F\u003C\u002Fcode> does when both sides are int\u003C\u002Fh2>\n\u003Cp>The JVM decides the type of a division from its two operands. Here \u003Ccode>sum\u003C\u002Fcode> is an \u003Ccode>int\u003C\u002Fcode> and \u003Ccode>scores.length\u003C\u002Fcode> is an \u003Ccode>int\u003C\u002Fcode>, so \u003Ccode>\u002F\u003C\u002Fcode> performs integer division and the result is an \u003Ccode>int\u003C\u002Fcode>. An \u003Ccode>int\u003C\u002Fcode> has no room for a fraction, so the fraction is dropped.\u003C\u002Fp>\n\u003Cp>Dropped is not the same as rounded. It is \u003Cstrong>cut off\u003C\u002Fstrong>. \u003Ccode>247 \u002F 3\u003C\u002Fcode> is \u003Ccode>82\u003C\u002Fcode>, and \u003Ccode>5 \u002F 2\u003C\u002Fcode> is \u003Ccode>2\u003C\u002Fcode>, where rounding would have given you 3. The program never sees the .33 at all.\u003C\u002Fp>\n\u003Cp>The \u003Ccode>%\u003C\u002Fcode> operator hands you the part that was dropped. \u003Ccode>247 % 3\u003C\u002Fcode> is \u003Ccode>1\u003C\u002Fcode>: three goes into 247 eighty-two times, and one is left over. Put the pair together and nothing is lost, since 82 * 3 + 1 is 247.\u003C\u002Fp>\n\u003Ch2 id=\"cast-before-the-division-not-after\">Cast before the division, not after\u003C\u002Fh2>\n\u003Cp>The obvious repair is to ask for a \u003Ccode>double\u003C\u002Fcode>. Change the line to this:\u003C\u002Fp>\n\u003Cp>\u003Ccode>double average = (double) (sum \u002F scores.length);\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cp>It compiles without a warning and prints \u003Ccode>82.0\u003C\u002Fcode>. That looks like a double, and a double looks precise, but it is not the average. The parentheses make the division run first, in \u003Ccode>int\u003C\u002Fcode>, and the result is 82. The cast then widens 82 to 82.0. The damage was done before the cast got a turn.\u003C\u002Fp>\n\u003Cp>The cast has to sit on an operand: \u003Ccode>(double) sum \u002F scores.length\u003C\u002Fcode>. A cast binds tighter than \u003Ccode>\u002F\u003C\u002Fcode>, so \u003Ccode>sum\u003C\u002Fcode> becomes a \u003Ccode>double\u003C\u002Fcode> first. With one \u003Ccode>double\u003C\u002Fcode> on the left, Java widens the other operand to match and divides in floating point. The result is \u003Ccode>82.33333333333333\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Here is the fixed file. It changes the type of \u003Ccode>average\u003C\u002Fcode>, moves the cast onto \u003Ccode>sum\u003C\u002Fcode>, and adds one line that prints the remainder explained above.\u003C\u002Fp>\n\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">JAVA\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"%2F%2F%20Average.java%0Apublic%20class%20Average%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20int%5B%5D%20scores%20%3D%20%7B80%2C%2075%2C%2092%7D%3B%0A%20%20%20%20%20%20%20%20int%20sum%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for%20(int%20score%20%3A%20scores)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20sum%20%2B%3D%20score%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20double%20average%20%3D%20(double)%20sum%20%2F%20scores.length%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22sum%3A%20%22%20%2B%20sum)%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22average%3A%20%22%20%2B%20average)%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22remainder%3A%20%22%20%2B%20sum%20%25%20scores.length)%3B%0A%20%20%20%20%7D%0A%7D\" title=\"Salin kode\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Copy\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\">\u003Ccode>\u002F\u002F Average.java\npublic class Average {\n    public static void main(String[] args) {\n        int[] scores = {80, 75, 92};\n        int sum = 0;\n        for (int score : scores) {\n            sum += score;\n        }\n        double average = (double) sum \u002F scores.length;\n        System.out.println(\"sum: \" + sum);\n        System.out.println(\"average: \" + average);\n        System.out.println(\"remainder: \" + sum % scores.length);\n    }\n}\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>Run the same two commands:\u003C\u002Fp>\n\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">TEXT\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"sum%3A%20247%0Aaverage%3A%2082.33333333333333%0Aremainder%3A%201\" title=\"Salin kode\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Copy\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\">\u003Ccode>sum: 247\naverage: 82.33333333333333\nremainder: 1\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Ch2 id=\"precedence-and-the-rest-of-the-operators\">Precedence and the rest of the operators\u003C\u002Fh2>\n\u003Cp>Multiplication, division and remainder bind tighter than addition and subtraction. So \u003Ccode>1 + 2 * 3\u003C\u002Fcode> is \u003Ccode>7\u003C\u002Fcode>, while \u003Ccode>(1 + 2) * 3\u003C\u002Fcode> is \u003Ccode>9\u003C\u002Fcode>. Parentheses change which operation runs first. The cast bug is the same kind of mistake: the order Java evaluates things in decides the answer.\u003C\u002Fp>\n\u003Cp>Integer division shows up outside averages too. \u003Ccode>10 \u002F 3\u003C\u002Fcode> is \u003Ccode>3\u003C\u002Fcode>. Make one operand a \u003Ccode>double\u003C\u002Fcode> and \u003Ccode>10.0 \u002F 3\u003C\u002Fcode> is \u003Ccode>3.3333333333333335\u003C\u002Fcode>. One \u003Ccode>.0\u003C\u002Fcode> on one side turns a whole number into a long fraction.\u003C\u002Fp>\n\u003Cp>Look at both long results again. \u003Ccode>82.33333333333333\u003C\u002Fcode> and \u003Ccode>3.3333333333333335\u003C\u002Fcode> do not end the way you would write them on paper. That leads to the one thing this article does not settle.\u003C\u002Fp>\n\u003Ch2 id=\"what-this-does-not-cover\">What this does not cover\u003C\u002Fh2>\n\u003Cp>A \u003Ccode>double\u003C\u002Fcode> cannot hold every decimal exactly. It stores binary fractions, and a value like 0.1 has no exact binary form. Add two of them and you can see the gap: \u003Ccode>0.1 + 0.2\u003C\u002Fcode> is \u003Ccode>0.30000000000000004\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>For money, that gap matters, and Java has \u003Ccode>BigDecimal\u003C\u002Fcode> for it. We will not use it here. An average of scores is not money. The error sits far past any digit a reader of a score would care about, so \u003Ccode>double\u003C\u002Fcode> is the right tool for this program.\u003C\u002Fp>\n\u003Ch2 id=\"before-the-next-article\">Before the next article\u003C\u002Fh2>\n\u003Cp>Change one score so the three add up to 246: use 80, 75 and 91. Run the starter version, then the fixed version. This is what I measured. The truncating version prints \u003Ccode>82\u003C\u002Fcode>, and the cast version prints \u003Ccode>82.0\u003C\u002Fcode>. They agree, and neither answer looks wrong, because 246 divides by 3 exactly.\u003C\u002Fp>\n\u003Cp>A data set that divides evenly hides the bug. Your task is to explain, in your own words, why the bug comes back the moment the sum is not divisible by the count.\u003C\u002Fp>\n\u003Cp>If a result looks right on one input, which input would make it wrong?\u003C\u002Fp>\n","\u003Cul>\n\u003Cli>\u003Ccode>int \u002F int\u003C\u002Fcode> is integer division: the fraction is cut off, not rounded, so \u003Ccode>247 \u002F 3\u003C\u002Fcode> is \u003Ccode>82\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>\u003Ccode>%\u003C\u002Fcode> returns what the division dropped: \u003Ccode>247 % 3\u003C\u002Fcode> is \u003Ccode>1\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>Casting the result (\u003Ccode>(double) (sum \u002F count)\u003C\u002Fcode>) prints \u003Ccode>82.0\u003C\u002Fcode>, because the division already happened in \u003Ccode>int\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>Cast one operand (\u003Ccode>(double) sum \u002F count\u003C\u002Fcode>) to divide in floating point and get \u003Ccode>82.33333333333333\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>A \u003Ccode>double\u003C\u002Fcode> cannot hold every decimal, since \u003Ccode>0.1 + 0.2\u003C\u002Fcode> is \u003Ccode>0.30000000000000004\u003C\u002Fcode>, which is why money uses \u003Ccode>BigDecimal\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>A test input that divides evenly, like 246 by 3, hides the bug in both versions.\u003C\u002Fli>\n\u003C\u002Ful>\n",[174,179,199,216,230,249],{"id":74,"title":75,"title_id":76,"slug":77,"excerpt":78,"excerpt_id":79,"has_translation":12,"published_at":80,"reading_time":14,"hidden_from_listing":15,"tags":81,"thumbnail_image":21,"og_image":84,"series":175,"authors":176},{"id":86,"title":87,"title_id":88,"slug":89},[177],{"authors_id":178},{"id":111,"name":112,"slug":113,"role":114,"profile_picture":21},{"id":180,"title":181,"title_id":182,"slug":183,"excerpt":184,"excerpt_id":185,"has_translation":12,"published_at":80,"reading_time":186,"hidden_from_listing":15,"tags":187,"thumbnail_image":21,"og_image":190,"series":191,"authors":196},136,"Python Modules: the Import That Printed the Report","Modul Python: Import yang Mencetak Laporannya","python-modules","You pull one function out into its own file, import it, and the whole report runs again and eats your input. A module is a file, `import` runs it top to bottom, and one line decides which of the two jobs it is doing.","Kamu memindahkan satu fungsi ke file sendiri, meng-import-nya, dan seluruh laporan jalan lagi lalu memakan inputmu. Modul adalah file, `import` menjalankannya dari atas ke bawah, dan satu baris menentukan pekerjaan mana yang sedang dijalankan file itu.",7,[188,189],"python","modules","\u002Fog\u002Fpython-modules.png",{"id":192,"title":193,"title_id":194,"slug":195},18,"Working with Python Scripts","Menggunakan Script Python","python-pemrograman-dengan-script",[197],{"authors_id":198},{"id":111,"name":112,"slug":113,"role":114,"profile_picture":21},{"id":200,"title":201,"title_id":21,"slug":202,"excerpt":203,"excerpt_id":21,"has_translation":15,"published_at":204,"reading_time":139,"hidden_from_listing":15,"tags":205,"thumbnail_image":21,"og_image":210,"series":211,"authors":213},135,"Caching That Never Hits Costs More Than No Caching","caching-that-never-hits","Same model, same conversation, same token count, and a bill five times higher. The cause is a prefix that changes, a write premium nobody reads about, and a cost curve that grows faster than the loop.","2026-11-04T01:10:00.000Z",[206,207,208,209],"llm","ai-agent","cache","api","\u002Fog\u002Fcaching-that-never-hits.png",{"id":212,"title":35,"title_id":36,"slug":37},8,[214],{"authors_id":215},{"id":111,"name":112,"slug":113,"role":114,"profile_picture":21},{"id":217,"title":218,"title_id":21,"slug":219,"excerpt":220,"excerpt_id":21,"has_translation":15,"published_at":221,"reading_time":14,"hidden_from_listing":15,"tags":222,"thumbnail_image":21,"og_image":225,"series":226,"authors":227},134,"Your Stream Dies at 125 Seconds and Nothing in Your Code Says 125","your-stream-dies-at-125-seconds","Streaming moves the wait into a connection that outlives the request. Four layers sit between the model and the browser, their idle timeouts disagree, and the smallest one ends your stream.","2026-11-04T01:00:00.000Z",[223,224,207,209],"streaming","sse","\u002Fog\u002Fyour-stream-dies-at-125-seconds.png",{"id":212,"title":35,"title_id":36,"slug":37},[228],{"authors_id":229},{"id":111,"name":112,"slug":113,"role":114,"profile_picture":21},{"id":231,"title":232,"title_id":233,"slug":234,"excerpt":235,"excerpt_id":236,"has_translation":12,"published_at":237,"reading_time":123,"hidden_from_listing":15,"tags":238,"thumbnail_image":21,"og_image":240,"series":241,"authors":246},133,"Python Strings: the Badge That Only Worked for One Name","String Python: Badge yang Cuma Jalan untuk Satu Nama","python-strings","The badge script printed the right name for the person who wrote it and the wrong name for everybody else. Slicing counts characters, and a name is words.","Skrip badge mencetak nama yang benar untuk orang yang menulisnya dan nama yang salah untuk semua orang lain. Slicing menghitung karakter, sedangkan nama itu kata.","2026-10-28T13:00:00.000Z",[188,239],"string","\u002Fog\u002Fpython-strings.png",{"id":242,"title":243,"title_id":244,"slug":245},30,"Collections and Strings","Koleksi dan String","python-collections",[247],{"authors_id":248},{"id":111,"name":112,"slug":113,"role":114,"profile_picture":21},{"id":250,"title":251,"title_id":252,"slug":253,"excerpt":254,"excerpt_id":255,"has_translation":12,"published_at":256,"reading_time":123,"hidden_from_listing":15,"tags":257,"thumbnail_image":21,"og_image":259,"series":260,"authors":261},132,"Python Tuples: Why All Three Points Are the Same Point","Tuple Python: Kenapa Ketiga Titik Itu Titik yang Sama","python-tuples","Three points walk into a loop and come out identical. The list was never copied three times; the name was. A tuple makes that bug impossible.","Tiga titik masuk ke satu loop dan keluar identik. List-nya nggak pernah disalin tiga kali; yang disalin cuma namanya. Tuple membuat bug ini mustahil terjadi.","2026-10-28T12:00:00.000Z",[188,258],"tuple","\u002Fog\u002Fpython-tuples.png",{"id":242,"title":243,"title_id":244,"slug":245},[262],{"authors_id":263},{"id":111,"name":112,"slug":113,"role":114,"profile_picture":21},[265,269,272,275,278,281],{"text":266,"depth":267,"id":268},"The program that prints 82",2,"the-program-that-prints-82",{"text":270,"depth":267,"id":271},"What \u002F does when both sides are int","what-does-when-both-sides-are-int",{"text":273,"depth":267,"id":274},"Cast before the division, not after","cast-before-the-division-not-after",{"text":276,"depth":267,"id":277},"Precedence and the rest of the operators","precedence-and-the-rest-of-the-operators",{"text":279,"depth":267,"id":280},"What this does not cover","what-this-does-not-cover",{"text":282,"depth":267,"id":283},"Before the next article","before-the-next-article",1793986940597]