How to convert Strings to and from UTF8 byte arrays in Java
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
To convert a Java String to a UTF-8 byte array, call str.getBytes(StandardCharsets.UTF_8). To convert back, use new String(bytes, StandardCharsets.UTF_8). Using the StandardCharsets constant instead of the string "UTF-8" avoids checked exceptions and is the recommended approach since Java 7. This article covers both the modern and legacy APIs, explains what happens under the hood during encoding and decoding, and shows patterns for handling edge cases in production code.
String to UTF-8 Byte Array
Modern Approach (Java 7+)
The cleanest way to encode a String into UTF-8 bytes uses StandardCharsets.UTF_8:
This version has no checked exceptions. StandardCharsets.UTF_8 is a Charset object guaranteed to be available on every JVM, so UnsupportedEncodingException is impossible.
Legacy Approach (Pre-Java 7)
The older API takes a charset name as a string:
The catch block is boilerplate that exists only to satisfy the compiler. Since UTF-8 is required by the Java specification, this exception cannot be thrown in practice. Prefer the StandardCharsets version to eliminate this noise.
UTF-8 Byte Array to String
Modern Approach
Legacy Approach
The same reasoning applies: prefer StandardCharsets.UTF_8 for cleaner code.
Partial Array Conversion
When you only need to decode a portion of the byte array:
This is useful when reading from buffers or protocols where the UTF-8 payload starts at an offset.
API Comparison
| Operation | Modern API | Legacy API | Exception Handling |
| String to bytes | str.getBytes(StandardCharsets.UTF_8) | str.getBytes("UTF-8") | None required vs UnsupportedEncodingException |
| Bytes to String | new String(bytes, StandardCharsets.UTF_8) | new String(bytes, "UTF-8") | None required vs UnsupportedEncodingException |
| Partial decode | new String(bytes, off, len, StandardCharsets.UTF_8) | new String(bytes, off, len, "UTF-8") | None required vs UnsupportedEncodingException |
How UTF-8 Encoding Works Internally
Java Strings are internally stored as sequences of char values using UTF-16 encoding (or compact Latin-1 in Java 9+ with compact strings enabled). When you call getBytes(StandardCharsets.UTF_8), the JVM converts each Unicode code point from its internal representation to its UTF-8 byte sequence.
UTF-8 is a variable-width encoding. The number of bytes per character depends on the Unicode code point:
| Code Point Range | UTF-8 Bytes | Example |
| U+0000 to U+007F | 1 byte | ASCII characters (A, z, 5) |
| U+0080 to U+07FF | 2 bytes | Latin extensions, Greek, Cyrillic |
| U+0800 to U+FFFF | 3 bytes | CJK characters, most symbols |
| U+10000 to U+10FFFF | 4 bytes | Emoji, rare scripts |
This means that "Hello".getBytes(StandardCharsets.UTF_8).length is 5 (one byte per ASCII character), but a string containing emoji or CJK characters will produce more bytes than characters:
Using CharsetEncoder for Fine-Grained Control
When you need to handle malformed input or control error behavior, CharsetEncoder gives you more options than getBytes():
The CodingErrorAction options are:
REPORT: throwCharacterCodingExceptionon invalid inputREPLACE: substitute the replacement character (U+FFFD)IGNORE: silently drop invalid characters
The default behavior of getBytes() is REPLACE, which means malformed surrogate pairs are silently converted to the UTF-8 replacement character bytes without any warning.
Reading and Writing UTF-8 Files
For file I/O, the Files API in java.nio.file handles charset conversion directly:
For streaming large files, use BufferedReader and BufferedWriter with explicit charset:
Network and Serialization Patterns
When sending strings over the network or serializing to a byte protocol, always be explicit about encoding:
Note that Content-Length must be the byte length, not the string character length. For ASCII-only content these are the same, but for multibyte characters they differ.
Common Pitfalls
Using the platform's default charset by calling str.getBytes() without a charset argument is the most dangerous mistake. The default charset varies by operating system and JVM configuration. Code that works on a developer's macOS machine (default UTF-8) can produce corrupted data on a Windows server (default Windows-1252).
Confusing string length with byte length causes buffer overflows and truncation bugs. "Hello".length() returns 5, and its UTF-8 byte array is also 5 bytes. But a string with multibyte characters has a byte length larger than its character count.
Catching UnsupportedEncodingException and swallowing it silently hides a code smell. If you see this catch block, switch to StandardCharsets.UTF_8 and eliminate the exception entirely.
Assuming all byte arrays are valid UTF-8 leads to silent data corruption. When decoding bytes from an untrusted source, use CharsetDecoder with CodingErrorAction.REPORT to detect invalid sequences rather than silently replacing them.
Mixing charsets between encoding and decoding produces garbled text (mojibake). If you encode with UTF-8, you must decode with UTF-8. This is especially common in systems where one service writes files in one encoding and another reads them assuming a different one.
Summary
- Use
str.getBytes(StandardCharsets.UTF_8)to convert a String to UTF-8 bytes. - Use
new String(bytes, StandardCharsets.UTF_8)to convert UTF-8 bytes back to a String. - Prefer
StandardCharsets.UTF_8over the string"UTF-8"to avoid unnecessary checked exceptions. - Remember that UTF-8 byte length is not always equal to string character length for non-ASCII text.
- Use
CharsetEncoder/CharsetDecoderwhen you need explicit control over malformed input handling. - Always specify a charset explicitly. Never rely on the platform default.
Related reading
- How to convert UInt8 byte array to string in Swift
- How to convert UTF-8 byte[] to string
- How to convert UTF-8 byte to string
- How to copy a 2D array into a 3rd dimension, N times?
- How to convert/parse from String to char in java?
- How to cope with x-forwarded-headers in Spring Boot 2.2.0? Spring Web MVC behind reverse proxy
- How to copy a dictionary and only edit the copy
- How to copy a dictionary and only edit the copy

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.