Sunday, May 05, 2024

Java 22: Statements Before super(...)

Java 22 brings forth a new preview language feature: the ability to include statements before the super() call in constructors.

Traditionally, Java constructors have had a strict rule: the super() call, which invokes the superclass constructor, must always be the first statement in a subclass constructor. This rule, while ensuring proper initialisation order, sometimes led to verbose or convoluted constructor implementations, especially when additional setup was required before invoking the superclass constructor.

With the introduction of JDK 22, this limitation has been relaxed with the introduction of pre-super statements, which allow you to validate and prepare arguments before the super() call. This also facilitates fail-fast scenarios, because you can perform rigorous argument validation or exception handling before superclass instantiation.

Here is an example:

class Shape {
  private final String color;

  Shape(String color) {
    this.color = color;
  }
}

class Rectangle extends Shape {
  private final double length;
  private final double width;

  Rectangle(String color, double length, double width) {
    if (length <= 0 || width <= 0) {
      throw new IllegalArgumentException("Dimensions must be positive");
    }
    super(color);
    this.length = length;
    this.width = width;
  }
}

In this example, before invoking the superclass constructor, a pre-super statement validates the dimensions of the rectangle, ensuring they are positive.

Saturday, May 04, 2024

Java 22: Unnamed Variables and Patterns

Java 22 introduces Unnamed Variables & Patterns. Unnamed variables are placeholders denoted by the underscore character (_) that stand in for variable names, particularly in situations where the variable's identifier is insignificant or redundant. They can be declared in several contexts, including local variable declarations, catch clauses, lambda expressions, and more. By omitting explicit variable names in scenarios where the variable name serves no functional purpose, code becomes more succinct, reducing unnecessary verbosity and aiding readability.

Here are a few examples of unnamed variables in action:

For-loop:

for (Order _ : orders) {
  doSomething();
}

Assignment statement:

Queue<Integer> q = ... // x1, y1, z1, x2, y2, z2, ...
var x = q.remove();
var y = q.remove();
var _ = q.remove();

Lambda expressions:

list.stream().mapToInt(_ -> 1).sum();

Exception handling:

String s = ...
try {
  int i = Integer.parseInt(s);
} catch (NumberFormatException _) {
  System.out.println("Invalid number: " + s);
}

Try-with-resources:

try (BufferedReader _ = new BufferedReader(...)) {
  System.out.println("File opened successfully.");
} catch (IOException _) {
  System.err.println("An error occurred while opening the file.");
}

Unnamed pattern variables:

switch (shape) {
  case Circle _ -> process(shape, 0);
  case Triangle _ -> process(shape, 3);
  case Rectangle _ -> process(shape, 4);
  case var _ -> System.out.println("Unknown shape");
}

Unnamed Patterns

Unnamed Patterns provide an elegant solution when you need to match a pattern without extracting specific components. If you have nested data structures, such as records within records, with unnamed patterns, you can focus on extracting the necessary components without cluttering your code with unnecessary variable assignments.

record Address(String city, String country) {}
record Person(String name, int age, Address address) {}

if (person instanceof Person(var name, _, Address(var city, _))) {
  System.out.println(name + " lives in " + city);
}

So, the next time you encounter a situation where the variable name seems inconsequential, consider using an unnamed variable to streamline your code.

Sunday, April 07, 2024

Useful FFmpeg Commands

FFmpeg is a great command-line tool for dealing with audio and video files. Here are a couple of useful commands:

Extract audio from a video
$ ffmpeg -i video.mp4 -q:a 0 -map a audio.mp3
Concatenate multiple videos into a single file

First, create a file containing the list of videos to concatenate, and then pass it through ffmpeg:

$ cat list.txt
file '/path/to/file1.mp4'
file '/path/to/file2.mp4'
file '/path/to/file3.mp4'

$ ffmpeg -safe 0 -f concat -i list.txt -c copy output.mp4

Related post:
FFmpeg Cheatsheet

Monday, January 01, 2024

fahd.blog in 2023

Happy 2024, everyone!

I'd like to wish everyone a great start to an even greater new year!

In keeping with tradition, here's one last look back at fahd.blog in 2023.

During 2023, I posted 11 new entries on fahd.blog. I am also thrilled that I have more readers from all over the world! Thanks for reading and especially for giving feedback.

Top 3 posts of 2023:

I'm going to be writing a lot more this year, so stay tuned for more great techie tips, tricks and hacks! :)

Related posts:

Saturday, December 09, 2023

Python: Running Tasks in Parallel

The concurrent.futures module can be used to run tasks in parallel in Python. Here is an example:

import concurrent.futures
from concurrent.futures import ProcessPoolExecutor

with ProcessPoolExecutor(max_workers = 10) as executor:
    futures = [executor.submit(perform_task, task) for task in tasks]
	
results = [future.result() for future in futures]

The ProcessPoolExecutor class uses a pool of processes to execute tasks asynchronously. The submit function immediately returns a Future object, and you can call future.result(), which will block until the task has completed.

Note that there is also a ThreadPoolExecutor class which uses a pool of threads; however, due to the Global Interpreter Lock, only one thread can execute python bytecode at any one time, which means that you will not achieve any parallelisation in most cases.