Hacker News new | ask | show | jobs
by singularity2001 2824 days ago
wow, after all these years, the Java syntax for

print(fetch("https://winterbe.com"))

is still this behemoth:

var request = HttpRequest.newBuilder() .uri(URI.create("https://winterbe.com")) .GET() .build(); var client = HttpClient.newHttpClient(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); !?

One can argue about taste, but how can anyone defend such uuuuuuuuurgh?

6 comments

Oddly, I almost feel compelled to.

The verbosity in that code is less of the typical (and deserved) Java criticism of over-architected pattern cancer. Instead, almost all of the verbosity there is due to a refusal of the language to assume common defaults.

Whether assuming common defaults or forcing people to think about that stuff is good or bad is debatable. But it's certainly far from deserving of the "uuuuuuuuurgh" of a lot of (mostly older) Java I've had to wade through.

This is really a really weird overdesigned API. Maybe I don't understand the purpose of it but it seems like an excessive use of design patterns.

Why would you need a Builder method on a static object to create a request object? Oh well, let me rephrase that: First you instantiate a Builder object that you need to call the create method on to get a request. Makes no sense to me.

What not make HttpRequest a concrete class and just instantiate it? If there's any good reason for that design please enlighten me.

Many use cases want to make a whole lot of pretty similar (URI, creds, method) requests that vary only in a single way ( e.g. a POST parameter) or don't vary at all (e.g. polling).

A builder is a convenient way to wrap up those common settings so that they can be handed to other parts of the code that don't care about them/want to override specific parts and leave the rest in common.

Now, there are other ways to do that (instantiating a concrete class with common settings and mutable fields for customizations in a function, and then passing references to that function to everything that wants the common-config-defaulted output object). The choice between that kind of strategy (or an instantiate-and-freeze-early and pass your mutators in, or a refactor-all-your-code-to-not-mutate strategy etc...) and a builder pattern is a subjective and debatable one. But the approach taken here is certainly defensible.

Much better than HttpUrlConnection though. As an aside, the http client API seems really well thought out, supporting all sorts of common use cases for http. Once you convert the examples to some non trivial request response stuff, the new API shines. I think the job of pleasent APIs for starters is left to external libraries here.
Yes, developers that like getting all the low level Lego pieces and are able to write higher level abstractions themselves.

You should never try to learn 3D graphics programming if that basic stuff is already "uuuuuuuuurgh" for you.

Almost nobody uses the standard lib for http in practice. Just use Unirest/OkHttp/SpringBoot then it’s trivial. SpringBoot is the best framework that I have worked with regardless of language. It covers most use case out of the box and everything is still completely configurable.
you can put all that in

print and fetch methods and both of those would be equivalent.