Showing posts with label Core Java. Show all posts
Showing posts with label Core Java. Show all posts

23 January 2024

Exploring the features of Java in Simple Terms

 Introduction:-

Java is a very popular programming language that is simple portable and robust as well. Java is the backbone of many applications which includes mobile applications and enterprise-level systems. In this blog, we will explore the significance of Java in the world of coding languages.


1. Write Once, Run Anywhere (WORA):-

WORA feature of Java is a standout. The meaning of this feature is that once we write the Java program then we can run it on any platform or device. This is done by Java Virtual Machine (JVM) which is the universal interpreter for the code written by us. Hence, we can use any operating system like Windows, macOS, or Linux to run the Java program.


2. Object Oriented Programming (OOP):- 

Java is based on Object-oriented programming which makes the development process easy. It reuses the objects with well-organized code. Encapsulation of data by objects makes code easy to understand. This leads to the enhancement of code flexibility.


3. Simplicity & Readability:-

Java is designed in a very simple manner. The syntax of Java is easy to understand which helps experienced and beginner developers to write code efficiently. If any developer switches from the programming language C++ to Java then he finds the syntax of Java easier than C++. Javas code is easy to read which reduces the errors which could be generated while coding. Javas simpler and readable code syntax increase the productivity of developer.


4. Platform Independence:-

The main advantage of Java is that it is platform-independent. Java is not depend on any platform, the code written in Java will run on any operating system. This makes Java applications versatile which in turn runs on any platform without doing any modifications. This is a big opportunity or we can say speciality for developers or businesses.


5. Automatic Memory Management (Garbage Collection) :-

Java has a Garbage collector which handles the memory management. This feature of Java identifies &  removes unused objects automatically. This feature of Java helps developers to focus on their code neglecting the memory management. Garbage collection prevents memory leaks, frees up memory space provided to objects. Actually, objects are get stored in the heap memory but after some time few of them are unused so such types of objects has been removed by a garbage collector which free the memory space.


6. Multithreading:-

Java possesses multithreading. Multithreading allows programs to execute multiple tasks concurrently. Multithreading plays a vital role in the applications that handles multiple operations such as handling user input, processing background tasks or managing network connections. Multithreading makes applications efficient. Multithreading executes complex processes using entities that are nothing but the threads. Threads share the same memory of the process. Threads execute the process in a safer way. Using Multithreading we can perform multiple processes in the same program. Available resources have been handled by the multithreading optimally when our computer consists of many CPUs.


7.  Rich Standard Library:-

Java consists of a standard Library that has prebuilt classes, functions, and interfaces. This rich standard library helps to simplify the common programming tasks which are handling input/output operations, data structures and algorithms, and networking. This library helps developers to fasten the development process for building complex applications. Libraries are used in almost all Java programs. Libraries offer ready-to-use solutions and save development time which empowers developers by increasing their  productivity.


8. Use Of Java in Android Applications Developement :-

We use Android Studio as IDE to write code for Android applications, Java is the priority language used in Android Studio. Javas Object-oriented programming features, Android SDK, and libraries make the path of the developers convenient to build robust mobile applications. Java Libraries add value in the development of Android applications.


Conclusion :-

These features of Java are making valuable contributions to the field of software development. If you are a beginner in coding then exploring Java makes your efforts worth building applications. Keep Coding, Happy Coding!


06 September 2023

Stream API in Java- learngreen.net

Stream API in Java

      Java, one of the most popular programming languages, has several characteristics that make it efficient and adaptable. One of these features is the Stream API, a powerful tool for working with data collections and sequences. In this paper, we'll discuss the Java Stream API in detail and explain complex concepts in simple words. You'll understand how streams work and why they're so crucial, whether you're new to Java development or a seasoned pro.

Developers working with Java programs frequently encounter data collections that need to be processed in a variety of ways. The Stream API, a potent tool offered by Java, makes it simple and efficient to manipulate data. With the use of this API, which was made available in Java 8, developers can operate in a functional manner on data, creating code that is shorter, easier to read, and more effective.

We will delve deeply into Java's Stream API in this article. To fully understand the possibilities of this formidable tool, we will go over its core ideas, illustrate real-world applications, and offer code samples.

It's important to understand the idea of a stream before we get into the specifics of the Stream API. A stream is a collection of elements that can be handled sequentially or concurrently in the world of Java programming. Any type of data, such as words, objects, numbers, and more, can be used to create these components. Developers can perform actions on these data elements in a more direct and useful manner by using streams. This higher-level approach to processing data will make your code clearer and easier to comprehend. Streams can be produced by using arrays, collections, or even randomly generated data. You can edit, filter, merge, or otherwise alter the data after generating a stream.



   Syntax of forEach Method:-

   stream.forEach(element -> {
    // Perform an action on 'element'
   });
  

 Explanation:-

stream:- The stream on which you want to perform the forEach operation.

element:- A placeholder representing each element in the stream during iteration.

->:- The lambda operator, which separates the parameter (element) from the lambda body.

{ }:- The lambda body, where you specify the action to be performed on each element.



   import java.util.Arrays;
   import java.util.List;

    public class ForEachExample {
    public static void main(String[] args) {
        List fruits = Arrays.asList("Apple", "Banana", "Cherry");

        // Using forEach to print each fruit
        fruits.forEach(fruit -> {
            System.out.println("Fruit: " + fruit);
           });
       }
      }
      

 



  // Printing the output using traditional for loop, lambda expression and method reference
     import java.util.Arrays;
    import java.util.List;
    public class PrintFruits {
    public static void main(String[] args) {
      List fruits = Arrays.asList("Apple", "Banana", "Cherry");

        // Using a traditional for loop to print each fruit
        System.out.println("Using a traditional for loop:");
        for (String fruit : fruits) {
            System.out.println(fruit);
        }

        // Using a lambda expression to print each fruit
        System.out.println("\nUsing a lambda expression:");
        fruits.forEach(fruit -> System.out.println(fruit));

        // Using a method reference to print each fruit
        System.out.println("\nUsing a method reference:");
        fruits.forEach(System.out::println);
         }
   }
  

 


 package Java;
  import java.util.Arrays;
  import java.util.List;
  import java.util.stream.Stream;

  public class StreamParallel {
  public static void main(String[] args) {
  List fruits = Arrays.asList("Apple","Grapes","Mangoes","Kiwi");	
  //Creating a sequential stream
  Stream sequentialStream = fruits.stream();
  Stream parallelStream = fruits.parallelStream();
  //Let's perform some operations on the streams
  System.out.println("Sequential Stream:");
  sequentialStream.forEach(fruit -> System.out.println("Processing: " +      fruit));

  System.out.println("\nParallel Stream:");
  parallelStream.forEach(fruit -> System.out.println("Processing: " + fruit));
  
	}
   }

 2. Stream from an Array

To create a stream from an array, you can use the Arrays.stream( ) method:-



 String[ ] fruits = {"Apple", "Banana", "Cherry", "Date"};

 Stream streamFromArray = Arrays.stream(fruits);

 3. Stream of Elements

You can also create a stream directly from individual elements using the Stream.of( ) method:-


Stream numbersStream = Stream.of(1, 2, 3, 4, 5);

 

 

 4. Stream from a File

Streams can be created from files using the Files.lines( ) method:-


   Path filePath = Paths.get("data.txt");

   try (Stream lines = Files.lines(filePath, Charset.defaultCharset())) {
    // Process lines from the file
    } catch (IOException e) {
    e.printStackTrace();
    
    }
 

 

These are some common ways to create streams in Java, but there are other methods and sources you can use depending on your specific requirements.

Stream Operations

Once you have a stream, you can manipulate it in a number of different ways. The two categories of stream operations are intermediate operations and terminal operations.

Intermediate Procedures

Operations known as intermediate operations modify or filter the data in a stream to create another stream. Frequently chained together, these activities are not carried out until a terminal operation is called. Typical intermediate operations include the following:-

filter(Predicate<T> predicate)

With the filter operation, you can select stream elements based on a predicate (a boolean function). Only the elements that meet the predicate are included in the new stream that is returned.



   import java.util.Arrays;
  import java.util.List;

  public class Main {

    public static void main(String[] args) {

        List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        List evenNumbers = numbers.stream()
            .filter(n -> n % 2 == 0)
            .collect(Collectors.toList());

        System.out.println(evenNumbers); // prints [2, 4, 6, 8, 10]
        }
    }
    

 

In this example, evenNumbersStream will contain only the even numbers from the original list.

map(Function<T, R> mapper)

The map operation allows you to transform each element in the stream using a given function. It returns a new stream of the transformed elements.



    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Stream;

    public class NameLengthsExample {
    public static void main(String[] args) {
        // Create a list of names
        List names = Arrays.asList("John", "Emma", "Michael");

        // Create a stream of Integer values representing the lengths of names
        Stream nameLengthsStream = names.stream()
                .map(name -> name.length());

        // Print the lengths of names
        nameLengthsStream.forEach(length -> System.out.println("Name Length: " + length));
       }
  }
  

 Here, nameLengthsStream will contain the lengths of the names in the original list.

 distinct( )

   The distinct operation returns a stream containing distinct elements from the original stream, removing duplicates.


   import java.util.Arrays;
   import java.util.List;
   import java.util.stream.Stream;

     public class DistinctNumbersExample {
    public static void main(String[] args) {
        // Create a list of numbers with duplicates
        List numbers = Arrays.asList(1, 2, 2, 3, 3, 3, 4, 4, 4, 4);

        // Create a stream of distinct numbers
        Stream distinctNumbersStream = numbers.stream()
                .distinct();

        // Print the distinct numbers
        distinctNumbersStream.forEach(number -> System.out.println("Distinct Number: " + number));
    }
}
  

The resulting distinctNumbersStream will have unique values from the original list.

Terminal Operations:-
     Operations that have a final outcome or a side consequence are referred to as terminal operations. Data processing through the stream pipeline begins when a terminal operation is performed on a stream. The following are some typical terminal operations:-

forEach(Consumer<T> action)
  The forEach operation allows you to apply an action to each element in the stream. It is often used for performing actions on each element, such as printing or saving to a file.



   import java.util.Arrays;
   import java.util.List;
   public class NamesExample {
    public static void main(String[] args) {
        // Create a list of names
        List names = Arrays.asList("David", "Ella", "Frank");

        // Use a stream to print each name
        names.stream()
                .forEach(System.out::println);
    }
}
 

This code will print each name from the list to the console.

collect(Collectors.toList( ))
The collect operation is used to accumulate elements from a stream into a collection. In this example, we collect the stream elements into a List.


  import java.util.Arrays;
  import java.util.List;
   import java.util.stream.Collectors;

    public class CollectNamesToList {
    public static void main(String[] args) {
        // Create a list of names
        List names = Arrays.asList("David", "Ella", "Frank");

        // Collect names from the stream into a new list
        List collectedNames = names.stream()
                .collect(Collectors.toList());

        // Print the collected names
        System.out.println("Collected Names:");
        collectedNames.forEach(System.out::println);
      }
  }
 

 The collectedNames variable will contain a List of the names from the original stream.

reduce(BinaryOperator<T> accumulator)

The reduce operation combines the elements of a stream into a single result. It takes a binary operator that specifies how the elements should be combined.




    import java.util.Arrays;
   import java.util.List;
   import java.util.Optional;

     public class SumNumbersWithReduce {
    public static void main(String[] args) {
        // Create a list of numbers
        List numbers = Arrays.asList(10, 20, 30, 40, 50);

        // Calculate the sum of numbers using the reduce operation
        Optional sum = numbers.stream()
                .reduce((a, b) -> a + b);

        // Check if the sum is present and print it
        if (sum.isPresent()) {
            System.out.println("Sum of Numbers: " + sum.get());
        } else {
            System.out.println("No elements to sum.");
        }
    }
}
 

 In this example, the sum variable will contain the sum of all numbers in the stream.

Best Practices and Things to Think About

Although the Stream API is a strong tool, there are several recommendations and things to think about before utilizing it:


1. Immutability

Immutability, or the idea that data in a stream won't be changed throughout operations, is encouraged by streams. The desired alterations are instead created in new streams. Writing clear and thread-safe code is much easier with this method.

2. Lazy Evaluation

Because streams employ lazy evaluation, intermediate operations are not carried out until a terminal operation is called. Because just the information that is required is processed, this can result in more effective resource use.

3. Side effects

When using lambda expressions for stream operations, avoid side effects. Lambda expressions must be stateless and should not alter external variables or carry out unrelated tasks.

4. Parallelism

Think twice before using parallel streams. For some activities, parallel processing can increase performance, but it can also add complexity and raise potential thread safety concerns.

5. Error Handling

Always use try-catch blocks or other exception-handling techniques when working with streams from external sources, such as files or network connections.

Conclusion

A strong and flexible tool for working with data collections is Java's Stream API. It enables the expression of data conversions and manipulations in a more functional and declarative manner, resulting in code that is easier to read and maintain. You may utilize the full capability of the Stream API in your Java projects by comprehending the core ideas behind streams, building stream pipelines, and following best practices.

You'll discover that streams make it easier to build code that is both efficient and elegant as you continue to investigate and use them in your programming activities. Streams are a useful addition to your Java toolset for managing big data collections, filtering, manipulating, aggregating results, and more.


05 September 2023

Java I/O & Streams - learngreen.net

 Describe Java I/O:-


The process of reading data from and writing data to external sources like files, consoles, and network connections is referred to as Java I/O, or input/output. I/O operations are essential in Java when doing activities like reading user input, processing data, and saving data to files or databases.


You will frequently work with streams, which are data sequences that flow between your program and external sources when performing I/O operations in Java. Data can be read from or written to a variety of locations using streams as conduits.


Input streams and output streams are the two basic categories of streams in Java. Let's examine each of these categories in more detail:-


Input Streams Consider input streams as the means by which your Java program listens to and collects data from the outside world. These streams can read data from many different places, including files, keyboards, networks, and other places. It resembles your program reading a book, only it receives bytes or characters rather than words. Therefore, input streams assist you in bringing that data into your Java program, whether you're reading input from a file or what someone puts on a keyboard.


Output Streams:- Output streams, on the other hand, are like your program's way of talking back to the world outside. They allow your Java program to send information and messages to external destinations. These destinations can include files, network connections, or other devices that can receive data. Just like with input streams, output streams can work with various data formats. So, whether you're writing text to a file or sending data over the internet, output streams help your program get its message out there.


In a nutshell, input streams are all about getting information into your program, and output streams are all about sending information out from your program. They're like the ears and mouth of your Java application, helping it communicate with the user


Knowledge of the Stream Hierarchy


A hierarchy of classes is used in Java to arrange streams, with the following two basic abstract classes at the top:


These abstract classes, InputStream and OutputStream, serve as the base classes for all input and output streams. They each specify crucial approaches to reading and writing data.


These abstract classes, Reader and Writer, are character data-specific variants of input and output streams. They offer ways to read and write characters, which qualifies them for text-based processes.



  // FileInputStream
  try (FileInputStream fis = new FileInputStream("example.txt")) {
    int byteRead;
    while ((byteRead = fis.read()) != -1) {
        // Process the byte read from the file
    }
 } catch (IOException e) {
    e.printStackTrace( );
 }

 


 // BufferedInputStream
 try (FileInputStream fis = new FileInputStream("example.txt");
     BufferedInputStream bis = new BufferedInputStream(fis)) {
    int byteRead;
    while ((byteRead = bis.read()) != -1) {
        // Process the byte read from the file
      }
  } catch (IOException e) {
    e.printStackTrace();
  } 

 


  // DataInputStream
  try (FileInputStream fis = new FileInputStream("data.dat");
     DataInputStream dis = new DataInputStream(fis)) {
    int intValue = dis.readInt();
    float floatValue = dis.readFloat( );
    // Process the read data
   } catch (IOException e) {
    e.printStackTrace();
    }

 


  // FileOutputStream
   try (FileOutputStream fos = new FileOutputStream("output.txt")) {
    byte[] data = "Hello, Java I/O!".getBytes();
    fos.write(data);
    } catch (IOException e) {
    e.printStackTrace();
     }

 


   //   BufferedOutputStream
  try (FileOutputStream fos = new FileOutputStream("output.txt");
     BufferedOutputStream bos = new BufferedOutputStream(fos)) {
    byte[] data = "Hello, Java I/O!".getBytes( );
    bos.write(data);
      } catch (IOException e) {
    e.printStackTrace( );
   }

 


   //DataOutputStream
  try (FileOutputStream fos = new FileOutputStream("data.dat");
     DataOutputStream dos = new DataOutputStream(fos)) {
    int intValue = 42;
    float floatValue = 3.14f;
    dos.writeInt(intValue);
    dos.writeFloat(floatValue);
   } catch (IOException e) {
    e.printStackTrace();
   }
 

Conclusion

We have succinctly explained the core ideas behind Java I/O and Streams in this essay. We looked at several input and output stream types, saw how to use input streams to read data from external sources, and saw how to use output streams to write data to external destinations. We introduced the try-with-resources statement for resource management and underlined the significance of effective exception handling.

For a variety of programming jobs, from reading and writing files to working with network connectivity, understanding Java I/O and Streams is crucial. It will be possible for you to create more robust and engaging programs as you advance in your Java programming career if you can understand these concepts. Remember that mastering Java I/O and Streams requires practice and experimentation.


27 August 2023

Regular Expression Java - learngreen.net

 

Regular expression Java - learngreen.net

  A string of characters known as a regular expression designates a search pattern. It is an effective tool for pattern-based string manipulation, matching, and searching. For tasks like string validation, text processing, and data extraction, regular expressions are utilized in many different programming languages and technologies.

The java.util.regex package in Java contains two primary classes: Pattern and Matcher, which are used to implement regular expressions.

The Java programming language's Pattern class is used to define and communicate with regular expression patterns. It is a part of the package java.util.regex. It provides methods for compiling, storing, and manipulating regular expressions for a range of string matching and manipulation applications. The Pattern class is examined in greater detail here

Making a Pattern Object:- To start using regular expressions, create a Pattern object using the Pattern.compile( ) function. This method compiles the regular expression into an internal representation that may be used to match input strings efficiently.



  package Java;
  import java.util.regex.Pattern;
  public class Vv {
  public static void main(String[] args) {
	 
  /* Using Pattern.matches() to check if input string matches a pattern */
  /* Pattern:- "Navne.*t"
   * Description: Matches strings that start with "Navne",
   *  have any characters (including none) in between,
   * and end with "t".
   */
  System.out.println(Pattern.matches("Navne.*t", "Navneet")); 
 
  /* Pattern: "Navne\\*t"
   * Description: Matches the string "Navne*t" 
   * literally, where the '*' character is treated 
   * as a literal '*'.
   */
 
  System.out.println(Pattern.matches("Navne\\*t", "Navneet"));
  // Output-> true
  //          false
	 }
   }

 


 package Java;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  public class PCE {
  public static void main(String[] args) {
  // Regular expression pattern to find occurrences of "Java"
  String regex = "\\bJava\\b";
  // Input text
  String text = "Java is a popular programming language. Java is used worldwide.";
  // Compile the regular expression pattern
  Pattern pattern = Pattern.compile(regex);
  // Create a Matcher object using the compiled pattern
  Matcher matcher = pattern.matcher(text);
  // Find and print all occurrences of "Java"
  System.out.println("Occurrences of 'Java':");
  while (matcher.find()) {
  System.out.println("Found at index " + matcher.start());
	 }
        }
   }

 compile(String regex)

It is used to create a pattern from the given regular expression.



  Pattern pattern = Pattern.compile("\\d+");
  

 compile(String regex, int flags)

It is used to create a pattern using the supplied flags and the specified regular expression.

flags( )
It serves to return the match flags for this pattern.



  int flags = pattern.flags( );
  

 matcher(CharSequence input)

It is utilized to build a matcher that will compare the input received with this pattern.



  boolean matches = pattern.matcher("12345").matches( );
  

 matches(String regex, CharSequence input)

It attempts to match the input against the specified regular expression after compiling it.



  boolean matches = pattern.matcher("12345").matches( );
  

 pattern( )

It is used to return the regular expression that was used to create this pattern.



  String regex = pattern.pattern();
  

 quote(String s)

For the given String, it is used to return a literal pattern String.


split(CharSequence input)

It is used to divide the input sequence that is given around instances of this pattern.



  String[] parts = pattern.split("one 2 three 45");
  

 split(CharSequence input, int limit)

It is used to divide the input sequence that is given around instances of this pattern. The limit parameter regulates how frequently the pattern is used.



  String[] parts = pattern.split("one 2 three 45", 2); // Results in ["one ", " three 45"]
  

 toString( )

The string representation of this pattern is returned using it.

Java's Matcher class, which is a component of the java.util.regex package, is used to compare an input string to a regular expression pattern. It offers ways to carry out different matching operations, look for occurrences, and extract matched substrings. Here is a description of the Matcher class's principal methods
By calling the matcher(CharSequence input) method on a Pattern object, you can build a Matcher object. The string you want to compare to the pattern is represented by the CharSequence input.



  Pattern pattern = Pattern.compile("pattern");
  Matcher matcher = pattern.matcher(inputString);
  

 Matching Operations:-

The Matcher class provides several methods to perform matching operations:-

matches( ):- This method checks if the entire input sequence matches the pattern.



  boolean isMatch = matcher.matches();
  

 lookingAt( ):- This method attempts to match the pattern starting at the beginning of the input sequence.


  boolean isMatch = matcher.lookingAt();
  

 find( ):- This method attempts to find the next subsequence in the input sequence that matches the pattern.


  boolean isFound = matcher.find( );
  

 Extracting Matched Substrings:-

The following methods are used to extract matched substrings:-

group( ):- Returns the matched substring from the last successful match.



  String matchedText = matcher.group( );
  

 group(int group):-  Returns the matched substring for the specified capturing group index.



  String groupText = matcher.group(1); // Get matched text for capturing group 1
 

 start( ) and end( ):- These methods return the start and end indices of the last match, respectively


  int startIndex = matcher.start( );
  int endIndex = matcher.end( );
 

 start(int group) and end(int group):- Similar to the previous methods, but they provide indices for a specific capturing group.


 int groupStart = matcher.start(1); // Start index of capturing group 1
 int groupEnd = matcher.end(1); // End index of capturing group 1
 

   In regular expressions, a character class is a way to offer a collection of characters that can all match the same character at a specific point in a string. Using character classes, you can specify a range or a collection of characters that you want to match. They are encapsulated by square brackets [...]. Following is a description of character classes and how they work

Beginner Character Classes

Various Characters The match could be defined as just one character. The character 'a', for instance, will match with [a].

Character Ranges:-  You can specify a range of characters by using a hyphen. For instance, any lowercase letter matches [a-z].

A character class that begins with a caret (') matches any character besides those listed because it is negated. For instance, [0-9] matches every character that is not a digit.

Predefined Character Classes: The regular expression engine in Java supports the following predefined character classes.

\d :matches any digit character(equivalent to [0-9]).

\D: Matches any non-digit character(equal to [0-9]).

(Represented by [a-zA-Z0-9_]) 

\w:  Compatible with all word characters.

\W: Any character that isn't a word can be represented by the character set [a-zA-Z0-9_].

Any whitespace character, such as a space, tab, or newline, is matched by the keyword  \s.

Any character that isn't a blank space that starts with \S matches.

Combining Characters: Within a character class, you can combine characters and character ranges. For instance, any uppercase or lowercase letter matches [A-Za-z].

Escape specific Characters:-  Some characters, such as [ ,   ] ,^ , -,  etc., have specific meanings inside character classes. You must use a backslash ( \ ) to escape these characters if you wish to match them exactly.



26 August 2023

Synchronization in Java - learngreen.net

 

Synchronization In Java

  By enabling many activities to run concurrently, concurrent programming is essential in the realm of software development for performance optimization. The problem of guaranteeing that several threads can access shared resources without introducing data corruption or unexpected behavior, however, arises with concurrency. Synchronization is useful in this situation. A key feature of Java is synchronization, which gives programmers control over how many threads can use the same resources at once while maintaining data integrity and avoiding race events.


Multiple threads may access and alter shared resources concurrently without sufficient synchronization, producing inconsistent or inaccurate results.


The Importance of Synchronization:-

Consider a situation where several threads are attempting to increase a common counter variable. Without synchronization, two threads might concurrently read the value of the counter, independently increment it, and then write back the results. Due to this, the counter might not increase by the anticipated amount, which could result in incorrect computations or unexpected behavior.


Synchronization Mechanisms in Java:-

Synchronized methods and synchronized blocks are the two primary synchronization mechanisms offered by Java.


Methods that can only be accessed by one thread at a time are referred to as synchronized methods. The monitor of an object is locked when a thread enters a synchronized method, preventing other threads from entering any additional synchronized methods on the same object. This guarantees that only one thread at a time can use the synchronized procedure.


Blocks that are synchronized: Blocks that are synchronized provide you with more precise control over synchronization. You can synchronize particular code sections as opposed to the full function. When you want to avoid locking the entire process to improve performance, this is quite helpful.


One thread can only execute the enclosed code block at a time in a critical section created by a synchronized block in Java. When numerous threads are concurrently gaining access to common resources, this is helpful for guaranteeing thread safety. The following is the fundamental grammar for writing a synchronized block



   synchronized (object) {
      // Code that needs to be executed in a synchronized manner
    }

 Synchronized blocks are defined with the term synchronized.


(object): Specify the object to which the synchronization will be applied inside the parenthesis. This item is frequently referred to as the "lock" or "monitor" object. It is employed to organize the synchronization of various threads.


You insert the code that you wish to run in synchronization across processes inside the curly braces. Based on the lock provided by the specified object, only one thread will be allowed to execute this block at once.


Compared to conventional synchronized blocks, locks in Java offer a more flexible and fine-grained method of managing synchronization. The java.util.concurrent.locks package contains locks, which provide more sophisticated functionality and synchronization control. Java offers the ReentrantLock and the ReadWriteLock as its two primary lock types.


ReentrantLock:-  A more potent substitute for synchronized blocks is the ReentrantLock. It offers more advanced synchronization features, supports interruptible and timed lock acquisition, and gives you more control over locking and unlocking. 


One thread may write to a resource at a time but multiple threads may read it simultaneously thanks to the ReadWriteLock synchronization feature. In situations where reads occur more frequently than writes, this might be more effective. The actual ReadWriteLock implementation is called ReentrantReadWriteLock.


The following are the key benefits of utilizing locks, especially the ReentrantLock and ReadWriteLock:-

power over locking and unlocking on a finer scale.

Support for conditions enables threads to wait until particular criteria are satisfied before continuing.

flexibility in the timing and acquisition of interruptible locks.

With ReadWriteLock, read-intensive scenarios perform better.

checking the lock's state, which is helpful for monitoring and troubleshooting.

But increasing responsibility also comes along with this increased authority and adaptability. Lock management may become increasingly difficult, and improper use may result in deadlocks or other synchronization problems. To prevent potential issues while utilizing locks, it's crucial to adhere to standard practices and ensure correct exception handling and cleaning.


Remember that Java also provides other synchronization mechanisms and concurrent data structures like Semaphore, CountDownLatch, CyclicBarrier, and more, each tailored for specific synchronization needs. The choice of synchronization mechanism depends on the specific requirements of your application.


The synchronized keyword in Java can be used to define synchronized methods. Only one thread can operate on a single instance of the class at a time when a method is designated as synchronized. When many threads are concurrently accessing the methods of the same object, this helps to ensure thread safety.



public synchronized void methodName( ) {
    // Synchronized method code
}

 Due to race circumstances and concurrent access concerns, when multiple threads access shared resources or data concurrently without synchronization, it can result in a variety of errors and unexpected behaviors. When the time or order of thread execution affects how anything turns out, a race condition has occurred. The following are some typical problems that can develop without synchronization:


Data corruption can occur when multiple threads read and modify shared data at the same time. For instance, if one thread reads the data while another is modifying it, the results could be inconsistent or incorrect.


Consistent State:- It's possible for threads to interact with shared objects without having adequate synchronization, in which case they might not be aware of any alterations performed by other threads. This may cause things to behave inconsistently or unexpectedly.


Updates made by one thread may be lost if they are overwritten by another before being transferred to memory in the absence of synchronization.


Deadlocks:- When two or more threads are unable to move forward because one is awaiting a resource that the other thread is holding, a deadlock has occurred. When threads acquire locks in a different order, this can occur.


Livelocks:- When two or more threads continuously modify their states in reaction to modifications in the states of the other threads, no progress is made.


Performance Problems:- Thread contention for locks can occasionally result in performance bottlenecks and decreased parallelism.



  class MRBL implements Runnable {
   // Implement the run method required by Runnable interface
    public synchronized void run() {
    for (int i = 1; i <= 3; i++) {
      // Print thread ID and loop index
    System.out.println("Thread " + Thread.currentThread().getId() + " " + i);
          }
      }
     }
    public class SynchronizedThreadExample {
    public static void main(String[] args) {
      // Create an instance of the MRBL class
     MRBL obj = new MRBL( );
    // Create two threads, both sharing the same MRBL instance
        Thread thread1 = new Thread(obj);
        Thread thread2 = new Thread(obj);
   // Start both threads
        thread1.start( );
        thread2.start( );
    try {
    // Wait for both threads to complete
     thread1.join( );
     thread2.join( );
     } catch (InterruptedException e) {
     e.printStackTrace( );
            }
        }
     }
 

 


     class CT {
     public synchronized void debug() { // Synchronized method
        for (int i = 0; i <= 3; i++) {
            System.out.println("CT " + Thread.currentThread().getId() + " " + i);
          }
        }
    }

    class MT extends CT {
    public synchronized void debug() { // Synchronized method
        for (int i = 0; i <= 3; i++) {
            System.out.println("MT " + Thread.currentThread().getId() + " " + i);
          }
      }
  }

    public class SynchronizedThreadDemo {
    public static void main(String[ ] args) {
        MT obj = new MT( );
        MT obj1 = new MT( );

       // Create and start the first thread
        Thread thread1 = new Thread(() -> {
            obj.debug(); // Call the synchronized debug method of MT class for thread1
        });

        // Create and start the second thread
        Thread thread2 = new Thread(() -> {
            obj1.debug(); // Call the synchronized debug method of MT class for thread2
        } );

        // Start both threads
        thread1.start();
        thread2.start();
      }
   }

 

23 August 2023

Enum Keyword In Java - learngreen.net

 

Enum Keyword in Java


   The concept of enumerations plays a big role in programming. It's a way to organize a group of named things in a structured manner. In the programming world, especially in Java, there's a powerful tool called the enum keyword that helps achieve this. This article takes a deep dive into the enum keyword in Java, explaining its benefits, uses, and how it makes code easier to read.


An "enumeration," sometimes just called "enum," is a special kind of data type. It's like a list of named values, also known as "enumerators" or "constants." The main idea behind enumerations is to group related values together. Usually, these values are constants with specific meanings. Using enums to define a set of named constants can make your code easier to understand, and maintain, and less prone to errors.


In Java programming, an enumeration is a bit like a special class. Even though you don't create enums using the usual `new` keyword, they have many of the same features as regular classes. This gives enums a lot of flexibility. Just like with classes, you can give enums special tasks to do.


What makes Java enums unique is their versatility. They aren't just limited to holding named values; they can do much more. Besides being containers for constants, enums can also have behaviors and characteristics that make your code more powerful. They can be more than just labels – they can hold important information and perform actions.


However, there are some important things to remember about enums. Unlike classes, enums can't be expanded by adding more things to them. This means they can't become larger or more important over time. They also can't copy things from other classes. But even with these limitations, enums can still have their own unique abilities.


For example, you can give enums special instructions when they're created. It's like telling them how to get ready for their job. You can also attach specific information to each enumerator by using instance variables. Additionally, you can include methods within enums, allowing them to perform actions. This makes enums more than just placeholders for constants; they become dynamic parts of your code.


Enums can also be used in decision-making. For instance, they work really well with something called "switch" statements. These statements help your program make choices based on different options. Using enums with switch statements makes your code cleaner and more reliable because you're telling the program exactly what to do in each case.


In simple terms, enums in Java are like super organizers. They're great for grouping related things together in a neat way. While they can't become bigger or copy from other classes like regular classes can, they have their own unique talents. They make code easier to read, and they're a perfect match for making decisions in your program. So, next time you're organizing your crayons, think about how enums do something similar for your code!



   


  package Java;
   //Define an enum named "Day" to represent days of the week
   enum Day{
   SUNDAY, MONDAY, TUESDAY,
   WEDNESDAY, THURSDAY, FRIDAY,
   SATURDAY 
   }
  //Main class to illustrate the usage of the enum
   public class EnumIllustration {
  /* Create an instance of the "Day" 
   * enum and assign it the value "WEDNESDAY"	 
   */
   public static void main(String[] args) {
   Day obj = Day.WEDNESDAY;
   /* Print the value of the "obj"
    * variable, which is the day 
    * "WEDNESDAY"
    */
   System.out.println(obj);
	  }
   }
 

 


    package Java;
   /* Define an enum named "complexionsthings"
   * to represent different complexion-related things
   */
    enum complexionsthings{
	 Yellow,
	 Orange,
	 Pink;
    }
  // Main class to illustrate the usage of the enum
    public class Complexion {
    public static void main(String[] args) {
   /* Create an instance of the "ComplexionsThings"
    * enum and assign it the value "Orange"	  
    */
    complexionsthings obj = complexionsthings.Orange;
   /* Print the value of the "obj" variable,
    * which is the complexion-related thing "Orange" 
    */
    System.out.println(obj);
	   }
   }  	
 

 

21 August 2023

Wrapper Class In Java - learngreen.net

 

Wrapper Class

In the realm of Java programming, data comes in different types, like numbers, letters, and true/false values. Sometimes, we want to treat these basic types as if they were fancier objects, giving us extra abilities to work with them. Enter wrapper classes – these are like cool jackets that wrap around simple data, making them look and behave like full-blown objects.


Java programmers frequently work with several forms of data, including numbers, characters, and true/false values. By offering "wrapper classes," Java makes it much more intriguing. These classes provide our fundamental data types a little magic, transforming them into adaptable objects. Let's explore wrapper classes using some straightforward examples.


Wrapper classes act as our companions, helping us transform our fundamental data types (such as int, char, boolean, etc.) into elegantly attired objects. They enable us to employ these basic types as though they were superhumans wearing capes who could perform additional feats.


Because they are object-oriented, generic classes do not support primitives. Wrapper classes are therefore necessary because they transform primitive data types into objects, and objects are essential if we need to modify the inputs supplied into a method. Now let's examine the Wrapper Classes in more detail.


The java.lang package, which is part of the Java programming language, contains classes that are crucial to the design, the most important of which being Object and Class.


The values of primitive data types are therefore wrapped in or represented by Java wrapper classes, which are objects. A field that can contain primitive data types is included when a wrapper class object is constructed.


A Double type object, for example, contains only fields of the Double type, representing that value such that a reference to it can be retained in a variable of reference type. An object of one type contains only fields of that type.


Need Of Wrapper Classes:-
Imagine you have a magical toolbox filled with amazing tools, but there's a rule  you can only use objects, not plain numbers or letters. But wait, most of our data is just plain numbers and letters, right? That's where wrapper classes swoop in. They turn your regular numbers, letters, and such into objects, so you can use them with all those magical tools in your toolbox.


The user frequently needs to work with objects in Collections, Synchronization, Serialization, and other areas even though Java is an object-oriented programming language. Let's look at a few situations where wrapper classes are necessary.
To conduct the serialization, we must first transform the objects into streams. The wrapper classes can be used to turn a primitive number into an object.


Java is limited to calling methods with arguments. Because of this, the original value is unaffected if a primitive value is passed. The original value is altered when a primitive value is turned into an object, though.
Java uses multi-threaded classes for synchronization.
Java's collection framework only functions with objects. 
All of the classes in the collection framework are object-oriented, including Vector, HashSet, LinkedHashSet, PriorityQueue, ArrayList, TreeSet, LinkedList, and ArrayDeque.


There are helpful classes for interacting with objects in the java.util package.


Autoboxing :-
It is the operation that convert primitive data type into objects with the proper wrapper classes. It transforms primitive type byte to Byte,
boolean to Boolean char to Character, double to Double, float to Float, long to Long and short to Short. The difference between primitive and wrapper types lies in their naming conventions. Primitive types are denoted with lowercase letters and often have short forms, whereas wrapper classes use their full names with the initial letter capitalized.


Unboxing:-
The process of instantly converting a wrapper type into its primitive type counterpart is known as unboxing. It's autoboxing done backward. Since Java 5, we are no longer required to convert wrapper types to primitives using the intValue() method of the wrapper classes. For instance, double to double, integer to int, and so forth.


The Java compiler uses unpacking when an object of a wrapper class is used as a parameter to a function that expects a value of the corresponding primitive type or when it is assigned to a variable of the corresponding primitive type.


Wrapper Class Methods:-


typeValue( ) – Converts a specific Number object's value to the returned primitive data type.


compareTo( ) compares the argument with the Number object.


equals( ) verifies that the Number object matches the supplied argument.


Returns an Integer object with the value of the provided primitive data type for valueOf( ).


Returns String object with the value of the supplied Integer type parameter using the
 toString( ) method.


parseInt( ) returns a value of the specified String representation as an Integer type.


The function decode( ) converts a String into an integer.


When comparing two inputs, min() delivers the lower number.


When comparing two inputs, max( ) returns the larger number.


round( ) - Depending on the method return type, returns the closest round off of an int or long value.




 //Integer Wrapper Illustration
 package Java;
 public class WrapperIllustration {
 public static void main(String[] args) {
 // Wrapping an int into an Integer	 
 Integer Number = new Integer(85);
 //Unwrapping: Converting Integer back to int
 int uwNumber = Number.intValue();
 System.out.println(Number);
 System.out.println(uwNumber);
 // Output-> 85
 //          85
	}
 }

 


 //Character Wrapper Illustration
  package Java;
  public class CharacterWrapperIllustration {
  public static void main(String[] args) {
  // Wrapping a char into a Character
  Character Letter = new Character('X');
  //Unwrapping: Converting Character back to char
  char uwLetter = Letter.charValue();
  System.out.println(Letter);
  System.out.println(uwLetter);
  // Output-> X
  //          X        
	}
  }

 


    //Boolean Wrapper Illustration
   package Java;
   public class BooleanWrapperIllustration {
   public static void main(String[] args) {
   // Wrapping a boolean into a Boolean	 
   Boolean Flag = new Boolean(true);
   // Unwrapping: Converting Boolean back to boolean
   boolean uwFlag = Flag.booleanValue();
   System.out.println(Flag);
   System.out.println(uwFlag);
   //Output-> true
   //         true
	  }
   }

 


   package Java;
   public class WrapperMethod {
   public static void main(String[] args) {
   String str = "852";
   //Converts string to Integer
   Integer ParsedInt = Integer.parseInt(str);
   //Print the parsed Integer value
   System.out.println(ParsedInt);
   //Output-> 852
	  }
   }

 


 // Autoboxing & Unboxing Illustration
  package Java;
  public class AxUx {
  public static void main(String[] args) {
  // Autoboxing: int to Integer
  Integer boxedInt = 35;
  // Unboxing: Integer to int
  int unboxedInt = boxedInt;
  System.out.println(boxedInt);
  System.out.println(unboxedInt);
	 }
  }

 


   //Comparison using Wrapper Method
    package Java;
    public class CNW {
    public static void main(String[] args) {
    Integer num1 = 8;
    Integer num2 = 28;
   //Compare two Integer objects
    int result = num1.compareTo(num2);
    System.out.println(result);
	}
  }
  

 


  //Handling Null Values
    package Java;
    public class WN {
    public static void main(String[] args) {
    // Declare an Integer variable and assign it a null value	 
   Integer missingNum = null;
   //Check if the missingNum variable is null
   if (missingNum == null) {
   /* If the variable is null, print a message
    * indicating the number is missing 
    */
	 System.out.println("Number is missing");
         }
      }
   }
  

The benefits of  Wrapper classes:-

Object-Oriented Capabilities:-

You can treat primitive data types as objects by utilizing wrapper classes. This entails that you can use inheritance, call methods on them, and other object-oriented characteristics.

Interoperability:-

Some Java libraries and APIs require objects rather than primitives. Wrapper classes, which enable the use of primitives as objects in such situations, aid in bridging this gap.


Handling Null Values:-

Primitive data types cannot represent null values; however, wrapper classes can. When you need to express the lack of a value, this is extremely helpful.


Closure:-

In Java, the primitive data type is contained within the class object via wrapper classes.Wrapper classes for Java are contained in the java.lang module. The Java Collection Framework's data structures, like ArrayList, only store objects; they do not store primitive types. The processes of autoboxing and unpacking convert simple data types into objects and back again. Instances of wrapper classes can be useful in a number of situations, such as synchronization, serialization, collections, and so forth. The primitive data type int does not allow us to assign an instance of the Integer class to null.


18 August 2023

Packages in Java - learngreen.net

 

Packages In Java

  Effective organization is one of the important criteria for building reliable and maintainable Java code. Maintaining a clean and structured codebase is crucial as Java projects get bigger and more complicated. The idea of packing comes into play in this situation. A key component of Java is the concept of packages, which enable programmers to group their code into logical parts for better project management, comprehension, and collaboration.

A package in Java allows you to put similar classes, interfaces, enumerations, and other kinds under a single namespace. The main goals of using packages are to avoid naming conflicts and provide the codebase a hierarchical structure. Essentially, a package is a directory that includes Java source files and, possibly, sub packages.

Let's take the case of developing a software program that has elements for user authentication and database interactions as an example. You can build two packages, com.example.authentication and com.example.database, in place of having all the classes in a single directory. This makes the codebase more modular and intelligible by providing a clear separation of concerns in addition to helping to prevent naming conflicts.

Advantages of Packages:-

Modularity:- Packages promote modular programming. Different parts of an application can be contained into distinct packages, which enables developers to concentrate on a single aspect of the system without becoming overburdened by the codebase as a whole.

Namespace management:- Packages offer a means of class organization and naming conflict avoidance. Even when libraries from multiple sources are utilized, the possibility of class name conflicts is decreased since classes inside a package are accessed using the package name as a prefix.

The readability and maintainability of the code are improved by the organization. The design of the program is clearly reflected in packages, which makes it simpler for developers to find and interact with particular classes.

Access Control:- To limit the visibility of classes, methods, and fields, Java offers access modifiers like public, protected, and private. Additionally, packages include a built-in default access modifier that enables classes to access each other's package-private members, which is helpful for ensuring encapsulation.

Packages assist in allocating tasks to team members in collaborative projects. Separate packages allow different developers to work on them independently of one another's code. Additionally, by separating them, version control systems are less likely to experience merge conflicts.

Using and Creating Packages

The procedure of creating and using packages in Java is simple:-

Package Declaration:- The package is declared using the package keyword at the start of each Java source file. A class's affiliation with the com. example.authentication package, for instance, is indicated by the package name package com.example.authentication;.

Directory Structure:- Your source files' directory structure needs to correspond to the package structure. The directory structure for the package com.example.authentication would be com/example/authentication.

Accessing Classes:- You must import a class using the import statement in order to use it from another package. For instance, you can utilize the DatabaseConnection class from the com. example.database package by importing com.example.database.DatabaseConnection;.

Typical Package Naming Practices

To keep your codebase clear and consistent, you must use consistent naming standards for packages. Here are some typical behaviors:-

Use the Reverse Domain Name:- To ensure uniqueness, start with the domain name of your company. If your domain is example.com, for instance, your root package might be called com. example.

Descriptive and lowercase:- To distinguish package names from class names, they are typically written in lowercase. Use names that are evocative of the package's function.

Avoid single-word names since they may cause naming conflicts with other libraries or Java core classes. To prevent such problems, use a prefix that is related to your project.



  package Library;
  // Create a class named Book in the library package
  public class Book {
  public static void main(String[] args) {
	 // Class implementation here
	}
  }

 


  package Test;
  import Library.Book;
  /* Create another class named
  * LibraryTester in the Test package
  */
  public class LibraryTester {
  public static void main(String[] args) {
	 Book obj = new Book();
  // Test book-related functionality	 

	}
  }

 


 package Library.catalog;
 /* Create a class named CatalogItem
  * in the library.catalog sub package
  */
 public class CatalogItem {
 public static void main(String[] args) {
 // Class implementation here
	}
 }

 


  package Test;
  /* Use the CatalogItem class
  * in a class within the test package
  */
  import Library.catalog.CatalogItem;
  public class CatalogTester {
  public static void main(String[] args) {
  CatalogItem obj = new CatalogItem();
  // Test catalog-related functionality
	 }
  }

 


 package Access;
 /* Create a class named Parent
  * in the access package
  */
 public class Parent {
 public int publicField;
 protected int protectedField;
 int defaultField;
 private int privateField;
 // Class implementation here
}

 


  package Access;
  /* Create a subclass named
   * Child in the same access package
   */
  public class Child extends Parent {
  public void childMethod() {
  publicField = 10; // Accessible
  protectedField = 20; // Accessible (due to subclass)
  defaultField = 30; // Accessible (same package)
  // privateField = 40;    
  // Not accessible (private)	 
      }
   }

 In Java programming, packages are a crucial organizing tool that you may use to organize your code and control access between classes. You can develop well-structured, modular, understandable codebases that are simpler to maintain and collaborate on by establishing packages and sub packages. Additionally, you may efficiently regulate visibility and encapsulation by comprehending access modifiers in packages.