Extremely Serious

Author: ron (Page 11 of 34)

Understanding Subject-Verb Agreement in English Grammar

When it comes to constructing clear and grammatically correct sentences in the English language, one of the fundamental principles to master is subject-verb agreement. This rule ensures that the verb in a sentence agrees with the subject in terms of both number and person. Let's delve deeper into this essential aspect of English grammar.

What Is Subject-Verb Agreement?

Subject-verb agreement is the grammatical principle that dictates that the verb in a sentence should correspond to the number and person of the subject. In simpler terms, if your subject is singular, the verb should be singular, and if the subject is plural, the verb should be plural.

Number Agreement

  • Singular Subjects: Singular verbs are used when the subject refers to one person, thing, or concept. For example:
    • She sings beautifully.
    • The cat is sleeping.
  • Plural Subjects: Plural verbs are used when the subject refers to more than one person, thing, or concept. For example:
    • They sing together.
    • The dogs are barking loudly.

Person Agreement

The verb also needs to agree with the person of the subject. There are three main persons in English:

  • First Person: Refers to the speaker or speakers (I/we).
  • Second Person: Refers to the person or people being spoken to (you).
  • Third Person: Refers to someone or something not involved in the conversation (he/she/it/they).

Examples of Person Agreement:

  • I am writing an article. (First person)
  • You are studying diligently. (Second person)
  • She is a talented artist. (Third person - singular)
  • They are skilled musicians. (Third person - plural)

Why Is Subject-Verb Agreement Important?

Subject-verb agreement is crucial for maintaining sentence clarity and grammatical correctness. When subjects and verbs do not agree, sentences can become confusing and grammatically incorrect, which may lead to misunderstandings.

Common Pitfalls

Some common pitfalls to watch out for include:

  • Errors with collective nouns (e.g., "The team is playing well" rather than "The team are playing well").
  • Subject-verb agreement in complex sentences where the subject and verb might be separated by intervening phrases.
  • Compound subjects (e.g., "Peanut butter and jelly is my favorite sandwich" because the compound subject "peanut butter and jelly" is singular).

Conclusion

Mastering subject-verb agreement is a fundamental step towards improving your English language skills. By ensuring that your verbs agree with your subjects in terms of number and person, you'll create sentences that are both clear and grammatically correct. So, whether you're writing an article, sending an email, or having a conversation, subject-verb agreement will always be an essential tool in your language arsenal.

Understanding the The Types of English Sentences

English, like many languages, employs various sentence types to convey information and emotions. These sentence types can be categorized into four main groups: declarative, interrogative, imperative, and exclamatory sentences. In addition to these basic forms, there are also complex and compound sentences that provide more variety and depth to our communication.

Main Groups

Declarative Sentences

Declarative sentences are perhaps the most common form of sentence in English. They are used to make statements, express facts, or convey opinions. When you want to share information or your point of view, you use declarative sentences. For example:

  1. "The sun is shining."
  2. "My favorite color is blue."
  3. "She enjoys reading books in her free time."
  4. "This movie is much better than the one we saw last week."
  5. "The conference starts at 9 AM tomorrow."

Interrogative Sentences

Interrogative sentences are designed for asking questions. They are structured in a way that prompts a response, either in the form of an answer or additional information. Questions often begin with words like "who," "what," "when," "where," "why," or "how." For instance:

  1. "Have you finished your homework?"
  2. "What time does the bus arrive?"
  3. "Are they coming to the party tonight?"
  4. "How did you learn to play the guitar?"
  5. "Is it going to rain tomorrow?"

Imperative Sentences

Imperative sentences are all about giving commands or making requests. When you want someone to do something, or you need to convey a strong directive, you use imperative sentences. For instance:

  1. "Close the door behind you."
  2. "Please pass the salt."
  3. "Turn off the lights before leaving."
  4. "Be quiet during the exam."
  5. "Don't forget to feed the dog."

Exclamatory Sentences

Exclamatory sentences express strong emotions or exclamations. They often begin with words like "what" or "how" and are used to convey surprise, excitement, or intense feelings. For example:

  1. "What a beautiful sunset!"
  2. "I can't believe I won!"
  3. "That was an incredible performance!"
  4. "Wow, that's amazing!"
  5. "How wonderful this place is!"

Complex and Compound Sentences

In addition to the four primary sentence types, English also employs complex and compound sentences to add depth and variety to communication.

Complex Sentences

Complex Sentences consist of an independent clause, which is a complete thought, and one or more dependent clauses, which are incomplete thoughts. These clauses are linked to create more intricate sentence structures. For instance:

  1. "Although it was raining (dependent clause), I went for a walk (independent clause)."
  2. "Because she studied hard (dependent clause), she aced the test (independent clause)."
  3. "Since I had some free time (dependent clause), I decided to read a book (independent clause)."
  4. "While I was cooking dinner (dependent clause), the phone rang (independent clause)."
  5. "After the concert (dependent clause), we went out for pizza (independent clause)."

Compound Sentences

Compound Sentences contain two or more independent clauses joined together by a semicolon or a comma along with a coordinating conjunction, such as "and," "but," or "or." The choice between a semicolon and a comma with a coordinating conjunction depends on the level of separation you want between the two clauses. For example:

  1. "I wanted to stay home; my friends convinced me to go to the party."
  2. "She loves to travel, so she plans to visit Europe next summer."
  3. "He wanted to go to the movie, and she preferred to stay home and watch TV."
  4. "I like both chocolate and vanilla ice cream, but I chose chocolate."
  5. "The weather was perfect, and we had a great day at the beach."

In a compound sentence, it's common to use a semicolon or a coordinating conjunction (such as "and," "but," "or," etc.) to join two independent clauses. The choice between a semicolon and a comma with a coordinating conjunction depends on the specific context and the level of separation you want between the two clauses.

Here's how it works:

Semicolon: You can use a semicolon to join two closely related independent clauses. This choice indicates a stronger connection between the two ideas than using a comma with a coordinating conjunction. For example: "I wanted to stay home; my friends convinced me to go to the party."

Comma with a Coordinating Conjunction: If you want a slightly less strong connection or you feel the clauses are more distinct but still related, you can use a comma along with a coordinating conjunction. For example: "I wanted to stay home, but my friends convinced me to go to the party."

In summary, English sentences come in various forms, each serving a unique purpose in communication. Declarative sentences share information and opinions, interrogative sentences seek answers, imperative sentences issue commands or requests, and exclamatory sentences convey strong emotions. Complex and compound sentences provide the tools for crafting more intricate and nuanced expressions. Understanding these different sentence types, along with the choice of punctuation in compound sentences, is crucial for effective and engaging communication in the English language.

Understanding the Tenses in English Grammar

English grammar is a complex system with a variety of tenses that allow us to express different times and aspects of actions. There are 12 main tenses in English, each serving a specific purpose. Let's explore these tenses with five examples for each to gain a better understanding of when and how to use them.

Simple Present

The simple present tense is used for actions that are habitual, factual, or general truths.

Examples

  • She reads books every evening.
  • The sun rises in the east.
  • Cats chase mice.
  • I work at a company.
  • They like to swim.

Present Continuous

The present continuous tense indicates actions happening right now or in the near future.

Examples

  • I am studying for my exams right now.
  • He is playing the piano at the moment.
  • They are watching a movie tonight.
  • She is cooking dinner.
  • We are driving to the beach tomorrow.

Simple Past

The simple past tense is used for actions that occurred in the past and are completed.

Examples

  • I visited London last summer.
  • She finished her homework yesterday.
  • They played soccer on Saturday.
  • He graduated from college in 2020.
  • We traveled to Paris two years ago.

Past Continuous

The past continuous tense emphasizes actions that were ongoing in the past.

Examples

  • It was raining when I left the house.
  • They were studying all night.
  • She was reading a book when the phone rang.
  • I was sleeping when you called.
  • We were having dinner at 7 pm.

Future Simple

The future simple tense describes actions that will happen in the future.

Examples

  • I will call you later.
  • She will visit her grandmother tomorrow.
  • They will buy a new car next year.
  • He will finish the project by Friday.
  • We will travel to Japan in the summer.

Future Continuous

The future continuous tense is used for actions that will be ongoing in the future.

Examples

  • At 8 pm, I will be watching a movie.
  • She will be working on her thesis all day.
  • They will be celebrating their anniversary tonight.
  • He will be driving to the airport at 9 am.
  • We will be hiking in the mountains this weekend.

Present Perfect

The present perfect tense expresses actions that happened at an unspecified time in the past or are connected to the present.

Examples

  • I have seen that movie before.
  • They have just moved to a new city.
  • She has already eaten lunch.
  • He has visited five different countries.
  • We have never tried sushi.

Past Perfect

The past perfect tense shows that one event in the past happened before another past event.

Examples

  • By the time I arrived, they had already left.
  • She had finished her work before the meeting.
  • They had graduated before I started college.
  • He realized he had forgotten his keys at home.
  • We had never been to that restaurant.

Future Perfect

The future perfect tense indicates that an action will be completed before a specific point in the future.

Examples

  • By the time you arrive, I will have completed my work.
  • She will have read the entire book by the end of the week.
  • They will have saved enough money for their dream vacation.
  • He will have graduated by the time the ceremony takes place.
  • We will have finished the renovations in two months.

Present Perfect Continuous

The present perfect continuous tense emphasizes the duration of an action that started in the past and continues into the present.

Examples

  • I have been learning Spanish for three months.
  • She has been practicing the piano all afternoon.
  • They have been working on the project for a while.
  • He has been living in New York since 2019.
  • We have been waiting for the bus for 20 minutes.

Past Perfect Continuous

The past perfect continuous tense is similar to the past perfect but emphasizes the duration of an action that happened before another past event.

Examples

  • By 5 pm, I had been studying for five hours.
  • She had been working overtime for several weeks.
  • They had been traveling for six months before returning home.
  • He had been fixing the car all morning.
  • We had been painting the house for days.

Future Perfect Continuous

The future perfect continuous tense shows that an action will continue up to a specific point in the future.

Examples

  • By the time you arrive, I will have been waiting for an hour.
  • She will have been practicing the guitar for three hours by 7 pm.
  • They will have been running the marathon for four hours when they finish.
  • He will have been working at the company for ten years by his retirement.
  • We will have been gardening all morning by the time you visit.

Understanding these 12 tenses is crucial for effective communication in English, as they help convey the timing and duration of actions with precision. Mastering these tenses will significantly improve your ability to express yourself in both spoken and written English.

Go Basic Dependency Management

Go, often referred to as Golang, is a statically typed, compiled language known for its simplicity and efficiency. When developing projects in Go, you often need to work with external packages or libraries to streamline your development process. Go Modules is the official dependency management solution introduced by the Go team to make this task easier and more organized. In this article, we'll explore how to manage dependencies with Go Modules, control their versions, specify the required Go version, list dependencies, and remove unwanted dependencies.

1. Initializing a Go Module

The first step in managing dependencies with Go Modules is to initialize a new module for your project. Open your terminal and navigate to your project directory, then run the following command:

go mod init <module-name>

Replace <module-name> with the name of your module or project. This command creates a go.mod file in your project's root directory. This file will keep track of your project's dependencies, their versions, and the required Go version.

2. Managing the Go Version

In addition to managing dependencies, you can specify the Go version your project requires in the go.mod file. This ensures that your project is built and executed using the correct version of Go. To specify the Go version, add a go directive to your go.mod file like this:

plaintextCopy codemodule <module-name>

go <go-version>

Replace <go-version> with the specific version of Go your project requires, such as 1.17.

3. Adding Dependencies

To add dependencies to your Go project, you can use the go get command. For example, to add the github.com/example/package package, run:

go get github.com/example/package

Go Modules will fetch the specified package and add it to your go.mod file, including its version information. By default, Go Modules will use the latest version of the package.

4. Controlling Dependency Versions

Go Modules provides powerful version control for dependencies. You can specify the version of a package in your go.mod file. Here's how to do it:

go get github.com/example/package@vX.Y.Z

Replace vX.Y.Z with the specific version you want to use. For example:

go get github.com/example/package@v1.2.3

This pins the dependency to version 1.2.3.

5. Importing Packages

Once you've added dependencies, you can import their packages into your Go code. Import them as you normally would:

import "github.com/example/package"

Go Modules will automatically manage the version of the package based on your go.mod file.

6. Downloading Dependencies

To download all the dependencies specified in your go.mod file, use the following command:

go mod download

This command fetches all the dependencies and stores them in the Go Modules cache.

7. Updating Dependencies

To update a specific dependency to its latest version, you can use the go get command with the -u flag:

go get -u github.com/example/package

The -u flag stands for "update" and will fetch the latest version of the package.

8. Listing Dependencies

To list all the dependencies used in your project and their versions, you can run:

go list -m all

This command provides a detailed list of your project's dependencies, including their module paths and versions.

9. Removing Dependencies

If you need to remove a dependency, you can use the go get command with the -u flag and specify the package path with an @none version. For example:

go get -u github.com/example/unwanted@none

This will effectively remove the github.com/example/unwanted package from your project.

10. The Vendor Directory (Optional)

If you want to have a local copy of your dependencies in your project directory, you can use the go mod vendor command:

go mod vendor

This creates a vendor directory containing your project's dependencies. This can be useful for offline development or to lock your project to specific dependency versions.

11. Versioning and go.mod

Your go.mod file automatically tracks the versions of your dependencies, specifies the required Go version, and includes any updates or removals you make. You can review and manually edit this file if needed, but Go Modules will typically handle versioning, Go version management, and dependency maintenance for you.

12. Building and Running

With your dependencies and Go version managed by Go Modules, you can build and run your Go application as you normally would. Go Modules ensures that the correct dependencies are used, making it easy to share your project with others.

In conclusion, Go Modules simplifies the process of managing dependencies in Go projects while offering robust version control capabilities. By following the steps outlined in this article, you can efficiently manage dependencies, control their versions, specify the required Go version, list dependencies, remove unwanted dependencies, and maintain a well-organized Go project.

Happy coding with Golang and Go Modules!

DRY Principle

Introduction

In the realm of software development, writing maintainable, efficient, and scalable code is of utmost importance. One of the fundamental principles that guide developers in achieving these goals is the DRY principle, which stands for "Don't Repeat Yourself." This principle emphasizes the significance of avoiding code duplication and promoting code reusability, leading to cleaner, more manageable, and more robust software systems.

Understanding the DRY Principle

The DRY principle can be summed up in a single phrase: Every piece of knowledge or logic in a software system should have a single, unambiguous representation within that system. In other words, duplicating code, data, or logic should be avoided whenever possible. This includes similar code with slight variations. By adhering to the DRY principle, developers can enhance the maintainability and overall quality of their codebase.

Benefits of the DRY Principle

  1. Code Maintenance: Duplicated code creates a maintenance nightmare. When a bug needs fixing or a feature requires updating, developers must remember to apply changes consistently across all instances of the duplicated code. This not only increases the likelihood of introducing errors but also consumes valuable time and effort. Adhering to the DRY principle ensures that changes need only be made in a single location, simplifying maintenance tasks.
  2. Consistency: Reusing code promotes consistency throughout a project. If a particular piece of functionality is implemented in one place, it can be reused throughout the application, guaranteeing a uniform user experience and reducing the chances of discrepancies.
  3. Reduced Development Time: Writing code from scratch for each occurrence of a particular logic or functionality is time-consuming. The DRY principle encourages developers to create reusable components and functions that can be leveraged across the codebase, ultimately accelerating development cycles.
  4. Bug Reduction: Duplication often leads to bugs. If a bug is discovered and fixed in one instance of duplicated code, other instances may remain unaffected, potentially causing unexpected behavior. By centralizing logic, the DRY principle helps in reducing the number of bugs and making it easier to identify and address issues.

Applying the DRY Principle

  1. Modularization: Divide your code into small, modular components that encapsulate specific functionalities. These components can then be reused across different parts of the application.
  2. Functions and Methods: Instead of repeating the same code in multiple places, encapsulate it within functions or methods. This not only promotes reusability but also enhances readability and maintainability.
  3. Data Abstraction: Abstract data structures and variables that are used in multiple places. By centralizing data definitions, you can ensure consistency and simplify future modifications.
  4. Template Engines and Inheritance: In web development, template engines and inheritance mechanisms allow you to create reusable layouts and components for consistent UI rendering.
  5. Version Control and Package Management: Leverage version control systems (e.g., Git) and package management tools (e.g., npm, pip) to manage and share reusable code across projects.

Conclusion

The DRY principle is a cornerstone of software development, advocating for efficient and maintainable code by avoiding redundancy and promoting reusability. By adhering to this principle, developers can create cleaner, more reliable software systems that are easier to maintain, enhance, and scale. As software projects become increasingly intricate, the DRY principle remains a guiding beacon, helping developers navigate the complexities of code while striving for excellence.

SOLID Principles

Introduction

In the ever-evolving world of software development, creating maintainable and scalable code is crucial. The SOLID principles offer a set of guidelines to achieve just that. First introduced by Robert C. Martin, these five principles provide a foundation for writing clean, flexible, and efficient code. In this article, we will delve into each SOLID principle, understand its significance, and explore how they contribute to building robust and maintainable software.

Single Responsibility Principle (SRP)

The Single Responsibility Principle advocates that a class should have only one reason to change. In other words, it should have a single responsibility and encapsulate a single functionality. By adhering to SRP, we can avoid coupling and improve maintainability. This principle encourages us to decompose complex functionalities into smaller, independent classes, making our code easier to understand, test, and modify.

Example

// Bad example: A class with multiple responsibilities
class Order {
    public void calculateTotalPrice() {
        // Calculation logic here
    }

    public void saveToDatabase() {
        // Database insertion logic here
    }

    public void sendConfirmationEmail() {
        // Email sending logic here
    }
}

// Good example: Separating responsibilities into different classes
class OrderCalculator {
    public void calculateTotalPrice() {
        // Calculation logic here
    }
}

class OrderRepository {
    public void saveToDatabase() {
        // Database insertion logic here
    }
}

class EmailService {
    public void sendConfirmationEmail() {
        // Email sending logic here
    }
}

Open/Closed Principle (OCP)

The Open/Closed Principle suggests that software entities (classes, modules, functions) should be open for extension but closed for modification. This means that we should design our code in a way that new functionalities can be added without altering existing code. This promotes code reuse and allows us to adapt to changing requirements without affecting the stability of the existing system.

// Bad example: A class that needs to be modified to add new shapes
class Shape {
    public void draw() {
        // Drawing logic for the shape
    }
}

// Good example: Using an abstract class or interface to support new shapes
interface Shape {
    void draw();
}

class Circle implements Shape {
    public void draw() {
        // Drawing logic for a circle
    }
}

class Rectangle implements Shape {
    public void draw() {
        // Drawing logic for a rectangle
    }
}

The Factory Pattern is a design pattern that aligns well with the Open/Closed Principle (OCP) by allowing you to create new objects without modifying existing code.

Liskov Substitution Principle (LSP)

The Liskov Substitution Principle emphasizes that objects of a superclass should be replaceable with objects of its subclasses without altering the correctness of the program. In simpler terms, derived classes should adhere to the contract established by their base class. This principle ensures that polymorphism works as expected, promoting code flexibility and reliability.

// Bad example: Square is a subclass of Rectangle but violates LSP
class Rectangle {
    protected int width;
    protected int height;

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getArea() {
        return width * height;
    }
}

class Square extends Rectangle {
    @Override
    public void setWidth(int width) {
        super.setWidth(width);
        super.setHeight(width);
    }

    @Override
    public void setHeight(int height) {
        super.setWidth(height);
        super.setHeight(height);
    }
}

// Good example: Avoiding LSP violation by not using inheritance
class Shape {
    public int getArea() {
        return 0;
    }
}

class Rectangle extends Shape {
    protected int width;
    protected int height;

    // constructor, getters, and setters
}

class Square extends Shape {
    protected int side;

    // constructor, getters, and setters
}

Interface Segregation Principle (ISP)

The Interface Segregation Principle suggests that a class should not be forced to implement interfaces it does not use. Instead of having a single large interface, we should create multiple smaller interfaces, each representing a specific set of related methods. This allows clients to depend on the minimal set of methods they require, reducing the risk of coupling and providing a more coherent system.

// Bad example: A large interface containing unrelated methods
interface Worker {
    void work();

    void eat();

    void sleep();
}

// Good example: Splitting the interface into smaller, cohesive ones
interface Workable {
    void work();
}

interface Eatable {
    void eat();
}

interface Sleepable {
    void sleep();
}

class Robot implements Workable {
    public void work() {
        // Robot working logic
    }
}

class Human implements Workable, Eatable, Sleepable {
    public void work() {
        // Human working logic
    }

    public void eat() {
        // Human eating logic
    }

    public void sleep() {
        // Human sleeping logic
    }
}

Dependency Inversion Principle (DIP)

The Dependency Inversion Principle focuses on decoupling high-level modules from low-level modules by introducing abstractions and relying on these abstractions. High-level modules should not depend on low-level modules directly; instead, they should depend on interfaces or abstract classes. This promotes flexibility, ease of testing, and modularity, as changes in low-level modules won't affect the higher-level ones.

// Bad example: High-level module depends on low-level module directly
class OrderService {
    private DatabaseRepository repository;

    public OrderService() {
        this.repository = new DatabaseRepository();
    }

    // OrderService logic using DatabaseRepository
}

// Good example: Using abstractions to invert the dependency
interface Repository {
    void saveData();
}

class DatabaseRepository implements Repository {
    public void saveData() {
        // Database saving logic
    }
}

class OrderService {
    private Repository repository;

    public OrderService(Repository repository) {
        this.repository = repository;
    }

    // OrderService logic using Repository
}

High-Level Module

A high-level module is a component or module that deals with broader, more abstract, and higher-level functionality of a software system. It often represents a larger part of the application and is responsible for orchestrating the interactions between various low-level modules. High-level modules tend to focus on business logic, overall system behavior, and user interactions.

Low-Level Module

A low-level module is a more specialized and granular component that handles specific, detailed, and focused functionality within a software system. These modules are typically closer to the underlying hardware or foundational operations of the system. They encapsulate specific operations or algorithms and are designed to perform a specific task or handle a specific aspect of the application.

Conclusion

The SOLID principles serve as a compass to guide software developers towards writing cleaner, more maintainable, and robust code. By adhering to these principles, developers can create flexible and scalable software systems that are easier to understand, modify, and extend. Embracing SOLID principles fosters good coding practices, promotes teamwork, and contributes to the long-term success of software projects. As you embark on your software development journey, keep these principles in mind, and witness the positive impact they bring to your projects. Happy coding!

Java Cleaner

Java Cleaner is a new feature introduced in Java 9 that allows you to define cleanup actions for groups of objects. Cleaners are implemented with the Cleanable interface, which descends from Runnable. Each Cleanable represents an object and a cleaning action registered in a Cleaner. Each Cleanable runs in a dedicated thread. All exceptions thrown by the cleaning action are ignored.

Java 18, marked the finalize method for removal. It is better to avoid the usage of finalize method.

The most efficient use of Cleaner is to explicitly invoke the clean() method when the object is closed or no longer needed. Note that the cleaning action must not refer to the object being registered.

Cleaners provide a more reliable way to perform cleanup tasks than relying on finalization. Finalization is often unreliable because it is not guaranteed to be called before the object is garbage collected. Cleaners, on the other hand, are guaranteed to be called before the object is garbage collected, as long as the clean() method is invoked.

See the sample usage of a Java Cleaner below:

import java.lang.ref.Cleaner;

public class SampleResourceUsage implements AutoCloseable {

    /**
     * A cleaner, preferably one shared within a library
     */
    private static final Cleaner cleaner = Cleaner.create();

    /**
     * An instance of Cleaner.Cleanable that the register returned.
     */
    final private Cleaner.Cleanable cleanable;

    /**
     * The resource that should be cleaned after use.
     */
    final private CloseableResource resource;

    public SampleResourceUsage() {
        //Instantiate a resource that must be cleaned after use.
        resource = new CloseableResource();

        //Register with the cleaner.
        cleanable = cleaner.register(this, resource::close);
    }

    public void use() {
        resource.use();
    }

    @Override
    public void close() {
        //Use clean method from the Cleanable instance to close the resource.
        cleanable.clean();
    }

    public static void main(String ... args) throws InterruptedException {
        //Create an instance with cleanable resource.
        var resource = new SampleResourceUsage();
        resource.use();

        //Remove the instance reference.
        resource = null;

        //Request for a garbage collection.
        System.gc();

        //Try to wait for a garbage collection to complete.
        //If garbage collection was not triggered. Increase the timeout.
        Thread.sleep(1000);
    }

    /**
     * The class that should have clean up operation.
     */
    private static class CloseableResource {
        public void use() {
            System.out.println("Using the resource that must be cleaned.");
        }

        /**
         * The cleaner that must be called for garbage collection.
         */
        public void close() {
            System.out.println("Cleaning up.");
        }
    }
}

Expect to see the following output:

Using the resource.
Cleaning up.

If you didn't see preceding output, you might need to check the timeout value.

Here are some additional things to keep in mind when using Java Cleaner:

  • The Cleaner object is a heavyweight object, so it should be shared whenever possible.
  • The Cleaner thread is a daemon thread, so it will not prevent your program from exiting.
  • The clean() method can only be called once. If you need to perform multiple cleanup actions, you should use a Runnable object to wrap the cleanup actions.

Checksum Using SHA-256 MessageDigest

//The data to be checksumed.
final var data = "Hello";
final MessageDigest md;
try {
    md = MessageDigest.getInstance("SHA-256");
    try (DigestInputStream dis = new DigestInputStream(
            //This can be replaced with FileInputStream.
            //The data just needs to be a File path.
            new ByteArrayInputStream(data.getBytes())
            , md)) {
        final var buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = dis.read(buffer)) != -1) {
            // Read the data into the buffer to update the digest
            md.update(buffer, 0, bytesRead);
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    final var digest = md.digest();
    final var sb = new StringBuilder();
    for (final byte b : digest) {
        sb.append(String.format("%02x", b & 0xff));
    }
    System.out.println("Checksum: " + sb.toString());
} catch (NoSuchAlgorithmException e) {
    throw new RuntimeException(e);
}

Retrieving the X509 Certificate Information in Java

//This will hold the target leaf certificate.
Optional<Certificate> cert;

try {
    //Must hold the target URL.
    final var targetUrl = "https://www.google.com";
    final var httpsURL = new URL(targetUrl);
    final var connection = (HttpsURLConnection) httpsURL.openConnection();
    connection.connect();

    //Retrieve the first certificate. This is normally the leaf certificate.
    cert = Arrays.stream(connection.getServerCertificates()).findFirst();
} catch (IOException e) {
    throw new RuntimeException(e);
}

cert.ifPresent(cer -> {
    //Check if the instance of certificate is of type of X509Certificate.
    if(cer instanceof final X509Certificate x509) {
        System.out.println("Subject: " + x509.getSubjectX500Principal().getName());
        System.out.println("From: " + x509.getNotBefore());
        System.out.println("To: " + x509.getNotAfter());
        System.out.println("Duration: " + ChronoUnit.DAYS.between(LocalDate.now(), LocalDate.ofInstant(x509.getNotAfter().toInstant(),ZoneId.systemDefault())));
        System.out.println("\n");
    }
});

Showing JVM Flags and Values

Flags

Flag Description
UnlockDiagnosticVMOptions Unlocks the options intended for diagnosing the JVM. By default, this option is disabled and diagnostic options are not available.
PrintFlagsFinal Shows the final flag values that JVM uses.

Usage

java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version

The usage of version argument is used to show the java version information instead of the help information.

« Older posts Newer posts »