0% found this document useful (0 votes)
15 views11 pages

Base64 Encoding and Decoding in Java

The document provides an overview of various Java programming concepts including method references, the Stream API, Base64 encoding and decoding, the forEach loop, try-with-resources, and type and repeating annotations. It explains how to use these features with examples and highlights their benefits and functionalities. Key operations of the Stream API, such as intermediate and terminal operations, are also discussed along with practical coding examples.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views11 pages

Base64 Encoding and Decoding in Java

The document provides an overview of various Java programming concepts including method references, the Stream API, Base64 encoding and decoding, the forEach loop, try-with-resources, and type and repeating annotations. It explains how to use these features with examples and highlights their benefits and functionalities. Key operations of the Stream API, such as intermediate and terminal operations, are also discussed along with practical coding examples.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

lOMoARcPSD|38190532

[Link]();
}
}

Output:
Hello, this is non-static method.
Hello, this is non-static method.

3) Reference to a Constructor
You can refer a constructor by using the new keyword. Here, we are referring constructor
with the help of functional interface.

Syntax

ClassName::new

Example

interface Messageable{
Message getMessage(String msg);
}
class Message{
Message(String msg){
[Link](msg);
}
}
public class ConstructorReference {
public static void main(String[] args) {
Messageable hello = Message::new;
[Link]("Hello");
}
}

Output:

Hello

[Link] In Java
Introduced in Java 8, Stream API is used to process collections of objects. A stream in Java is
a sequence of objects that supports various methods which can be pipelined to produce the
desired result.

Use of Stream in Java


There uses of Stream in Java are mentioned below:

Stream API is a way to express and process collections of objects.


Enable us to perform operations like filtering, mapping,reducing and sorting.
How to Create Java Stream?
Java Stream Creation is one of the most basic steps before considering the functionalities of
the Java Stream. Below is the syntax given on how to declare Java Stream.

Syntax
lOMoARcPSD|38190532

Stream<T> stream;
Here T is either a class, object, or data type depending upon the declaration.

Java Stream Features


The features of Java stream are mentioned below:

A stream is not a data structure instead it takes input from the Collections, Arrays or I/O
channels.
Streams don’t change the original data structure, they only provide the result as per the
pipelined methods.
Each intermediate operation is lazily executed and returns a stream as a result, hence various
intermediate operations can be pipelined. Terminal operations mark the end of the stream and
return the result.
Different Operations On Streams
There are two types of Operations in Streams:
Intermediate Operations
Terminate Operations

Intermediate Operations

Intermediate Operations are the types of operations in which multiple methods are
chained in a row.

Characteristics of Intermediate Operations


Methods are chained together.
Intermediate operations transform a stream into another stream.
It enables the concept of filtering where one method filters data and passes it to another
method after processing.
Benefit of Java Stream
There are some benefits because of which we use Stream in Java as mentioned below:

No Storage
Pipeline of Functions
Laziness
Can be infinite
Can be parallelized
Can be created from collections, arrays, Files Lines, Methods in Stream, IntStream etc.

Important Intermediate Operations


There are a few Intermediate Operations mentioned below:
lOMoARcPSD|38190532

1. map()
The map method is used to return a stream consisting of the results of applying the given
function to the elements of this stream.

List number = [Link](2,3,4,5);


List square = [Link]().map(x->x*x).collect([Link]());
2. filter()
The filter method is used to select elements as per the Predicate passed as an argument.

List names = [Link]("Reflection","Collection","Stream");


List result = [Link]().filter(s->[Link]("S")).collect([Link]());
3. sorted()
The sorted method is used to sort the stream.

List names = [Link]("Reflection","Collection","Stream");


List result = [Link]().sorted().collect([Link]());
Terminal Operations
Terminal Operations are the type of Operations that return the result. These Operations are
not processed further just return a final result value.

Important Terminal Operations


There are a few Terminal Operations mentioned below:

1. collect()
The collect method is used to return the result of the intermediate operations performed on
the stream.

List number = [Link](2,3,4,5,3);


Set square = [Link]().map(x->x*x).collect([Link]());
2. forEach()
The forEach method is used to iterate through every element of the stream.

List number = [Link](2,3,4,5);


[Link]().map(x->x*x).forEach(y->[Link](y));
3. reduce()
The reduce method is used to reduce the elements of a stream to a single value. The reduce
method takes a BinaryOperator as a parameter.

List number = [Link](2,3,4,5);


int even = [Link]().filter(x->x%2==0).reduce(0,(ans,i)-> ans+i);
Here ans variable is assigned 0 as the initial value and i is added to it.

Note: Intermediate Operations are running based on the concept of Lazy Evaluation, which
ensures that every method returns a fixed value(Terminal operation) before moving to the
next method.

Example of Java Stream


Java

// Java program to demonstrate


// the use of stream in java
import [Link].*;
import [Link].*;
lOMoARcPSD|38190532

class Demo {
public static void main(String args[])
{
// create a list of integers
List<Integer> number = [Link](2, 3, 4, 5);

// demonstration of map method


List<Integer> square
= [Link]()
.map(x -> x * x)
.collect([Link]());

// create a list of String


List<String> names = [Link](
"Reflection", "Collection", "Stream");

// demonstration of filter method


List<String> result
= [Link]()
.filter(s -> [Link]("S"))
.collect([Link]());

[Link](result);

// demonstration of sorted method


List<String> show
= [Link]()
.sorted()
.collect([Link]());

[Link](show);

// create a list of integers


List<Integer> numbers
= [Link](2, 3, 4, 5, 2);

// collect method returns a set


Set<Integer> squareSet
= [Link]()
.map(x -> x * x)
.collect([Link]());

[Link](squareSet);

// demonstration of forEach method


[Link]()
.map(x -> x * x)
.forEach(y -> [Link](y));

// demonstration of reduce method


int even
= [Link]()
.filter(x -> x % 2 == 0)
lOMoARcPSD|38190532

.reduce(0, (ans, i) -> ans + i);

[Link](even);
}
}
Output

[4, 9, 16, 25]


[Stream]
[Collection, Reflection, Stream]
[16, 4, 9, 25]
4
9
16
25
6

5. Basic Type Base64 Encoding and Decoding in Java

In computer programming, Base64 is a group of binary-to-text encoding schemes that


transforms binary data into a sequence of printable characters, limited to a set of 64 unique
characters. More specifically, the source binary data is taken 6 bits at a time, then this group of
6 bits is mapped to one of 64 unique characters.
As with all binary-to-text encoding schemes, Base64 is designed to carry data stored in binary
formats across channels that only reliably support text content. Base64 is particularly prevalent
on the World Wide Web[1] where one of its uses is the ability to embed image files or other
binary assets inside textual assets such as HTML and CSS files.[2]
Base64 is also widely used for sending e-mail attachments, because SMTP – in its original
form – was designed to transport 7-bit ASCII characters only. Encoding an attachment as
Base64 before sending, and then decoding when received, assures older SMTP servers will not
interfere with the attachment.

Base 64 is an encoding scheme that converts binary data into text format so that encoded
textual data can be easily transported over network un-corrupted and without any data
loss.(Base 64 format reference).
The Basic encoding means no line feeds are added to the output and the output is mapped to a
set of characters in A-Za-z0-9+/ character set and the decoder rejects any character outside of
this set.

Encode simple String into Basic Base 64 format

String BasicBase64format= [Link]().encodeToString(“actualString”.getBytes());

Explanation: In above code we called [Link] using getEncoder() and then get the
encoded string by passing the byte value of actualString in encodeToString() method as
parameter.

Decode Basic Base 64 format to String

byte[] actualByte= [Link]().decode(encodedString);


String actualString= new String(actualByte);
lOMoARcPSD|38190532

Explanation: In above code we called [Link] using getDecoder() and then decoded
the string passed in decode() method as parameter then convert return value to string.

Below programs illustrate the Encoding and Decoding in Java:

Program 1:Encode simple String into Basic Base 64 format


// Java program to demonstrate
// Encoding simple String into Basic Base 64 format

import [Link].*;
public class GFG {
public static void main(String[] args)
{

// create a sample String to encode


String sample = "India Team will win the Cup";

// print actual String


[Link]("Sample String:\n" + sample);

// Encode into Base64 format


String BasicBase64format = [Link]().encodeToString([Link]());

// print encoded String


[Link]("Encoded String:\n" + BasicBase64format);
}
}
Output:
Sample String: India Team will win the Cup
Encoded String: SW5kaWEgVGVhbSB3aWxsIHdpbiB0aGUgQ3Vw

Program 2: Decode Basic Base 64 format to String


// Java program to demonstrate
// Decoding Basic Base 64 format to String

import [Link].*;
public class GFG {
public static void main(String[] args)
{
// create an encoded String to decode
String encode = "SW5kaWEgVGVhbSB3aWxsIHdpbiB0aGUgQ3Vw";
// print encoded String
[Link]("Encoded String:\n+ encoded);
// decode into String from encoded format
byte[] actualByte = [Link]() .decode(encoded);

String actualString = new String(actualByte);


// print actual String
[Link]("actual String:\n"
+ actualString);
}
}
Output:
lOMoARcPSD|38190532

Encoded String: SW5kaWEgVGVhbSB3aWxsIHdpbiB0aGUgQ3Vw


actual String: India Team will win the Cup

6. Java forEach loop

Java provides a new method forEach() to iterate the elements. It is defined in Iterable and
Stream interface. It is a default method defined in the Iterable interface. Collection classes
which extends Iterable interface can use forEach loop to iterate elements.
This method takes a single parameter which is a functional interface. So, you can pass
lambda expression as an argument.

forEach() Signature in Iterable Interface


default void forEach(Consumer<super T>action)

Java 8 forEach() example 1

import [Link];
import [Link];
public class ForEachExample {
public static void main(String[] args) {
List<String> gamesList = new ArrayList<String>();
[Link]("Football");
[Link]("Cricket");
[Link]("Chess");
[Link]("Hocky");
[Link]("------------Iterating by passing lambda expression--------------");
[Link](games -> [Link](games));
} }
Output:
------------Iterating by passing lambda expression--------------
Football Cricket Chess Hocky

Java 8 forEach() example 2

import [Link];
import [Link];
public class ForEachExample {
public static void main(String[] args) {
List<String> gamesList = new ArrayList<String>();
[Link]("Football");
[Link]("Cricket");
[Link]("Chess");
[Link]("Hocky");
[Link]("------------Iterating by passing method reference---------------");
[Link]([Link]::println);
} }
Output:
------------Iterating by passing method reference---------------
Football Cricket Chess Hocky

[Link]-with-resources Feature in Java


lOMoARcPSD|38190532

In Java, the Try-with-resources statement is a try statement that declares one or more
resources in it. A resource is an object that must be closed once your program is done using
it. For example, a File resource or a Socket connection resource. The try-with-resources
statement ensures that each resource is closed at the end of the statement execution. If we
don’t close the resources, it may constitute a resource leak and also the program could
exhaust the resources available to it.

You can pass any object as a resource that implements [Link], which
includes all objects which implement [Link].

By this, now we don’t need to add an extra finally block for just passing the closing
statements of the resources. The resources will be closed as soon as the try-catch block is
executed.

Syntax: Try-with-resources

try(declare resources here) {


// use resources
}
catch(FileNotFoundException e) {
// exception handling
}

Exceptions:

When it comes to exceptions, there is a difference in try-catch-finally block and try-with-


resources block. If an exception is thrown in both try block and finally block, the method
returns the exception thrown in finally block.
For try-with-resources, if an exception is thrown in a try block and in a try-with-resources
statement, then the method returns the exception thrown in the try block. The exceptions
thrown by try-with-resources are suppressed, i.e. we can say that try-with-resources block
throws suppressed exceptions.

Now, let us discuss both the possible scenarios which are demonstrated below as an example
as follows:
Case 1: Single resource
Case 2: Multiple resources

Example 1: try-with-resources having a single resource

// Java Program for try-with-resources


// having single resource

// Importing all input output classes


import [Link].*;

// Class
class GFG {

// Main driver method


public static void main(String[] args)
{
// Try block to check for exceptions
lOMoARcPSD|38190532

try (

// Creating an object of FileOutputStream


// to write stream or raw data

// Adding resource
FileOutputStream fos = new FileOutputStream("[Link]")) {

// Custom string input


String text = "Hello World. This is my java program";

// Converting string to bytes


byte arr[] = [Link]();

// Text written in the file


[Link](arr);
}

// Catch block to handle exceptions


catch (Exception e) {

// Display message for the occurred exception


[Link](e);
}

// Display message for successful execution of


// program
[Link](
"Resource are closed and message has been written into the [Link]");
}
}
Output:

Resource are closed and message has been written into the [Link]

[Link] Type and Repeating Annotations

Java Type Annotations


Java 8 has included two new features repeating and type annotations in its prior annotations
topic. In early Java versions, you can apply annotations only to declarations. After releasing
of Java SE 8 , annotations can be applied to any type use. It means that annotations can be
lOMoARcPSD|38190532

used anywhere you use a type. For example, if you want to avoid NullPointerException in
your code, you can declare a string variable like this:

@NonNull String str;


Following are the examples of type annotations:

@NonNull List<String>
List<@NonNull String> str
Arrays<@NonNegative Integer> sort
@Encrypted File file
@Open Connection connection
void divideInteger(int a, int b) throws @ZeroDivisor ArithmeticException
Note - Java created type annotations to support improved analysis of Java programs. It
supports way of ensuring stronger type checking.

Java Repeating Annotations


In Java 8 release, Java allows you to repeating annotations in your source code. It is helpful
when you want to reuse annotation for the same class. You can repeat an annotation anywhere
that you would use a standard annotation.

For compatibility reasons, repeating annotations are stored in a container annotation that is
automatically generated by the Java compiler. In order for the compiler to do this, two
declarations are required in your code.
1. Declare a repeatable annotation type
2. Declare the containing annotation type

1) Declare a repeatable annotation type


Declaring of repeatable annotation type must be marked with the @Repeatable meta-
annotation. In the following example, we have defined a custom @Game repeatable
annotation type.

@Repeatable([Link])
@interfaceGame{
String name();
String day();
}
The value of the @Repeatable meta-annotation, in parentheses, is the type of the container
annotation that the Java compiler generates to store repeating annotations. In the following
example, the containing annotation type is Games. So, repeating @Game annotations is
stored in an @Games annotation.

2) Declare the containing annotation type


Containing annotation type must have a value element with an array type. The component
type of the array type must be the repeatable annotation type. In the following example, we
are declaring Games containing annotation type:

@interfaceGames{
Game[] value();
}
Note - Compiler will throw a compile-time error, if you apply the same annotation to a
declaration without first declaring it as repeatable.

Java Repeating Annotations Example


lOMoARcPSD|38190532

// Importing required packages for repeating annotation

import [Link];
import [Link];
import [Link];
// Declaring repeatable annotation type
@Repeatable([Link])
@interfaceGame{
String name();
String day();
}
// Declaring container for repeatable annotation type
@Retention([Link])
@interfaceGames{
Game[] value();
}
// Repeating annotation
@Game(name = "Cricket", day = "Sunday")
@Game(name = "Hockey", day = "Friday")
@Game(name = "Football", day = "Saturday")
public class RepeatingAnnotationsExample {
public static void main(String[] args) {
// Getting annotation by type into an array
Game[] game =
[Link]([Link]);
for (Gamegame2 : game) { // Iterating values
[Link]([Link]()+" on "+[Link]());
}
}
}
OUTPUT:

Cricket on Sunday
Hockey on Friday
Football on Saturday

[Link] 9 Module System

Java Module System is a major change in Java 9 version. Java added this feature to collect
Java packages and code into a single unit called module.

In earlier versions of Java, there was no concept of module to create modular Java
applications, that why size of application increased and difficult to move around. Even JDK
itself was too heavy in size, in Java 8, [Link] file size is around 64MB.

To deal with situation, Java 9 restructured JDK into set of modules so that we can use only
required module for our project.

Apart from JDK, Java also allows us to create our own modules so that we can develop
module based application.
The module system includes various tools and options that are given below.

Common questions

Powered by AI

Java's forEach method, defined in the Iterable and Stream interfaces, enhances collection iteration by leveraging lambda expressions, leading to a more functional programming style. It accepts a Consumer functional interface, allowing easy iteration over elements with cleaner and more concise syntax. This approach boosts code readability and maintainability by reducing boilerplate code associated with traditional loops. It encourages expressive programming paradigms, aligning with functional programming principles like immutability and declarative iteration .

The try-with-resources statement is significant because it simplifies resource management by ensuring resources are automatically closed after program execution. Unlike the traditional try-catch-finally approach, which manually required resource closing in the finally block, try-with-resources statements are efficient and less error-prone, handling resources that implement AutoCloseable. This method suppresses exceptions by focusing on the try block exception over the resource closing one, ensuring cleaner exception handling and reducing resource leaks .

Base64 encoding transforms binary data into a sequence of 64 unique characters, allowing binary data to be transported across channels that support only text reliably. This is crucial for embedding binary assets inside textual assets like HTML or CSS files or for sending email attachments through SMTP, which traditionally handled only 7-bit ASCII characters. Encoding ensures the data is not corrupted in transit .

Encoding and decoding with Base64 in Java provide significant advantages over other binary-to-text encoding schemes by ensuring compatibility with text-only transport protocols like SMTP and applications that process HTML and CSS. Base64 ensures zero data corruption during Internet transmission by mapping binary data to an ASCII text format using a defined character set. This encoding scheme is particularly advantageous for embedding binary data within text formats without risk of data loss. Its wide usage and standardization also simplify integration across platforms and systems .

The Stream API in Java 8 offers several advantages: it enables the expression and processing of collections using operations like filtering, mapping, reducing, and sorting. It supports method chaining for intermediate operations, allowing for more fluent and readable code. Streams provide lazy execution and can be parallelized for performance optimization. They also do not alter the original data structures, only providing results based on the applied sequence of operations .

Java 9's module system enhances modularity by allowing Java packages and code to be bundled into a single unit called a module. This restructuring into modules helps in managing application size by allowing developers to include only the necessary modules for a project. In Java 8 and earlier, the JDK was monolithic and large, making apps bulky and difficult to manage. The module system allows for clearer dependency management and potentially reduces both the size and complexity of Java applications .

Using method references in lambda expressions benefits Java programming by enhancing code readability and conciseness. Method references allow direct references to methods by their names, eliminating boilerplate code commonly found in lambda expressions. They support a more declarative style, improving code maintainability and simplifying how operations are expressed, especially when performing actions like object construction, instance method invocation on the same object, or static method calls .

In Java 8, type annotations can be applied to any use of a type, enhancing the possibility for stronger type-checking and program analysis. Repeating annotations allow the same annotation to be applied multiple times to the same declaration, enhancing reusability. Unlike earlier Java versions where annotations could only be applied to declarations, these new features introduce more flexible annotation practices. Repeating annotations require declaring a repeatable annotation type and its containing annotation type, organizing repeated annotations into a container .

Java Streams operate by taking input from collections, arrays, or I/O channels, transforming them into streams that do not modify the original data structure. Streams perform operations like mapping, filtering, and reducing to produce results using pipelined methods without altering the data source. This approach improves efficiency by enabling lazy evaluation, where results are computed only as needed, and supports operations like parallelization, potentially enhancing performance while keeping data integrity intact .

Lambdas and functional interfaces enable succinct creation of single-method interfaces, which can be targeted by method and constructor references. This feature facilitates the instantiation of objects and simplifies the invocation of methods, making Java code more expressive and compact. Examples include reference to a constructor using ClassName::new or a method reference like System.out::println. This can be particularly useful in scenarios requiring dynamic behavior definition, such as event handling, collection processing using streams, and asynchronous task execution .

You might also like