What is Hackers' Pub?

Hackers' Pub is a place for software engineers to share their knowledge and experience with each other. It's also an ActivityPub-enabled social network, so you can follow your favorite hackers in the fediverse and get their latest posts in your feed.

0
0

ECBチーフエコノミスト、ステーブルコインや米大手テック企業と対抗するにはデジタルユーロが必要と発言

CoinDesk JAPAN(コインデスク・ジャパン) @coindeskjapan.com@web.brid.gy

ECBチーフエコノミスト、ステーブルコインや米大手テック企業と対抗するにはデジタルユーロが必要と発言

欧州中央銀行(ECB)のチーフエコノミスト、フィリップ・レーン氏は、ドル連動型ステーブルコインと米国の電子決済システムが欧州の金融システム内で足場を固めつつある ...

The post ECBチーフエコノミスト、ステーブルコインや米大手テック企業と対抗するにはデジタルユーロが必要と発言 first appeared on CoinDesk JAPAN(コインデスク・ジャパン).

Read more →
0
0
0
0
0

Die Selbstplastifizierung des Menschen

Wir Menschen sind ja bisweilen geradezu rührend naiv. Da ersäufen wir einerseits den gesamten Lebensraum in Plastikmüll und sind andererseits erstaunt, dass wir uns damit selbst vermüllen, so als hätten wir nichts mit unserem Lebensraum zu tun. Untersuchungen zeigen: In unseren Gehirnen finden sich mittlerweile 5 Mikrogramm Plastik auf 1g Gehirnmasse, Tendenz steigend.

Illustration: ein Mann un schwarz mit Zylinder mit geneigtem Haupt trägt gelbe Säcke. Textzeile: Wenn die Menschen weiter so viel Mikroplastik aufnehmen, werden Beerdigungen in gelben Säcken nötig.
0
0
0

Firefoxだと家族くっつくなあ

$ bundle exec ruby show-unicode-name.rb 👨‍👩‍👦‍👦
"👨" MAN
"‍" ZERO WIDTH JOINER
"👩" WOMAN
"‍" ZERO WIDTH JOINER
"👦" BOY
"‍" ZERO WIDTH JOINER
"👦" BOY
$ cat show-unicode-name.rb
#!/usr/bin/ruby
#
# usage: ruby show-unicoce-name.rb Ʊ”−ʓ
#
require "unicode/name"

str = ARGV.first
unless str
str = $stdin.read.chomp
end

str.chars.each do |c|
puts "#{c.inspect}\t#{Unicode::Name.of c}"
end

xfce4-tereminalで表示したばらばらの家族。フォントはたぶんRicty Diminished Regular 11。Firefoxの文字入力欄にひとまとまりで表示された家族。フォントはたぶんNoto Sans。
0
0
0
0
0
0

The trends in frontend development are making it hard to build products that will still be around in 5 or 10 years.

The frontend framework or build toolchain that you pick for your job today is likely to be deprecated and affected by countless breaking changes already in 6 months - let alone survive the next 10 years.

It sounds like frontend development has become this eternal “let’s rewrite everything” black hole of wastefulness, fed by a toxic market made of useless influencers, useless conferences, useless certifications and useless developers who have made a certain framework part of their identity, and whenever they join a new job their only contribution is “I see that you use X for your frontend - can we rewrite all with Y?”

If you have to pick a frontend framework, pick one and stick with it. Master it inside out. Resist any push to change. Success is defined by the usefulness of your final product, not by choosing Vue 3 + Vite, React with Remix, Svelte or Apollo CLI, nor by your ability to stay up-to-date with whatever new trend or useless abstraction the frontend parasites have thrown in the cogs of our industry just to make a bit more money out of courses and conferences. Nor by your ability to attract frontend developers who master the new shiny thing. A developer is first of all a problem solver who is able to solve problems regardless of the tools - it could also be vanilla JS or jQuery. Those who can only solve problems with a specific configuration of dependencies and frameworks are fanboys, not developers.

https://polotek.net/posts/the-frontend-treadmill/

0
0

Why are Germans being detained by US immigration?

Three tourists and a permanent US resident say they were subjected to aggressive interrogation and held for weeks without knowing why. In response, the German government has extended a travel advisory to its citizens.
dw.com/en/why-are-germans-bein

0

言ってはいけない可能性があるので一応隠す

これ実際に刑法175条をわざわざ守る必要があるかとかそういう問題ではなく、警察の怖くてエロい人からの怒られが発生しないために、「管理者としてちゃんと取り締まりしてますし注意喚起してますよ」という実績を示しておく必要があるか、あるいは既に何かしらの怒られが発生したのではと思われる
多分幾らネットに無知な警察でも「SNSに無修正えっち画像が1件でも放置されてたらダメ、投稿する奴がいた時点でサーバーごと潰す」とかは言い出さないはずなので、管理者が常識的な範囲の仕事してるかどうかが本質的な問題になるはず

0

イギリスはアメリカに対しTravel Warningを出したのか。ルールを守ることと、どんな難癖もつけられないぐらいにルールを厳守することの間には大きな開きがある。
記事で言及されているレベッカ・バークはホストファミリーの家事を手伝っていた。いままで誰も問題にしていなかった旅行のある形態だけど、それが旅行者に許可されていない「労働」になるということで、拘束され、独房を経由して拘留施設に送られ、強制送還された。

アメリカ人CEOが日本に来てラーメンを食う写真を投稿した時、それが事業のプロモーションになるからといって(バークが「稼いだ宿泊費」の比ではないプロモーションになるのは確実だ)手錠をかけて独房に入れ、入管に拘留して臭い飯を食わせた末にエコノミーで叩き返したらどうなると思う?

newsweek.com/britain-issues-tr

0

What I learned so far in the last months
1. I have to be very clear
2. Double check info I receive
3. Do what is right for the people
4. Be okay being the bad guy
5. Integrity is crucial but rare

0
0
0
0

국가유산청은 “‘산 것을 죽이지 않는다’는 생명 존중의 원칙과 절제의 가치를 구현하는 고유의 음식 문화를 형성해왔고, 최근에는 국내외 요리 전문가들의 창의적인 재해석 작업도 진행되는 등 문화적 다양성에 기여한다는 점에서 가치가 크다”고 설명했다. www.hani.co.kr/arti/culture...

hani.co.kr/arti/culture/c...

0
0
0
0

Why are Germans being detained by US immigration?

Three tourists and a permanent US resident say they were subjected to aggressive interrogation and held for weeks without knowing why. In response, the German government has extended a travel advisory to its citizens.
dw.com/en/why-are-germans-bein

0

2017년 박근혜 탄핵 헌법재판소 결정문 읽어보는데, 보충의견 중 안창호(지금 인권위를 망가뜨리고 있는 그 사람) 의견문을 보니 처음엔 탄핵문제와 직접적인 관련이 없는 대통령 제도의 문제를 열심히 말하고 뒷부분에는 "옛 성현의 지적"이나 "성경말씀"을 인용하는 이상한 글이었다...

0
0
0
0
0
0
0
0

🌊💻 OceanSprint 2025 – Day 3 💻🌊

The most amazing part of this sprint isn't just the hacking or excursions (surfing at Famara Beach and winery visits were awesome!). It’s the sense of community. Despite recent drama around forks (Nix, Lix, Tvix/Snix), I've seen firsthand how people come together here—sharing ideas, having respectful discussions, and moving the ecosystem forward. The space is big enough for everyone, and that’s what makes it special.

Me with a wet suit on the Famara beach waiting for surf lessons to startWine fields on LanzaroteGroup discussion in the OceanSprint venue's kitchen
0

📢 Do you remember the xz supply chain attack (or backdoor) that happened one year ago and nearly compromised half the world? (I think you do)

I claim that we could have automatically detected this backdoor in NixOS thanks to reproducible-builds!

-> Go read about it in my blog post: luj.fr/blog/how-nixos-could-ha

🔁 Boosts would be much appreciated!

0
0
0

유루메 Yurume replied to the below article:

Revisiting Java's Checked Exceptions: An Underappreciated Type Safety Feature

洪 民憙 (Hong Minhee) @hongminhee@hackers.pub

Despite their bad reputation in the Java community, checked exceptions provide superior type safety comparable to Rust's Result<T, E> or Haskell's Either a b—we've been dismissing one of Java's best features all along.

Introduction

Few features in Java have been as consistently criticized as checked exceptions. Modern Java libraries and frameworks often go to great lengths to avoid them. Newer JVM languages like Kotlin have abandoned them entirely. Many experienced Java developers consider them a design mistake.

But what if this conventional wisdom is wrong? What if checked exceptions represent one of Java's most forward-thinking features?

In this post, I'll argue that Java's checked exceptions were ahead of their time, offering many of the same type safety benefits that are now celebrated in languages like Rust and Haskell. Rather than abandoning this feature, we should consider how to improve it to work better with modern Java's features.

Understanding Java's Exception Handling Model

To set the stage, let's review how Java's exception system works:

  • Unchecked exceptions (subclasses of RuntimeException or Error): These don't need to be declared or caught. They typically represent programming errors (NullPointerException, IndexOutOfBoundsException) or unrecoverable conditions (OutOfMemoryError).

  • Checked exceptions (subclasses of Exception but not RuntimeException): These must either be caught with try/catch blocks or declared in the method signature with throws. They represent recoverable conditions that are outside the normal flow of execution (IOException, SQLException).

Here's how this works in practice:

// Checked exception - compiler forces you to handle or declare it
public void readFile(String path) throws IOException {
    Files.readAllLines(Path.of(path));
}

// Unchecked exception - no compiler enforcement
public void processArray(int[] array) {
    int value = array[array.length + 1]; // May throw ArrayIndexOutOfBoundsException
}

The Type Safety Argument for Checked Exceptions

At their core, checked exceptions are a way of encoding potential failure modes into the type system via method signatures. This makes certain failure cases part of the API contract, forcing client code to explicitly handle these cases.

Consider this method signature:

public byte[] readFileContents(String filePath) throws IOException

The throws IOException clause tells us something critical: this method might fail in ways related to IO operations. The compiler ensures you can't simply ignore this fact. You must either:

  1. Handle the exception with a try-catch block
  2. Propagate it by declaring it in your own method signature

This type-level representation of potential failures aligns perfectly with principles of modern type-safe programming.

Automatic Propagation: A Hidden Advantage

One often overlooked advantage of Java's checked exceptions is their automatic propagation. Once you declare a method as throws IOException, any exception that occurs is automatically propagated to the caller without additional syntax.

Compare this with Rust, where you must use the ? operator every time you call a function that returns a Result:

// Rust requires explicit propagation with ? for each call
fn read_and_process(path: &str) -> Result<(), std::io::Error> {
    let content = std::fs::read_to_string(path)?;
    process_content(&content)?;
    Ok(())
}

// Java automatically propagates exceptions once declared
void readAndProcess(String path) throws IOException {
    String content = Files.readString(Path.of(path));
    processContent(content); // If this throws IOException, it's automatically propagated
}

In complex methods with many potential failure points, Java's approach leads to cleaner code by eliminating the need for repetitive error propagation markers.

Modern Parallels: Result Types in Rust and Haskell

The approach of encoding failure possibilities in the type system has been adopted by many modern languages, most notably Rust with its Result<T, E> type and Haskell with its Either a b type.

In Rust:

fn read_file_contents(file_path: &str) -> Result<Vec<u8>, std::io::Error> {
    std::fs::read(file_path)
}

When calling this function, you can't just ignore the potential for errors—you need to handle both the success case and the error case, often using the ? operator or pattern matching.

In Haskell:

readFileContents :: FilePath -> IO (Either IOException ByteString)
readFileContents path = try $ BS.readFile path

Again, the caller must explicitly deal with both possible outcomes.

This is fundamentally the same insight that motivated Java's checked exceptions: make failure handling explicit in the type system.

Valid Criticisms of Checked Exceptions

If checked exceptions are conceptually similar to these widely-praised error handling mechanisms, why have they fallen out of favor? There are several legitimate criticisms:

1. Excessive Boilerplate in the Call Chain

The most common complaint is the boilerplate required when propagating exceptions up the call stack:

void methodA() throws IOException {
    methodB();
}

void methodB() throws IOException {
    methodC();
}

void methodC() throws IOException {
    // Actual code that might throw IOException
}

Every method in the chain must declare the same exception, creating repetitive code. While automatic propagation works well within a method, the explicit declaration in method signatures creates overhead.

2. Poor Integration with Functional Programming

Java 8 introduced lambdas and streams, but checked exceptions don't play well with them:

// Won't compile because map doesn't expect functions that throw checked exceptions
List<String> fileContents = filePaths.stream()
    .map(path -> Files.readString(Path.of(path))) // Throws IOException
    .collect(Collectors.toList());

This forces developers to use awkward workarounds:

List<String> fileContents = filePaths.stream()
    .map(path -> {
        try {
            return Files.readString(Path.of(path));
        } catch (IOException e) {
            throw new UncheckedIOException(e); // Wrap in an unchecked exception
        }
    })
    .collect(Collectors.toList());

3. Interface Evolution Problems

Adding a checked exception to an existing method breaks all implementing classes and calling code. This makes evolving interfaces over time difficult, especially for widely-used libraries and frameworks.

4. Catch-and-Ignore Anti-Pattern

The strictness of checked exceptions can lead to the worst possible outcome—developers simply catching and ignoring exceptions to make the compiler happy:

try {
    // Code that might throw
} catch (Exception e) {
    // Do nothing or just log
}

This is worse than having no exception checking at all because it provides a false sense of security.

Improving Checked Exceptions Without Abandoning Them

Rather than abandoning checked exceptions entirely, Java could enhance the existing system to address these legitimate concerns. Here are some potential improvements that preserve the type safety benefits while addressing the practical problems:

1. Allow lambdas to declare checked exceptions

One of the biggest pain points with checked exceptions today is their incompatibility with functional interfaces. Consider how much cleaner this would be:

// Current approach - forced to handle or wrap exceptions inline
List<String> contents = filePaths.stream()
    .map(path -> {
        try {
            return Files.readString(Path.of(path));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    })
    .collect(Collectors.toList());

// Potential future approach - lambdas can declare exceptions
List<String> contents = filePaths.stream()
    .map((String path) throws IOException -> Files.readString(Path.of(path)))
    .collect(Collectors.toList());

This would require updating functional interfaces to support exception declarations:

@FunctionalInterface
public interface Function<T, R, E extends Exception> {
    R apply(T t) throws E;
}

2. Generic exception types in throws clauses

Another powerful enhancement would be allowing generic type parameters in throws clauses:

public <E extends Exception> void processWithException(Supplier<Void, E> supplier) throws E {
    supplier.get();
}

This would enable much more flexible composition of methods that work with different exception types, bringing some of the flexibility of Rust's Result<T, E> to Java's existing exception system.

3. Better support for exception handling in functional contexts

Unlike Rust which requires the ? operator for error propagation, Java already automatically propagates checked exceptions when declared in the method signature. What Java needs instead is better support for checked exceptions in functional contexts:

// Current approach for handling exceptions in streams
List<String> contents = filePaths.stream()
    .map(path -> {
        try {
            return Files.readString(Path.of(path));
        } catch (IOException e) {
            throw new RuntimeException(e); // Lose type information
        }
    })
    .collect(Collectors.toList());

// Hypothetical improved API
List<String> contents = filePaths.stream()
    .mapThrowing(path -> Files.readString(Path.of(path))) // Preserves checked exception
    .onException(IOException.class, e -> logError(e))
    .collect(Collectors.toList());

4. Integration with Optional<T> and Stream<T> APIs

The standard library could be enhanced to better support operations that might throw checked exceptions:

// Hypothetical API
Optional<String> content = Optional.ofThrowable(() -> Files.readString(Path.of("file.txt")));
content.ifPresentOrElse(
    this::processContent,
    exception -> log.error("Failed to read file", exception)
);

Comparison with Other Languages' Approaches

It's worth examining how other languages have addressed the error handling problem:

Rust's Result<T, E> and ? operator

Rust's approach using Result<T, E> and the ? operator shows how propagation can be made concise while keeping the type safety benefits. The ? operator automatically unwraps a successful result or returns the error to the caller, making propagation more elegant.

However, Rust's approach requires explicit propagation at each step, which can be more verbose than Java's automatic propagation in certain scenarios.

Kotlin's Approach

Kotlin made all exceptions unchecked but provides functional constructs like runCatching that bring back some type safety in a more modern way:

val result = runCatching {
    Files.readString(Path.of("file.txt"))
}

result.fold(
    onSuccess = { content -> processContent(content) },
    onFailure = { exception -> log.error("Failed to read file", exception) }
)

This approach works well with Kotlin's functional programming paradigm but lacks compile-time enforcement.

Scala's Try[T], Either[A, B], and Effect Systems

Scala offers Try[T], Either[A, B], and various effect systems that encode errors in the type system while integrating well with functional programming:

import scala.util.Try

val fileContent: Try[String] = Try {
  Source.fromFile("file.txt").mkString
}

fileContent match {
  case Success(content) => processContent(content)
  case Failure(exception) => log.error("Failed to read file", exception)
}

This approach preserves type safety while fitting well with Scala's functional paradigm.

Conclusion

Java's checked exceptions were a pioneering attempt to bring type safety to error handling. While the implementation has shortcomings, the core concept aligns with modern type-safe approaches to error handling in languages like Rust and Haskell.

Copying Rust's Result<T, E> might seem like the obvious solution, but it would represent a radical departure from Java's established paradigms. Instead, targeted enhancements to the existing checked exceptions system—like allowing lambdas to declare exceptions and supporting generic exception types—could preserve Java's unique approach while addressing its practical limitations.

The beauty of such improvements is that they'd maintain backward compatibility while making checked exceptions work seamlessly with modern Java features like lambdas and streams. They would acknowledge that the core concept of checked exceptions was sound—the problem was in the implementation details and their interaction with newer language features.

So rather than abandoning checked exceptions entirely, perhaps we should recognize them as a forward-thinking feature that was implemented before its time. As Java continues to evolve, we have an opportunity to refine this system rather than replace it.

In the meantime, next time you're tempted to disparage checked exceptions, remember: they're not just an annoying Java quirk—they're an early attempt at the same type safety paradigm that newer languages now implement with much celebration.

What do you think? Could these improvements make checked exceptions viable for modern Java development? Or is it too late to salvage this controversial feature? I'm interested in hearing your thoughts in the comments.

Read more →
0
0
3
0
0

개인적으론 공식 계정들이 오기만을 기다리는건 허무맹랑하다고 봅니다. 소셜 미디어 역사상 기업이 먼저 와서 기다린 경우가 거의 없기도 하고 블루스카이에 공식 계정들이 생긴것도 사람들이 많이 있기 때문에 가능한거였죠. 기업들은 절대 사람 없는 곳에서 마케팅하지 않으려고 할겁니다.

0
0
0
0

The trends in frontend development are making it hard to build products that will still be around in 5 or 10 years.

The frontend framework or build toolchain that you pick for your job today is likely to be deprecated and affected by countless breaking changes already in 6 months - let alone survive the next 10 years.

It sounds like frontend development has become this eternal “let’s rewrite everything” black hole of wastefulness, fed by a toxic market made of useless influencers, useless conferences, useless certifications and useless developers who have made a certain framework part of their identity, and whenever they join a new job their only contribution is “I see that you use X for your frontend - can we rewrite all with Y?”

If you have to pick a frontend framework, pick one and stick with it. Master it inside out. Resist any push to change. Success is defined by the usefulness of your final product, not by choosing Vue 3 + Vite, React with Remix, Svelte or Apollo CLI, nor by your ability to stay up-to-date with whatever new trend or useless abstraction the frontend parasites have thrown in the cogs of our industry just to make a bit more money out of courses and conferences. Nor by your ability to attract frontend developers who master the new shiny thing. A developer is first of all a problem solver who is able to solve problems regardless of the tools - it could also be vanilla JS or jQuery. Those who can only solve problems with a specific configuration of dependencies and frameworks are fanboys, not developers.

https://polotek.net/posts/the-frontend-treadmill/

0
0

🌋💻 OceanSprint 2025 – Day 4 🚀

We made great progress today! Fixes to the apache-airflow package, improvements to Snix and integration test support in nixpkgs, and a blog post on preventing the XZ backdoor.

Big strides in supply chain security too: packaged SPIFFE for secure identity, and improved SBOM support via Laut, integrating it with Lila to track build provenance.

Plus, we hiked up a volcano for epic views and enjoyed traditional paella! 🍽️

A whiteboard with the text days since last fork: 3. The word fork is crossed out and "Downstream Distributions" is written below.Group foto of the OceanSpring 2025 teamPaela
0
0

국가유산청은 “‘산 것을 죽이지 않는다’는 생명 존중의 원칙과 절제의 가치를 구현하는 고유의 음식 문화를 형성해왔고, 최근에는 국내외 요리 전문가들의 창의적인 재해석 작업도 진행되는 등 문화적 다양성에 기여한다는 점에서 가치가 크다”고 설명했다. www.hani.co.kr/arti/culture...

hani.co.kr/arti/culture/c...

0

Daniel Temme shared the below article:

Revisiting Java's Checked Exceptions: An Underappreciated Type Safety Feature

洪 民憙 (Hong Minhee) @hongminhee@hackers.pub

Despite their bad reputation in the Java community, checked exceptions provide superior type safety comparable to Rust's Result<T, E> or Haskell's Either a b—we've been dismissing one of Java's best features all along.

Introduction

Few features in Java have been as consistently criticized as checked exceptions. Modern Java libraries and frameworks often go to great lengths to avoid them. Newer JVM languages like Kotlin have abandoned them entirely. Many experienced Java developers consider them a design mistake.

But what if this conventional wisdom is wrong? What if checked exceptions represent one of Java's most forward-thinking features?

In this post, I'll argue that Java's checked exceptions were ahead of their time, offering many of the same type safety benefits that are now celebrated in languages like Rust and Haskell. Rather than abandoning this feature, we should consider how to improve it to work better with modern Java's features.

Understanding Java's Exception Handling Model

To set the stage, let's review how Java's exception system works:

  • Unchecked exceptions (subclasses of RuntimeException or Error): These don't need to be declared or caught. They typically represent programming errors (NullPointerException, IndexOutOfBoundsException) or unrecoverable conditions (OutOfMemoryError).

  • Checked exceptions (subclasses of Exception but not RuntimeException): These must either be caught with try/catch blocks or declared in the method signature with throws. They represent recoverable conditions that are outside the normal flow of execution (IOException, SQLException).

Here's how this works in practice:

// Checked exception - compiler forces you to handle or declare it
public void readFile(String path) throws IOException {
    Files.readAllLines(Path.of(path));
}

// Unchecked exception - no compiler enforcement
public void processArray(int[] array) {
    int value = array[array.length + 1]; // May throw ArrayIndexOutOfBoundsException
}

The Type Safety Argument for Checked Exceptions

At their core, checked exceptions are a way of encoding potential failure modes into the type system via method signatures. This makes certain failure cases part of the API contract, forcing client code to explicitly handle these cases.

Consider this method signature:

public byte[] readFileContents(String filePath) throws IOException

The throws IOException clause tells us something critical: this method might fail in ways related to IO operations. The compiler ensures you can't simply ignore this fact. You must either:

  1. Handle the exception with a try-catch block
  2. Propagate it by declaring it in your own method signature

This type-level representation of potential failures aligns perfectly with principles of modern type-safe programming.

Automatic Propagation: A Hidden Advantage

One often overlooked advantage of Java's checked exceptions is their automatic propagation. Once you declare a method as throws IOException, any exception that occurs is automatically propagated to the caller without additional syntax.

Compare this with Rust, where you must use the ? operator every time you call a function that returns a Result:

// Rust requires explicit propagation with ? for each call
fn read_and_process(path: &str) -> Result<(), std::io::Error> {
    let content = std::fs::read_to_string(path)?;
    process_content(&content)?;
    Ok(())
}

// Java automatically propagates exceptions once declared
void readAndProcess(String path) throws IOException {
    String content = Files.readString(Path.of(path));
    processContent(content); // If this throws IOException, it's automatically propagated
}

In complex methods with many potential failure points, Java's approach leads to cleaner code by eliminating the need for repetitive error propagation markers.

Modern Parallels: Result Types in Rust and Haskell

The approach of encoding failure possibilities in the type system has been adopted by many modern languages, most notably Rust with its Result<T, E> type and Haskell with its Either a b type.

In Rust:

fn read_file_contents(file_path: &str) -> Result<Vec<u8>, std::io::Error> {
    std::fs::read(file_path)
}

When calling this function, you can't just ignore the potential for errors—you need to handle both the success case and the error case, often using the ? operator or pattern matching.

In Haskell:

readFileContents :: FilePath -> IO (Either IOException ByteString)
readFileContents path = try $ BS.readFile path

Again, the caller must explicitly deal with both possible outcomes.

This is fundamentally the same insight that motivated Java's checked exceptions: make failure handling explicit in the type system.

Valid Criticisms of Checked Exceptions

If checked exceptions are conceptually similar to these widely-praised error handling mechanisms, why have they fallen out of favor? There are several legitimate criticisms:

1. Excessive Boilerplate in the Call Chain

The most common complaint is the boilerplate required when propagating exceptions up the call stack:

void methodA() throws IOException {
    methodB();
}

void methodB() throws IOException {
    methodC();
}

void methodC() throws IOException {
    // Actual code that might throw IOException
}

Every method in the chain must declare the same exception, creating repetitive code. While automatic propagation works well within a method, the explicit declaration in method signatures creates overhead.

2. Poor Integration with Functional Programming

Java 8 introduced lambdas and streams, but checked exceptions don't play well with them:

// Won't compile because map doesn't expect functions that throw checked exceptions
List<String> fileContents = filePaths.stream()
    .map(path -> Files.readString(Path.of(path))) // Throws IOException
    .collect(Collectors.toList());

This forces developers to use awkward workarounds:

List<String> fileContents = filePaths.stream()
    .map(path -> {
        try {
            return Files.readString(Path.of(path));
        } catch (IOException e) {
            throw new UncheckedIOException(e); // Wrap in an unchecked exception
        }
    })
    .collect(Collectors.toList());

3. Interface Evolution Problems

Adding a checked exception to an existing method breaks all implementing classes and calling code. This makes evolving interfaces over time difficult, especially for widely-used libraries and frameworks.

4. Catch-and-Ignore Anti-Pattern

The strictness of checked exceptions can lead to the worst possible outcome—developers simply catching and ignoring exceptions to make the compiler happy:

try {
    // Code that might throw
} catch (Exception e) {
    // Do nothing or just log
}

This is worse than having no exception checking at all because it provides a false sense of security.

Improving Checked Exceptions Without Abandoning Them

Rather than abandoning checked exceptions entirely, Java could enhance the existing system to address these legitimate concerns. Here are some potential improvements that preserve the type safety benefits while addressing the practical problems:

1. Allow lambdas to declare checked exceptions

One of the biggest pain points with checked exceptions today is their incompatibility with functional interfaces. Consider how much cleaner this would be:

// Current approach - forced to handle or wrap exceptions inline
List<String> contents = filePaths.stream()
    .map(path -> {
        try {
            return Files.readString(Path.of(path));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    })
    .collect(Collectors.toList());

// Potential future approach - lambdas can declare exceptions
List<String> contents = filePaths.stream()
    .map((String path) throws IOException -> Files.readString(Path.of(path)))
    .collect(Collectors.toList());

This would require updating functional interfaces to support exception declarations:

@FunctionalInterface
public interface Function<T, R, E extends Exception> {
    R apply(T t) throws E;
}

2. Generic exception types in throws clauses

Another powerful enhancement would be allowing generic type parameters in throws clauses:

public <E extends Exception> void processWithException(Supplier<Void, E> supplier) throws E {
    supplier.get();
}

This would enable much more flexible composition of methods that work with different exception types, bringing some of the flexibility of Rust's Result<T, E> to Java's existing exception system.

3. Better support for exception handling in functional contexts

Unlike Rust which requires the ? operator for error propagation, Java already automatically propagates checked exceptions when declared in the method signature. What Java needs instead is better support for checked exceptions in functional contexts:

// Current approach for handling exceptions in streams
List<String> contents = filePaths.stream()
    .map(path -> {
        try {
            return Files.readString(Path.of(path));
        } catch (IOException e) {
            throw new RuntimeException(e); // Lose type information
        }
    })
    .collect(Collectors.toList());

// Hypothetical improved API
List<String> contents = filePaths.stream()
    .mapThrowing(path -> Files.readString(Path.of(path))) // Preserves checked exception
    .onException(IOException.class, e -> logError(e))
    .collect(Collectors.toList());

4. Integration with Optional<T> and Stream<T> APIs

The standard library could be enhanced to better support operations that might throw checked exceptions:

// Hypothetical API
Optional<String> content = Optional.ofThrowable(() -> Files.readString(Path.of("file.txt")));
content.ifPresentOrElse(
    this::processContent,
    exception -> log.error("Failed to read file", exception)
);

Comparison with Other Languages' Approaches

It's worth examining how other languages have addressed the error handling problem:

Rust's Result<T, E> and ? operator

Rust's approach using Result<T, E> and the ? operator shows how propagation can be made concise while keeping the type safety benefits. The ? operator automatically unwraps a successful result or returns the error to the caller, making propagation more elegant.

However, Rust's approach requires explicit propagation at each step, which can be more verbose than Java's automatic propagation in certain scenarios.

Kotlin's Approach

Kotlin made all exceptions unchecked but provides functional constructs like runCatching that bring back some type safety in a more modern way:

val result = runCatching {
    Files.readString(Path.of("file.txt"))
}

result.fold(
    onSuccess = { content -> processContent(content) },
    onFailure = { exception -> log.error("Failed to read file", exception) }
)

This approach works well with Kotlin's functional programming paradigm but lacks compile-time enforcement.

Scala's Try[T], Either[A, B], and Effect Systems

Scala offers Try[T], Either[A, B], and various effect systems that encode errors in the type system while integrating well with functional programming:

import scala.util.Try

val fileContent: Try[String] = Try {
  Source.fromFile("file.txt").mkString
}

fileContent match {
  case Success(content) => processContent(content)
  case Failure(exception) => log.error("Failed to read file", exception)
}

This approach preserves type safety while fitting well with Scala's functional paradigm.

Conclusion

Java's checked exceptions were a pioneering attempt to bring type safety to error handling. While the implementation has shortcomings, the core concept aligns with modern type-safe approaches to error handling in languages like Rust and Haskell.

Copying Rust's Result<T, E> might seem like the obvious solution, but it would represent a radical departure from Java's established paradigms. Instead, targeted enhancements to the existing checked exceptions system—like allowing lambdas to declare exceptions and supporting generic exception types—could preserve Java's unique approach while addressing its practical limitations.

The beauty of such improvements is that they'd maintain backward compatibility while making checked exceptions work seamlessly with modern Java features like lambdas and streams. They would acknowledge that the core concept of checked exceptions was sound—the problem was in the implementation details and their interaction with newer language features.

So rather than abandoning checked exceptions entirely, perhaps we should recognize them as a forward-thinking feature that was implemented before its time. As Java continues to evolve, we have an opportunity to refine this system rather than replace it.

In the meantime, next time you're tempted to disparage checked exceptions, remember: they're not just an annoying Java quirk—they're an early attempt at the same type safety paradigm that newer languages now implement with much celebration.

What do you think? Could these improvements make checked exceptions viable for modern Java development? Or is it too late to salvage this controversial feature? I'm interested in hearing your thoughts in the comments.

Read more →
0
0
3

nogajun🍉 shared the below article:

『ドラマ・文学・K-POPがもっとわかる 今さら聞けない 現代韓国の超基本』(朝日新聞出版)

hana+(ハナタス) @hanatas.jp@web.brid.gy

書籍内容紹介(出版社) K-POP、K文学、韓流ドラマ、映画等で、世界を席巻する韓国カルチャー。その背景にある歴史、事件、文化、人物等を図解やイラストを使ってわかりやすく解説。「なにがなんでも韓国好き!」「よく知らないけ […]

投稿 『ドラマ・文学・K-POPがもっとわかる 今さら聞けない 現代韓国の超基本』(朝日新聞出版) は hana+(ハナタス) に最初に表示されました。

Read more →
0

nogajun🍉 shared the below article:

韓国映画ファン必見!2010年代を映画史で振り返る

hana+(ハナタス) @hanatas.jp@web.brid.gy

2010年代(2010〜2019年)は、韓国の人たちが「より映画を見るようになった」10年と言えるだろう。 映画の観客数は2013年に2億人を超えて以来、2018年まで2億1000万人台で推移。平均して1人当たり4本以上 […]

投稿 韓国映画ファン必見!2010年代を映画史で振り返る は hana+(ハナタス) に最初に表示されました。

Read more →
0
0
0