4 ms·
> Java is infamous for its verbosity. [...] This paragraph highlights something I've been saying for ages. Most criticism of Java needs to be directed towards
by Sohcahtoa82 5y ago
> Java is infamous for its verbosity. [...]
This paragraph highlights something I've been saying for ages.
Most criticism of Java needs to be directed towards Java programmers and not the language itself.
The language allows you to simply make a class. You're not required to make an interface and then make a class that implements it, and yet, Java programmers do it anyways and then criticize the language for being verbose.
Getters and Setters? You probably don't need them. Classes can have public member variables.
Java programmers seem to have the hardest time understanding YAGNI.
- floverfelt 5y agoYeah, I'm actually a pretty big fan of Java programming. It gets a lot of hate on HN for things that have been mostly solved or can be solved if you implement it a certain way.
- shagie 5y ago> Getters and Setters? You probably don't need them. Classes can have public member variables. The getter / setter debate and public fields is about exposing the internal implementation of the object (and thus making it unchangeable without breaking other code) and being able to reason about where the internals are used (if you do need to change them). For example, if I've got a java.util.Date exposed as a public field and someone uses it, I can't change that later to a java.time.LocalDateTime unless I change all of the things using it. If this is a library that others are using it may mean a cascade of unknown changes. If, on the other hand, the Date was exposed as a public Date getDate() { return date.clone(); } then I don't have to worry about it. When the internals are changed to LocalDateTime, then Date getDate() { return Date.from(local.atZone(ZoneId.systemDefault()).toInstant()); } and everything will still work. I don't have an issue with the infrequently used "default package private" level of field visibility where only classes in the same package can see that field as that limits the range of the changes to the classes within single package (in a single project).
- Jtsummers 5y agoGetters and Setters also permit you to specify that something can only be retrieved or assigned, but not the other. This is non-trivial in most programming languages so having this as a common pattern is useful. Though I like C#'s properties versus seeing a bunch of getFoo and setFoo methods running around, if Java had provided the same or a similar capability there would probably be no controversy. It's the noisiness of the Java solution that seems to irk people more than the concept.
- shagie 5y agoJava now has records which handles the creation of getters (and since its an immutable, it doesn't have any setters). https://blogs.oracle.com/javamagazine/post/records-come-to-java https://blogs.oracle.com/javamagazine/post/records-come-to-j... and https://dzone.com/articles/what-are-java-records https://dzone.com/articles/what-are-java-records I'm really looking forward to using the local records defined mid stream for bundling the information to the next part.
- avgcorrection 5y ago> Getters and Setters also permit you to specify that something can only be retrieved or assigned, but not the other. Only retrieved? `final` and set the fields through the constructor. Sure someone could implement setters-only if they wanted that. Except I’ve never seen it and get/set are always used instead. Just one layer of indirection for no benefit.
- Jtsummers 5y agoThat's not equivalent. You may want a field to be updated by other actions. That is, its value is derived from the other properties of the system. You could recompute those on each request, but that's potentially costly. You could also recreate the entire object with each small field change. That's also very costly. Consider a collection class which has a size field. `final` would be the wrong thing to use. If you expose the size field but make it final, well, it's immutable and your entire collection is either lying or also immutable. If you expose the size field but it's not final, then anything can alter it. Consequently, a getter (the concept of one at least, see C# again for a cleaner approach than what Java did historically) is useful and then when another element of the interface is used (adding or removing elements) the size field can be updated appropriately. The next time it's retrieved, it's correct and you don't need to recompute it. This kind of thing can be a consequence of many other systems, a collection is just sufficiently universally understood that it's a good example of the concept.
- avgcorrection 5y agoApparently your field was used both for some internal shenanigans as well as a public field through the get/set indirection. Then you changed the field but kept the old public behavior. I wonder whether (1) that dual purpose internal/public role was wise to be begin with, and (2) whether that change of the internal logic of the getter might have just papered over a more significant change. It might be good if a change just breaks client code. The client expects just to get/set something: they might not expect that some update migth add arbitrary logging or internal logic (like setting this value will also set another value, but we won’t tell you). Most of the get/set stuff that I see are for value objects with either no or little business logic. Simple value objects _should_ just expose their implementation.
- shagie 5y agoThe backing implementation of what supplies the DTO shouldn't be an issue for the client / other part of the application if the contract that the DTO provides remains the same. If that contract is the underlying field implementation, then that means that those fields are frozen and cannot change. If that contract is instead methods, the underlying field types can change (for example from a Date to a LocalDateTime) while the method contracts remain the same and new method contracts are added to expose more functionality for other clients / application modules. In particular, this was code written in the Java 1.7 days and it was Date (and all the mess with java.util.Date and java.sql.Date) while in 1.8 java.time was provided which allowed the underlying implementation of the object to cleaned up without changing the contract of the methods (things wanting a Date still get a Date). Yes, changing from a Date to a Calendar (because of the aforementioned java.sql.Date mess) to a LocalDateTime were significant changes -- but the clients didn't notice because the methods they were using remained consistent. The deeper you expose the client contract into the guts of the object, the more difficult it is to change when a change is needed. Now, if you're just passing DTOs around between classes within a single package or local to one library that don't leak - feel free to do whatever is needed. I suspect that records will solve a lot of the boilerplate DTO code, though passing a record outside of a library boundary gives me a bit of unease because it means that changes to the record will be breaking changes to the clients.
- bitwize 5y ago> The language allows you to simply make a class. You're not required to make an interface and then make a class that implements it, and yet, Java programmers do it anyways and then criticize the language for being verbose. That's the 'D' in SOLID -- dependency inversion. An object's dependencies should be defined in terms of abstract interfaces, not concrete classes. The verbosity is just boilerplate, and it would appear in any statically typed language if you're following SOLID principles. > Getters and Setters? You probably don't need them. Classes can have public member variables. Getters and setters are part of the JavaBeans spec for being able to load and configure arbitrary beans. If you're writing JavaBeans, as many EJB or Spring application developers are, you'll use getters and setters.
- goto11 5y ago> That's the 'D' in SOLID -- dependency inversion. An object's dependencies should be defined in terms of abstract interfaces, not concrete classes DI does not talk about the interface keyword in Java. It talks about interface as the public surface of an object or system. Programming to a Java interface declaration does not guarantee the code is depending on higher-level abstractions - this depends on how the interface is defined. An interface which just replicate the public surface of a class (a "header interface") is on the exact same abstraction level as the class, it just introduce needless boilerplate.
- gpderetta 5y agoI.e. (together with the S and I) this implies that the interface should be defined by its immediate consumer and should consist of all and only the methods required to implement the functionality in the most straightforward way (i.e. the consumer shouldn't have to deal with the idiosyncrasies of the provider). On most languages this requires a lot of boilerplate and indirections though.
- avgcorrection 5y ago> Getters and Setters? You probably don't need them. Classes can have public member variables. We do need them if the objects interact with a lot the libraries that we use. Libraries that we didn’t make. They expect get/set. I agree that getters/setters are very overrated. I tend to make public-final fields when I can. Most of the time I can’t though.
- deleted 5y ago[deleted]
- rajacombinator 5y agoVery true but Java devs tend to have limited perspective and flexibility. If you get rid of the cruft it’s a fine language.
- taeric 5y agoAmusingly, j2ee did require you to make an interface and an implementation. I seem to recall you had to also have a "stub" class. Which is to say, early ecosystems in Java certainly needed this criticism. They did adjust, though.
- selfhoster11 5y agoThank you. I have programmed Java for years, but it's been frustrating. The clean language I learnt at university, that I love to bits, seems to be used approximately nowhere. Instead, it's always some monstrosity held together by inheritance, XML/(awful) Gradle and liberal sprinklings of magical annotations that always (always!) bite you in the backside at runtime rather than at compile time, because why would you prefer to have good tooling that takes advantage of static typing to tell you what might go wrong. I am appalled by what Spring mentality did to my language.
- Too 5y agoJava was for very long missing anonymous functions, so for anything involving callbacks you had to make gazillion of Listener- or Factory-classes instead, which further forced you to create an interface for each of them. Leading to all these infamously verbose design-patterns. It was also for a very long time missing some fundamental Stream, List and String processing features. Just getting the contents of a file or converting a string to bytes, or even just initializing an Array often required 2-3 lines of verbose OutputStream(StreamBuilder().fromArray(Arrays.asList(1,2))).readBytes().add(3), wrapped in a try-catch for all the checked exceptions. For things that in C# would just be a oneliner of new List<int>({1,2,3}) or in Python [1,2,3]. This is mostly solved in current versions of the language, but the reputation and the "best practice" design-patterns remains.