<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged stream</title>
<link>https://coderlegion.com/tag/stream</link>
<description>Powered by Question2Answer</description>
<item>
<title>The Mechanics of Compression: How 100GB Becomes 25GB</title>
<link>https://coderlegion.com/14657/the-mechanics-of-compression-how-100gb-becomes-25gb</link>
<description>
&lt;p&gt;&lt;img src=&quot;https://blog.ratnesh-maurya.com/images/blog/The-Mechanics-of-Compression-How-100GB-Becomes-25GB.png&quot; alt=&quot;The Mechanics of Compression: How 100GB Becomes 25GB&quot;&gt;&lt;/p&gt;&lt;h2 id=&quot;the-mechanics-of-compression-how-100gb-becomes-25gb&quot;&gt;The Mechanics of Compression: How 100GB Becomes 25GB&lt;/h2&gt;
&lt;p&gt;In an era of 4K streaming and massive cloud databases, we often take for granted that a 100GB backup can be shrunk down to 25GB. It isn&amp;rsquo;t magic&amp;mdash;and it isn&amp;rsquo;t just &amp;ldquo;squeezing&amp;rdquo; bits. It&amp;rsquo;s a careful process of spotting patterns, removing redundancy, and using mathematical shorthand so that the same information takes less space. This post explains how that works in plain terms, so you can understand what happens under the hood when you zip a folder or stream a video.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;1-the-core-idea-redundancy-is-waste&quot;&gt;1. The Core Idea: Redundancy Is Waste&lt;/h2&gt;
&lt;p&gt;At its heart, compression is about &lt;strong&gt;efficiency&lt;/strong&gt;. Most data is repetitive. The same words, phrases, or pixel patterns show up again and again. If the computer has already seen a pattern once, it doesn&amp;rsquo;t need to store it again in full&amp;mdash;it can refer back to it or describe it in fewer bits.&lt;/p&gt;
&lt;p&gt;Think of a recipe that says &amp;ldquo;add salt&amp;rdquo; five times. You could write &amp;ldquo;add salt&amp;rdquo; five times, or you could write &amp;ldquo;add salt (&amp;times;5).&amp;rdquo; The second version carries the same information in less space. Compression algorithms do something similar: they find repetition and describe it more compactly.&lt;/p&gt;
&lt;p&gt;So the main job of any compression scheme is to &lt;strong&gt;find redundancy&lt;/strong&gt; and &lt;strong&gt;encode it in fewer bits&lt;/strong&gt; without losing the ability to recover the original data when needed.&lt;/p&gt;
&lt;h3 id=&quot;a-real-life-example-compressing-a-book-with-repeated-words&quot;&gt;A Real-Life Example: Compressing a Book with Repeated Words&lt;/h3&gt;
&lt;p&gt;Imagine a &lt;strong&gt;book&lt;/strong&gt; where the same words appear again and again. Words like &quot;the,&quot; &quot;and,&quot; and &quot;to&quot; might show up thousands of times. Instead of writing the full word every time, we could agree on a &lt;strong&gt;legend&lt;/strong&gt; at the start and replace each repeated word with a short &lt;strong&gt;sub-symbol&lt;/strong&gt;. Anyone with the legend can reconstruct the original text exactly.&lt;/p&gt;
&lt;p&gt;Suppose we define a small dictionary at the top of the page:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot;&gt;Legend:  @ = the   |   # = and   |   % = to   |   &amp;sect; = of
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now take a normal sentence and &quot;compress&quot; it by substituting:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Original (longer):&lt;/strong&gt;
&quot;The king and the queen went to the castle and stayed there for the rest of the day.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compressed (shorter):&lt;/strong&gt;
&quot;@ king # @ queen went % @ castle # stayed there for @ rest &amp;sect; @ day.&quot;&lt;/p&gt;
&lt;p&gt;We still have the same meaning, but we used one character (@, #, %, &amp;sect;) wherever a repeated word appeared. The &lt;strong&gt;legend&lt;/strong&gt; is the &quot;dictionary&quot;&amp;mdash;it has to be stored or sent once so the reader can decode. For a whole book, if &quot;the&quot; appears 2,000 times, we save (3 &amp;minus; 1) &amp;times; 2,000 = 4,000 characters just on that one word. Add &quot;and,&quot; &quot;to,&quot; &quot;of,&quot; and other frequent words, and the book shrinks noticeably without losing a single word.&lt;/p&gt;
&lt;p&gt;This is exactly the idea behind &lt;strong&gt;dictionary coding&lt;/strong&gt; and &lt;strong&gt;Huffman-style&lt;/strong&gt; compression: find what repeats, assign it a short code, and use that code everywhere. Real compressors do this automatically; they don't need a human to write the legend.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A real experiment from the wild:&lt;/strong&gt; Researchers applied this idea to the full text of &lt;strong&gt;&quot;Alice's Adventures in Wonderland&quot;&lt;/strong&gt; by Lewis Carroll. They treated each &lt;em&gt;word&lt;/em&gt; as a symbol, counted how often it appeared, and assigned &lt;strong&gt;shorter codes to the most frequent words&lt;/strong&gt; (like &quot;the,&quot; &quot;and,&quot; &quot;to,&quot; &quot;a&quot;) and &lt;strong&gt;longer codes to rare words&lt;/strong&gt; (like &quot;wretched,&quot; &quot;yawned&quot;). The result: the text went from &lt;strong&gt;164 KB down to 109 KB&lt;/strong&gt;&amp;mdash;about &lt;strong&gt;one-third smaller&lt;/strong&gt;&amp;mdash;with no information lost (&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.nayuki.io/page/huffman-coding-english-words&quot;&gt;&lt;em&gt;Huffman-coding English words&lt;/em&gt;&lt;/a&gt;, Project Nayuki&amp;mdash;includes original text from Project Gutenberg, input/output file sizes, and codebook samples). The same technique&amp;mdash;replace repeated words with shorter symbols, and keep a mapping so we can decode&amp;mdash;is what powers the compression we use every day in ZIP files and beyond.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;2-lossless-vs-lossy-two-different-goals&quot;&gt;2. Lossless vs. Lossy: Two Different Goals&lt;/h2&gt;
&lt;p&gt;Before diving into algorithms, it helps to know that compression splits into two families: &lt;strong&gt;lossless&lt;/strong&gt; and &lt;strong&gt;lossy&lt;/strong&gt;. The choice depends on whether you can afford to lose any information.&lt;/p&gt;
&lt;h3 id=&quot;lossless-compression-every-bit-preserved&quot;&gt;Lossless Compression: Every Bit Preserved&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Lossless&lt;/strong&gt; compression means that after you decompress, you get back &lt;strong&gt;exactly&lt;/strong&gt; the original data&amp;mdash;every bit. Nothing is discarded.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;How it works:&lt;/strong&gt; The algorithm finds statistical redundancy (repeated or predictable patterns) and encodes them more efficiently. Decompression reverses the process and reconstructs the original stream.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; Whenever you cannot afford to lose information&amp;mdash;source code, text files, databases, executables, legal documents, medical data, or images where every pixel must stay exact (e.g. PNG for graphics, FLAC for audio).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Common formats:&lt;/strong&gt; ZIP, GZIP, PNG, GIF (for lossless use), FLAC.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So when you compress 100GB of source code or logs to 25GB with a lossless tool, you can later decompress and get back the same 100GB bit-for-bit.&lt;/p&gt;
&lt;h3 id=&quot;lossy-compression-smaller-files-imperceptible-loss&quot;&gt;Lossy Compression: Smaller Files, Imperceptible Loss&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Lossy&lt;/strong&gt; compression &lt;strong&gt;discards&lt;/strong&gt; some information on purpose. What you get back is an &lt;strong&gt;approximation&lt;/strong&gt; of the original&amp;mdash;close enough for human perception, but not identical.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;How it works:&lt;/strong&gt; The algorithm keeps what matters for the intended use (e.g. what the eye or ear notices) and drops &amp;ldquo;invisible&amp;rdquo; or less important detail&amp;mdash;e.g. colors we can&amp;rsquo;t easily tell apart, or sounds masked by louder ones.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; Media where small quality loss is acceptable&amp;mdash;photos (JPEG), music (MP3, AAC), video (H.264, VP9). Streaming and storage would be far heavier without lossy compression.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Common formats:&lt;/strong&gt; JPEG, MP3, AAC, H.264, VP9.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the rest of this post we focus on &lt;strong&gt;lossless&lt;/strong&gt; compression&amp;mdash;the kind that powers ZIP, GZIP, and the 100GB&amp;rarr;25GB backup scenario&amp;mdash;and then briefly touch how &lt;strong&gt;video&lt;/strong&gt; combines similar ideas with lossy temporal compression.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;3-the-building-blocks-huffman-coding-and-lz77&quot;&gt;3. The Building Blocks: Huffman Coding and LZ77&lt;/h2&gt;
&lt;p&gt;Most modern lossless compressors (including the ones inside ZIP and GZIP) combine two ideas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Dictionary / back-reference coding&lt;/strong&gt; (e.g. LZ77): &amp;ldquo;I&amp;rsquo;ve seen this phrase before; refer back to it.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entropy coding&lt;/strong&gt; (e.g. Huffman): &amp;ldquo;Frequent symbols get short codes; rare symbols get longer codes.&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Together they form algorithms like &lt;strong&gt;DEFLATE&lt;/strong&gt; (used in ZIP and GZIP): first reduce repetition with something like LZ77, then shorten the remaining stream with Huffman (or similar) coding.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;31-huffman-coding-short-codes-for-common-symbols&quot;&gt;3.1 Huffman Coding: Short Codes for Common Symbols&lt;/h3&gt;
&lt;p&gt;In normal text encoding (e.g. ASCII or UTF-8), every character uses the &lt;strong&gt;same&lt;/strong&gt; number of bits (e.g. 8 bits per character). So the letter &amp;ldquo;E&amp;rdquo; and the letter &amp;ldquo;Z&amp;rdquo; both cost 8 bits, even though &amp;ldquo;E&amp;rdquo; appears far more often in English text. That&amp;rsquo;s wasteful: we&amp;rsquo;re spending the same budget on rare and common symbols.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Huffman coding&lt;/strong&gt; fixes that by giving &lt;strong&gt;variable-length&lt;/strong&gt; codes: frequent symbols get &lt;strong&gt;shorter&lt;/strong&gt; codes, rare symbols get &lt;strong&gt;longer&lt;/strong&gt; codes. On average, the whole message uses fewer bits.&lt;/p&gt;
&lt;p&gt;One crucial constraint: no code is allowed to be a &lt;strong&gt;prefix&lt;/strong&gt; of another. So if &amp;ldquo;E&amp;rdquo; is encoded as &lt;code&gt;10&lt;/code&gt;, then no other character&amp;rsquo;s code can start with &lt;code&gt;10&lt;/code&gt; (e.g. no &lt;code&gt;100&lt;/code&gt; or &lt;code&gt;101&lt;/code&gt;). That way, when we read the compressed stream left-to-right, we always know where one symbol ends and the next begins&amp;mdash;no need for extra separators (unlike Morse code, which needs pauses between letters).&lt;/p&gt;
&lt;p&gt;A simple way to build such codes is with a &lt;strong&gt;binary tree&lt;/strong&gt;: each character is a leaf, and the path from the root to that leaf (e.g. left=0, right=1) is its code. The algorithm builds the tree from the &lt;strong&gt;bottom up&lt;/strong&gt;, repeatedly grouping the two least frequent symbols (or groups) until everything is in one tree. Frequent characters end up near the root (short path); rare ones end up deeper (long path).&lt;/p&gt;
&lt;p&gt;Conceptually:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot;&gt;// Standard 8-bit encoding (e.g. ASCII): every character uses 8 bits
&quot;E&quot; = 01000101 (8 bits)
&quot;Z&quot; = 01011010 (8 bits)

// Huffman encoding (example): frequent letters get shorter codes
&quot;E&quot; = 10      (2 bits)   &amp;larr; common in English
&quot;Z&quot; = 111010  (6 bits)   &amp;larr; rare, so longer code
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So Huffman doesn&amp;rsquo;t &amp;ldquo;invent&amp;rdquo; new information; it &lt;strong&gt;represents&lt;/strong&gt; the same information in fewer bits by exploiting how often each symbol appears.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;32-lz77-ive-seen-this-beforepoint-back-to-it&quot;&gt;3.2 LZ77: &amp;ldquo;I&amp;rsquo;ve Seen This Before&amp;mdash;Point Back to It&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;Huffman only shortens symbols based on frequency. It doesn&amp;rsquo;t remove &lt;strong&gt;repeated phrases&lt;/strong&gt;. That&amp;rsquo;s where &lt;strong&gt;LZ77&lt;/strong&gt; (and family) comes in.&lt;/p&gt;
&lt;p&gt;LZ77 keeps a &lt;strong&gt;sliding window&lt;/strong&gt; of recently seen data. As it reads the input, it looks for the &lt;strong&gt;longest match&lt;/strong&gt; between:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;what&amp;rsquo;s coming next (the &amp;ldquo;look-ahead&amp;rdquo; buffer), and&lt;/li&gt;
&lt;li&gt;what it has already seen (the &amp;ldquo;search&amp;rdquo; buffer).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When it finds a match, it doesn&amp;rsquo;t output the phrase again. Instead it outputs a &lt;strong&gt;back-reference&lt;/strong&gt;: a pair &lt;strong&gt;(distance, length)&lt;/strong&gt; meaning &amp;ldquo;go back &lt;code&gt;distance&lt;/code&gt; bytes and copy &lt;code&gt;length&lt;/code&gt; bytes.&amp;rdquo; The decoder can then reconstruct the phrase from earlier in the stream.&lt;/p&gt;
&lt;p&gt;So the stream becomes a mix of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Literal&lt;/strong&gt; bytes (when there&amp;rsquo;s no useful match), and&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Back-references&lt;/strong&gt; (when a phrase repeats).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot;&gt;Input:  &quot;The quick brown fox jumps over the quick dog&quot;
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        &quot;the quick&quot; appears twice

Compressed idea:
  Literals: &quot;The quick brown fox jumps over &quot;
  Back-reference: (distance=31, length=9)  &amp;rarr; copy 9 bytes from 31 bytes ago
  Literals: &quot; dog&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this step, the stream has fewer bytes but still contains the same information. Then Huffman (or similar) is applied to that stream to shorten the representation of literals and back-reference pairs&amp;mdash;that&amp;rsquo;s DEFLATE in a nutshell.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;4-zip-vs-targz-same-ideas-different-packaging&quot;&gt;4. ZIP vs. TAR.GZ: Same Ideas, Different Packaging&lt;/h2&gt;
&lt;p&gt;Both ZIP and TAR.GZ use lossless compression (often DEFLATE/GZIP-style), but they &lt;strong&gt;package&lt;/strong&gt; files differently. That difference affects compression ratio and how you can access files.&lt;/p&gt;
&lt;h3 id=&quot;zip-one-file-at-a-time&quot;&gt;ZIP: One File at a Time&lt;/h3&gt;
&lt;p&gt;ZIP compresses &lt;strong&gt;each file separately&lt;/strong&gt; and then puts them in one archive, with a central directory so you can list and extract individual files.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros:&lt;/strong&gt; &lt;strong&gt;Random access.&lt;/strong&gt; You can extract &lt;code&gt;image_402.jpg&lt;/code&gt; from a 50GB archive without reading or decompressing the rest. Good for browsing and pulling single files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons:&lt;/strong&gt; The compressor never looks &lt;strong&gt;across&lt;/strong&gt; file boundaries. If 100 files are nearly identical, ZIP may store 100 separate compressed versions and miss shared patterns. So total size can be larger than a &amp;ldquo;solid&amp;rdquo; archive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So ZIP is great when you need &lt;strong&gt;per-file access&lt;/strong&gt; and broad compatibility (e.g. Windows, macOS, Linux).&lt;/p&gt;
&lt;h3 id=&quot;targz-one-big-stream-solid-archive&quot;&gt;TAR.GZ: One Big Stream (Solid Archive)&lt;/h3&gt;
&lt;p&gt;TAR.GZ is a &lt;strong&gt;two-step&lt;/strong&gt; process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;TAR (Tape Archiver):&lt;/strong&gt; Concatenate all files into one continuous &lt;strong&gt;stream&lt;/strong&gt; (no compression yet). This is a &amp;ldquo;solid&amp;rdquo; archive&amp;mdash;one long byte stream.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GZIP:&lt;/strong&gt; Compress that &lt;strong&gt;entire&lt;/strong&gt; stream with DEFLATE (LZ77 + Huffman) as if it were a single file.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because GZIP sees the whole project as one stream, it can find patterns that span &lt;strong&gt;many files&lt;/strong&gt;. A repeated header in &lt;code&gt;file_A.txt&lt;/code&gt; can be used to compress the same header in &lt;code&gt;file_Z.txt&lt;/code&gt;. That&amp;rsquo;s why you can get a &lt;strong&gt;much&lt;/strong&gt; better ratio&amp;mdash;e.g. 100GB down to 25GB&amp;mdash;when you have lots of similar or repeated content across files.&lt;/p&gt;
&lt;p&gt;Trade-off: to get &lt;strong&gt;any&lt;/strong&gt; file out of a TAR.GZ, you typically have to decompress from the beginning up to that file. There&amp;rsquo;s no cheap &amp;ldquo;jump to file 402&amp;rdquo; as in ZIP.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Step 1: Bundle everything into one stream (size unchanged)&lt;/span&gt;
tar -cvf backup.tar ./my_project

&lt;span class=&quot;hljs-comment&quot;&gt;# Step 2: Compress that whole stream&lt;/span&gt;
gzip backup.tar

&lt;span class=&quot;hljs-comment&quot;&gt;# Result: backup.tar.gz &amp;mdash; one compressed stream&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;When to use TAR.GZ:&lt;/strong&gt; Backups, source tarballs, logs, or any case where you want &lt;strong&gt;maximum compression&lt;/strong&gt; and usually extract the whole archive (or don&amp;rsquo;t mind decompressing from the start to reach a file). Common on Linux and in DevOps pipelines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to prefer ZIP:&lt;/strong&gt; When you need &lt;strong&gt;random access&lt;/strong&gt; to individual files or maximum compatibility with non-Unix systems.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;5-how-video-compression-goes-further-temporal-redundancy&quot;&gt;5. How Video Compression Goes Further: Temporal Redundancy&lt;/h2&gt;
&lt;p&gt;Video has a special kind of redundancy: &lt;strong&gt;between frames&lt;/strong&gt;, most of the image doesn&amp;rsquo;t change. Only moving parts (and lighting changes) differ. So instead of storing every frame in full, modern codecs (e.g. H.264) use &lt;strong&gt;temporal compression&lt;/strong&gt;: store one full frame, then for the next frames store mainly &lt;strong&gt;what changed&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Roughly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;I-frames (Intra-frames):&lt;/strong&gt; Full frames&amp;mdash;like a JPEG image. They don&amp;rsquo;t depend on other frames. Used as anchors so you can seek or recover from errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;P-frames (Predictive):&lt;/strong&gt; Encoded as &amp;ldquo;differences&amp;rdquo; from a previous frame (or I-frame). Much smaller than a full frame.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B-frames (Bi-predictive):&lt;/strong&gt; Use both past and future frames to predict the current frame, so they can be even smaller.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So conceptually:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot;&gt;Frame 1 (I):  Full image of a sunset
Frame 2 (P):  &amp;ldquo;Same as Frame 1, but the bird moved 2 pixels left&amp;rdquo;
Frame 3 (P):  &amp;ldquo;Same as Frame 2, but the bird moved 2 pixels left&amp;rdquo;
&amp;hellip;
Total stored: one full frame + many small &amp;ldquo;deltas&amp;rdquo; and motion vectors
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.ratnesh-maurya.com/images/blogs-inline-image/inter-frame-prediction-video-compression.png&quot; alt=&quot;Inter-frame prediction: I-frame and P-frames with motion vectors. Frame 1 is a full photo; Frames 2 and 3 store only the moving bird and motion vector (-2, 0).&quot;&gt;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s &lt;strong&gt;temporal&lt;/strong&gt; compression. Video also uses &lt;strong&gt;spatial&lt;/strong&gt; compression inside each frame (similar in spirit to JPEG). Together, temporal + spatial (and often lossy choices) let streaming and storage stay practical at 1080p and 4K.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;6-wrapping-up&quot;&gt;6. Wrapping Up&lt;/h2&gt;
&lt;p&gt;Compression is the invisible engine behind smaller backups, faster transfers, and watchable video. The main ideas are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Redundancy&lt;/strong&gt; is removed or shortened: repeated phrases become back-references (LZ77), and frequent symbols get short codes (Huffman).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lossless&lt;/strong&gt; (ZIP, GZIP, PNG) keeps every bit; &lt;strong&gt;lossy&lt;/strong&gt; (JPEG, MP3, H.264) trades a bit of quality for much smaller size.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ZIP&lt;/strong&gt; compresses file-by-file for random access; &lt;strong&gt;TAR.GZ&lt;/strong&gt; compresses one solid stream for better ratio when you don&amp;rsquo;t need per-file random access.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Video&lt;/strong&gt; adds &lt;strong&gt;temporal&lt;/strong&gt; compression: store full frames rarely, and mostly store changes between frames.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Understanding these mechanics helps you choose the right format&amp;mdash;whether you&amp;rsquo;re optimizing Next.js assets, shipping backups to S3, or tuning video encoding&amp;mdash;and demystifies how 100GB can become 25GB without losing a single bit.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;written using AI tools&lt;/p&gt;
&lt;/blockquote&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/14657/the-mechanics-of-compression-how-100gb-becomes-25gb</guid>
<pubDate>Sun, 19 Apr 2026 23:55:52 +0000</pubDate>
</item>
<item>
<title>Mastering Lambda Expressions, Functional Interfaces, and Streams in Java 8 and Beyond</title>
<link>https://coderlegion.com/2914/mastering-lambda-expressions-functional-interfaces-and-streams-in-java-8-andbeyond</link>
<description>&lt;p&gt;Java 8 revolutionized how developers write and think about Java code by introducing &lt;em&gt;functional programming&lt;/em&gt; concepts. At the heart of this transformation are &lt;strong&gt;Lambda Expressions&lt;/strong&gt;, &lt;strong&gt;Functional Interfaces&lt;/strong&gt;, and the &lt;strong&gt;Streams API&lt;/strong&gt;. These features together promote a more expressive, concise, and readable way to write code that is powerful, efficient, and scalable.&lt;/p&gt;
&lt;p&gt;In this comprehensive article, we will dive deep into each of these features, understand the underlying theory, and then walk through practical examples with detailed, line-by-line explanations.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;1-introduction-to-functional-programming-in-java&quot;&gt;1. Introduction to Functional Programming in Java&lt;/h3&gt;
&lt;p&gt;Before Java 8, Java was strictly an &lt;strong&gt;object-oriented&lt;/strong&gt; programming language. Functional programming concepts like passing behavior (not just data) as arguments were difficult and verbose. Java 8 brought in a hybrid model, enabling functional programming through lambdas and streams while retaining OOP principles.&lt;/p&gt;
&lt;h4 id=&quot;what-is-functional-programming-&quot;&gt;What is Functional Programming?&lt;/h4&gt;
&lt;p&gt;Functional programming is a paradigm where &lt;strong&gt;functions are treated as first-class citizens&lt;/strong&gt;. It encourages writing pure functions, immutability, and declarative constructs to process data.&lt;/p&gt;
&lt;p&gt;Key concepts include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Functions can be passed as arguments&lt;/li&gt;
&lt;li&gt;No side effects&lt;/li&gt;
&lt;li&gt;Lazy evaluation&lt;/li&gt;
&lt;li&gt;Higher-order functions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Java's adoption of functional programming features made the language more expressive and concise, especially for data manipulation and collection processing.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;2-lambda-expressions-in-java&quot;&gt;2. Lambda Expressions in Java&lt;/h3&gt;
&lt;h4 id=&quot;what-is-a-lambda-expression-&quot;&gt;What is a Lambda Expression?&lt;/h4&gt;
&lt;p&gt;A &lt;strong&gt;Lambda Expression&lt;/strong&gt; is an anonymous function that can be passed around as data. It provides a clear and concise way to represent a method interface using an expression.&lt;/p&gt;
&lt;h5 id=&quot;syntax-&quot;&gt;Syntax:&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;(parameters) -&amp;gt; expression
(parameters) -&amp;gt; { statements }
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;characteristics-&quot;&gt;Characteristics:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;No name (anonymous)&lt;/li&gt;
&lt;li&gt;Can be assigned to a variable&lt;/li&gt;
&lt;li&gt;Implements a &lt;strong&gt;functional interface&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Enables cleaner and more expressive code&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;why-use-lambda-expressions-&quot;&gt;Why Use Lambda Expressions?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Simplifies writing anonymous inner classes&lt;/li&gt;
&lt;li&gt;Makes code more readable and concise&lt;/li&gt;
&lt;li&gt;Enables functional-style operations on collections&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;example-&quot;&gt;Example:&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;Runnable r = () -&amp;gt; System.out.println(&quot;Running a thread&quot;);
r.run();
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;traditional-vs-lambda-&quot;&gt;Traditional vs Lambda:&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;// Traditional Runnable
Runnable r1 = new Runnable() {
    public void run() {
        System.out.println(&quot;Hello from thread&quot;);
    }
};
r1.run();

// Lambda Runnable
Runnable r2 = () -&amp;gt; System.out.println(&quot;Hello from lambda&quot;);
r2.run();
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;common-lambda-use-cases-&quot;&gt;Common Lambda Use Cases:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Event handling&lt;/li&gt;
&lt;li&gt;Threading&lt;/li&gt;
&lt;li&gt;Collection iteration&lt;/li&gt;
&lt;li&gt;Stream operations&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;3-functional-interfaces&quot;&gt;3. Functional Interfaces&lt;/h3&gt;
&lt;h4 id=&quot;what-is-a-functional-interface-&quot;&gt;What is a Functional Interface?&lt;/h4&gt;
&lt;p&gt;A &lt;strong&gt;Functional Interface&lt;/strong&gt; is an interface with exactly &lt;strong&gt;one abstract method&lt;/strong&gt;. It can have default or static methods, but only one method must be abstract.&lt;/p&gt;
&lt;h5 id=&quot;examples-in-java-&quot;&gt;Examples in Java:&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@FunctionalInterface
interface Calculator {
    int operation(int a, int b);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;functional-interface-characteristics-&quot;&gt;Functional Interface Characteristics:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Annotated with &lt;code&gt;@FunctionalInterface&lt;/code&gt; (not mandatory but recommended)&lt;/li&gt;
&lt;li&gt;Target type for lambda expressions&lt;/li&gt;
&lt;li&gt;Defined in &lt;code&gt;java.util.function&lt;/code&gt; package for standard use cases&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;common-built-in-functional-interfaces-&quot;&gt;Common Built-in Functional Interfaces:&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Interface          &lt;/th&gt;&lt;th&gt;Abstract Method &lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Predicate       &lt;/td&gt;&lt;td&gt;test(T t)       &lt;/td&gt;&lt;td&gt;Returns true/false&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Consumer        &lt;/td&gt;&lt;td&gt;accept(T t)     &lt;/td&gt;&lt;td&gt;Consumes input, no return&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Function&lt;/td&gt;&lt;td&gt;apply(T t)      &lt;/td&gt;&lt;td&gt;Converts T to R&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Supplier        &lt;/td&gt;&lt;td&gt;get()           &lt;/td&gt;&lt;td&gt;Supplies a result&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BiFunction&lt;/td&gt;&lt;td&gt;apply(T,U)      &lt;/td&gt;&lt;td&gt;Takes two args, returns one&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&quot;example-with-lambda-&quot;&gt;Example with Lambda:&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;Function&amp;lt;String, Integer&amp;gt; lengthFunc = s -&amp;gt; s.length();
System.out.println(lengthFunc.apply(&quot;Lambda&quot;)); // Output: 6
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;4-streams-api&quot;&gt;4. Streams API&lt;/h3&gt;
&lt;h4 id=&quot;what-is-a-stream-&quot;&gt;What is a Stream?&lt;/h4&gt;
&lt;p&gt;A &lt;strong&gt;Stream&lt;/strong&gt; is a pipeline of elements from a data source (e.g., collections) that supports aggregate operations such as &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;reduce&lt;/code&gt;, &lt;code&gt;collect&lt;/code&gt;, etc.&lt;/p&gt;
&lt;h4 id=&quot;stream-characteristics-&quot;&gt;Stream Characteristics:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Doesn’t store data, just processes it&lt;/li&gt;
&lt;li&gt;Lazy evaluation&lt;/li&gt;
&lt;li&gt;Can be sequential or parallel&lt;/li&gt;
&lt;li&gt;Doesn’t modify the source&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;stream-pipeline-structure-&quot;&gt;Stream Pipeline Structure:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Source&lt;/strong&gt;: e.g., List, Set, Map&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Intermediate Operations&lt;/strong&gt;: e.g., &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;sorted&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terminal Operation&lt;/strong&gt;: e.g., &lt;code&gt;collect&lt;/code&gt;, &lt;code&gt;count&lt;/code&gt;, &lt;code&gt;forEach&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;common-operations-&quot;&gt;Common Operations:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;filter(Predicate)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;map(Function)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sorted(Comparator)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;limit(long)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;collect(Collectors)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;5-practical-example-with-explanation&quot;&gt;5. Practical Example with Explanation&lt;/h3&gt;
&lt;p&gt;Let’s analyze this common example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;List&amp;lt;String&amp;gt; names = Arrays.asList(&quot;John&quot;, &quot;Alice&quot;, &quot;Bob&quot;);

List&amp;lt;String&amp;gt; filtered =
    names.stream()
         .filter(name -&amp;gt; name.startsWith(&quot;A&quot;))
         .map(String::toUpperCase)
         .collect(Collectors.toList());

System.out.println(filtered); // [ALICE]
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;line-by-line-breakdown-&quot;&gt;Line-by-Line Breakdown:&lt;/h4&gt;
&lt;h5 id=&quot;line-1-&quot;&gt;Line 1:&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;List&amp;lt;String&amp;gt; names = Arrays.asList(&quot;John&quot;, &quot;Alice&quot;, &quot;Bob&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Creates a &lt;code&gt;List&lt;/code&gt; of &lt;code&gt;String&lt;/code&gt; with three names.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Arrays.asList()&lt;/code&gt; creates a fixed-size list backed by an array.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;line-3-&quot;&gt;Line 3:&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;names.stream()
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Converts the list into a &lt;strong&gt;Stream&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;No data is processed yet (lazy initialization).&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;line-4-&quot;&gt;Line 4:&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;.filter(name -&amp;gt; name.startsWith(&quot;A&quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Intermediate operation.&lt;/li&gt;
&lt;li&gt;Filters elements where the name starts with &quot;A&quot;.&lt;/li&gt;
&lt;li&gt;Result: &lt;code&gt;Stream.of(&quot;Alice&quot;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;line-5-&quot;&gt;Line 5:&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;.map(String::toUpperCase)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Maps the name &quot;Alice&quot; to its uppercase form.&lt;/li&gt;
&lt;li&gt;Result: &lt;code&gt;Stream.of(&quot;ALICE&quot;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;line-6-&quot;&gt;Line 6:&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;.collect(Collectors.toList());
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Terminal operation.&lt;/li&gt;
&lt;li&gt;Converts the stream into a &lt;code&gt;List&amp;lt;String&amp;gt;&lt;/code&gt; containing one element: &lt;code&gt;[&quot;ALICE&quot;]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;line-8-&quot;&gt;Line 8:&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;System.out.println(filtered);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Prints the final result: &lt;code&gt;[ALICE]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;6-real-world-use-cases-of-lambdas-functional-interfaces-and-streams&quot;&gt;6. Real-World Use Cases of Lambdas, Functional Interfaces, and Streams&lt;/h3&gt;
&lt;h4 id=&quot;1-filtering-and-transforming-user-data&quot;&gt;1. Filtering and transforming user data&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;List&amp;lt;User&amp;gt; users = ...
List&amp;lt;String&amp;gt; emails = users.stream()
    .filter(user -&amp;gt; user.isActive())
    .map(User::getEmail)
    .collect(Collectors.toList());
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;2-logging-and-event-handling&quot;&gt;2. Logging and event handling&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;button.setOnClickListener(event -&amp;gt; System.out.println(&quot;Clicked!&quot;));
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;3-sorting-with-comparator-and-lambdas&quot;&gt;3. Sorting with Comparator and Lambdas&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;Collections.sort(users, (u1, u2) -&amp;gt; u1.getName().compareTo(u2.getName()));
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;7-best-practices&quot;&gt;7. Best Practices&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Keep lambdas short and expressive&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use method references when possible&lt;/strong&gt; (&lt;code&gt;String::toUpperCase&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avoid side-effects&lt;/strong&gt; in stream pipelines&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use parallel streams only when beneficial&lt;/strong&gt; (e.g., large datasets)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chain operations for readability and maintainability&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;8-conclusion&quot;&gt;8. Conclusion&lt;/h3&gt;
&lt;p&gt;Lambda expressions, functional interfaces, and the Stream API are cornerstones of modern Java programming. They enable a &lt;strong&gt;declarative&lt;/strong&gt;, &lt;strong&gt;functional&lt;/strong&gt;, and &lt;strong&gt;clean&lt;/strong&gt; way to process data and compose logic.&lt;/p&gt;
&lt;p&gt;By mastering these constructs, Java developers can write code that is &lt;strong&gt;more concise, expressive, thread-safe, and easier to test and maintain&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you haven’t already started integrating these into your projects, now is the time to evolve your Java style into the functional future.&lt;/p&gt;
&lt;p&gt;Originally published at &lt;a rel=&quot;nofollow&quot; href=&quot;https://aditya-sunjava.medium.com/mastering-lambda-expressions-functional-interfaces-and-streams-in-java-8-and-beyond-e7617075815a&quot;&gt;Medium&lt;/a&gt;.&lt;/p&gt;
</description>
<category>Java</category>
<guid isPermaLink="true">https://coderlegion.com/2914/mastering-lambda-expressions-functional-interfaces-and-streams-in-java-8-andbeyond</guid>
<pubDate>Thu, 08 May 2025 06:18:17 +0000</pubDate>
</item>
</channel>
</rss>