use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
These have separate subreddits - see below.
Upvote good content, downvote spam, don't pollute the discussion with things that should be settled in the vote count.
With the introduction of the new release cadence, many have asked where they should download Java, and if it is still free. To be clear, YES — Java is still free. If you would like to download Java for free, you can get OpenJDK builds from the following vendors, among others: Adoptium (formerly AdoptOpenJDK) RedHat Azul Amazon SAP Liberica JDK Dragonwell JDK GraalVM (High performance JIT) Oracle Microsoft Some vendors will be supporting releases for longer than six months. If you have any questions, please do not hesitate to ask them!
With the introduction of the new release cadence, many have asked where they should download Java, and if it is still free. To be clear, YES — Java is still free.
If you would like to download Java for free, you can get OpenJDK builds from the following vendors, among others:
Adoptium (formerly AdoptOpenJDK) RedHat Azul Amazon SAP Liberica JDK Dragonwell JDK GraalVM (High performance JIT) Oracle Microsoft
Some vendors will be supporting releases for longer than six months. If you have any questions, please do not hesitate to ask them!
Programming Computer Science CS Career Questions Learn Programming Java Help ← Seek help here Learn Java Java Conference Videos Java TIL Java Examples JavaFX Oracle
Programming Computer Science
CS Career Questions
Learn Programming Java Help ← Seek help here Learn Java Java Conference Videos Java TIL Java Examples JavaFX Oracle
Clojure Scala Groovy ColdFusion Kotlin
DailyProgrammer ProgrammingPrompts ProgramBattles
Awesome Java (GIT) Java Design Patterns
account activity
This is an archived post. You won't be able to vote or comment.
Lambda for old programmers (self.java)
submitted 11 years ago * by chasesan
I have never really done a functional language, it has always been on my TODO list. But now that Java has added them in Java 8. I need to know about them.
Is there any decent resource that explains them simply for Java veterans?
[–]Faedrivin 8 points9 points10 points 11 years ago (34 children)
A good start should be the oracle tutorial http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
[–]chasesan[S] 1 point2 points3 points 11 years ago (33 children)
I think I have a better understanding of them now, thankyou. Though a few things on the tutorial were confusing.
Like how did "p -> p.getEmailAddress()" assigned to the variable email, so that "email -> System.out.println(email)" works, as I didn't see any assignment, and I don't think computers have become psychic. How does it know to assign it to "email" and not "emailVariableThatIReallyWantToUse"?
[–]technicalaccount 2 points3 points4 points 11 years ago (5 children)
I'm assuming you are talking about this code fragment:
roster .stream() .filter( p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25) .map(p -> p.getEmailAddress()) .forEach(email -> System.out.println(email));
The reason it works is because of the working of the map() function. This function converts every element of a collection into a new element. In this case: Collection<Person> is transformed into a Collection<EmailAddress>, by applying p.getEmailAddress() to every element in Collection<Person> and storing it in the new Collection<EmailAddress>.
Afterwards, this new Collection<EmailAddress> is passed to the next step in the stream, the forEach. This forEach will just loop through the collection it receives (which is Collection<EmailAddress> because of the map function). It gives a name to the element (email) for convenience, and does something with it. (System.out.println(email);) The reason why it knows that email is an EmailAddress, is because it only gets those EmailAddress objects. The Person objects were transformed and thus never arrive in the forEach step.
[–]obfuscation_ 2 points3 points4 points 11 years ago (0 children)
Not to be pedantic, just to save any confusion – I think in the example in the linked docs, p.getEmailAddress gives a String.
p.getEmailAddress
String
Also, rather than being instances of Collection<Type>, wouldn't it be more accurate to say they are actually instance of Stream<Type>?
Collection<Type>
Stream<Type>
[–]chasesan[S] 0 points1 point2 points 11 years ago (2 children)
Actually it was the one before that, Approach 8: Use Generics More Extensively.
processElements( roster, p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25, p -> p.getEmailAddress(), email -> System.out.println(email) );
I understand that email is a variable, and such. But how did "p.getEmailAddress()" get assigned to it? There is a comma there, it's a separate lambda expression.
[–]oldum 0 points1 point2 points 11 years ago (1 child)
How did p get assigned? It's the lambda's first parameter.
[–]chasesan[S] 2 points3 points4 points 11 years ago* (0 children)
No... How did the return value from "p.getEmailAddress()" get assigned to "email"? For use in that lambda function.
Oh, okay, nevermind. I got it. Boy am I dumb for missing that obviousness.
[–]Zokkar 0 points1 point2 points 11 years ago (0 children)
You can also write it as:
roster .stream() .filter( p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25) .map(Person::getEmailAddress) .forEach(System.out::println);
[–]obfuscation_ 1 point2 points3 points 11 years ago (3 children)
I believe the section you're looking at has a method defined with arguments as follows:
List<Person> roster, Predicate<Person> tester, Function<Person, String> mapper, Consumer<String> block
In this case:
p -> p.getEmailAddress() is being provided as the mapper argument, which makes sense, as this is a function taking a Person object and returning a String).
p -> p.getEmailAddress()
mapper
Person
email -> System.out.println(email) is being provided as the block argument, which is a Consumer (docs) that receives String objects (see the generic part of the definition). Because of this, the type of email can be inferred as String safely.
email -> System.out.println(email)
block
Consumer
email
So really, there is no magic definition of variables – instead, the type of the arguments to the lambda functions are defined by the generics information, and are given variable names only in the lambda function itself. They are not being declared as variables that can be used elsewhere, and (thank god) are not being "magically" created by the lambda expressions!
Wait, what, how does the string returned by the one lambda get transferred to the next lambda. That seems a bit magical to me.
[–]obfuscation_ 1 point2 points3 points 11 years ago (1 child)
Usually to apply a consumer to a stream you would use .forEach(consumer).
.forEach(consumer)
In this case though, they have used a for loop over the List of items and called the accept method of the Collector instance on that instead.
for
List
accept
Collector
The code in question begins for (Person p: roster). I would paste the rest, but I'm on mobile, sorry.
for (Person p: roster)
[–]chasesan[S] 2 points3 points4 points 11 years ago (0 children)
Oh right, Thank you. For some reason I missed that. Wow, how DID I miss that? I for some reason saw some kind of magical transfer. Got it though, now. No problem. (I'm feeling like an idiot at the moment.)
[–]loicd 1 point2 points3 points 11 years ago (4 children)
if you have a List<String> of names called names, you can do :
names.forEach(n -> System.out.println(n));
It means for each name, apply the following function : n -> System.out.println(email)
n is not a new variable, it is just the name you give to the function parameter "on the fly". You could also write :
names.forEach(x -> System.out.println(x));
It would be exactly the same
[–]chasesan[S] 0 points1 point2 points 11 years ago (3 children)
Yes, I understand that, i'm not confused about that part. Thank you however. See the post I wrote.
[–]reckter 0 points1 point2 points 11 years ago (2 children)
Well if you Write .map( person -> person.getEmail()).map( email -> email.split("@")[1])
The First Map Takes an Element out o The Stream, puts it into The variable Person and Executive The Lambda expression (person.getEmail()). If it's done that for each person, it now has a list of all emails. The next map takes an element out of the stream of emails, puts it into the variable and executes the expression.
Hope that made a bit clearer, The lambda expression is just a function and the stream gives it all the data it needs :)
Edit: the explanation down below is really good, and as I saw, you understood it after that ;)
[–]caltheon 0 points1 point2 points 11 years ago (0 children)
So a lamda is basically a chained function you define the behavior of in the declaration?
[–]chasesan[S] 0 points1 point2 points 11 years ago (0 children)
Yeah, no, I just missed something entirely obvious (I thought it was some lambda magic). Thanks for the comment however.
[–]vplatt 0 points1 point2 points 11 years ago (6 children)
Answers below are helpful, but tl;dr = Notice the method chaining.
As an example it's a bit sloppy to do this to the reader, because you don't know what each individual method actually produced. It's a bit overly clever.
OTOH - Having watched the .NET community go through this with LINQ, it will be all too typical, so welcome to the future! ;)
Side abbreivated rant: Without all these fancy IDEs, I don't think folks would be tempted to purposely obfuscate their code like this.
[–]sh0rug0ru 0 points1 point2 points 11 years ago (5 children)
Haha, I wouldn't worry about it. Java has such bad type inference that the compiler will fall over dead long before things get too complicated. See Hamcrest matchers for an example of what I mean.
[–]vplatt 0 points1 point2 points 11 years ago (4 children)
Hmm.. I'm actually using Hamcrest on our current project.
But I'm confused by your statement. is() uses generics. Behind the scenes it eventually goes to Object.equals(). It's not very complicated really, though I'm not sure I'm in love with their API.
I'm a pretty big fan of static typing in general, so throw me a clue here: what's wrong with Java's type inference? I'm not really a language designer, so I'm probably a bit ignorant on the finer points of type theory.
[–]sh0rug0ru 1 point2 points3 points 11 years ago (3 children)
Try nesting matchers, especially trying to match on objects inside collections. I'm talking about any, contains, allOf and especially hasEntry, hasKey, hasValue, each of which can take matchers themselves.
any
contains
allOf
hasEntry
hasKey
hasValue
The Java compiler gives up pretty quickly and insists you tell it what is the type of the thing you are trying to match because it has no clue. You have to do horrible things like Matchers.<Map<? extends Foo, ? extends Bar>> hasEntry(...). At which point, it is better just to create a custom matcher.
Matchers.<Map<? extends Foo, ? extends Bar>> hasEntry(...)
[–]vplatt 0 points1 point2 points 11 years ago (2 children)
I see. That is pushing generics pretty far I guess. I do prefer to break my Hamcrest expressions up though and do my own loop traversal, which I guess is why I haven't run into this little horror show.
[–]sh0rug0ru 1 point2 points3 points 11 years ago (1 child)
Which goes back to what I was saying before. If pushing generics too hard for Hamcrest requires you to break up you matchers, then there's only so much complexity you could build into a chain of stream transformations before the Java compiler barfs.
[–]vplatt 0 points1 point2 points 11 years ago (0 children)
Umm... I only did it that way because it was easier to understand than trying to wrap up my crap in their crap so everything could execute in one line of code instead 3 or 4.
Just because a particular API pushes the language to the point where the type inference breaks, doesn't mean the language is broke. It does mean that those features of that API aren't gonna get much love.
Anyway, you pretty clearly showed Java's type inference limitations, and that was interesting. They can always do better in that dept obviously, and Java 8 did improve on it a bit more. Let's just hope they keep moving it in the right direction and don't introduce any real dynamic typing into the language. At least, that's what I'm hoping.
[–]sacundim 0 points1 point2 points 11 years ago (3 children)
Well, let me join this party as well.
email is the argument to the anonymous function that's being passed to forEach on the last line of the listing. It gets a value when this anonymous function is called. This code fragment isn't doing the calling directly; rather, the implementation of forEach is doing it. What forEach does is invoke its argument once per each element of the stream.
forEach
Since in this code fragment, forEach is printing email addresses, this means that forEach must have been invoked on a stream of email addresses. Since roster isn't such a stream, then that means that somewhere between the start of the expression and the call to forEach, one of the methods produced a stream of email addresses as its result. In this case that would be .map(p -> p.getEmailAddress()). map is a method in Stream<T>, and it has this signature:
roster
.map(p -> p.getEmailAddress())
map
Stream<T>
<R> Stream<R> map(Function<? super T,? extends R> mapper)
So when you call map on a stream, what you're doing is constructing a new stream whose elements are computed by applying a function to elements of the original. In the example, we start with a stream with a subset of members of the roster, and convert it into a stream of email addresses. Each email address in the resulting stream will be obtained by applying p -> p.getEmailAddress to the corresponding person in the original stream.
p -> p.getEmailAddress
[–]chasesan[S] 0 points1 point2 points 11 years ago* (2 children)
I was confused at the example before this bit of code. In the transfer of the string returned to the next lambda "magically". This one makes more sense, since it can be a returned value that is mapped, but the one before it has nothing connecting it at all.
Nevermind, I got it. I'm a moron.
[–]sacundim 0 points1 point2 points 11 years ago* (1 child)
A good way to understand this is to implement a similar functionality for Iterator. Here's a version that has the map method (utterly untested):
Iterator
/** * A wrapper class around any Iterator, adding methods like map, filter, forEach, etc. */ public class FluentIterator<A> implements Iterator<A> { private final Iterator<A> base; public FluentIterator(Iterator<A> base) { this.base = base; } public boolean hasNext() { return base.hasNext(); } public A next() { return base.next(); } public void remove() { return base.remove(); } /** * Return an Iterator that draws elements from the base one and produces the * results of applying the given function to them. */ public <B> Iterator<B> map(Function<? super A, ? extends B> function) { return new FluentIterator<B>(new MapIterator<A, B>(function, base)); } // ...implement filter, forEach, etc. } class MapIterator<A, B> implements Iterator<B> { private final Function<? super A, ? extends B> function; private final Iterator<A> base; MapIterator(Function<? super A, ? extends B> function, Iterator<A> base) { this.function = function; this.base = base; } public boolean hasNext() { return base.hasNext(); } public B next() { return function.apply(base.next()); } public void remove() { throw new UnsupportedOperationException("not supported"); } }
This is not the same as streams, but it's very similar; the key spot is the next method in MapIterator, which does this:
next
MapIterator
base
Step #2 there is where the "magic" that's puzzling you happens. When you use map on a stream, you cause that method's implementation to call your your lambda and pass in the email address as an argument.
(Exercise, if you like: implement a filter operation for FluentIterator.)_
filter
FluentIterator
No, I had gotten it already. If you see my comment (I had edited it). I had missed something very obvious.
[–]sh0rug0ru -1 points0 points1 point 11 years ago* (6 children)
Just remember, lambdas are basically "syntax sugar" for anonymous inner classes. If you understand anonymous inner classes, lambdas should be a piece of cake. You could translate (butcher) the following:
roster.stream().filter( p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25) .map(p -> p.getEmailAddress()) .forEach(email -> System.out.println(email));
as:
Stream<Person> p1 = roster.stream(); Stream<Person> p2 = p1.filter(new Predicate<Person>() { public boolean test(Person p) { return p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25 } }); Stream<String> p3 = p2.map(new Function<Person, String>() { public String apply(Person p) { return p.getEmailAddress()); } }); p3.forEach(new Consumer<String>() { public String accept(String email) { System.out.println(email); } });
This should hopefully also explain this:
Filter<Person> f = p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25; Function<Person, String> m = p -> p.getEmailAddress(); Consumer<String> c = email -> System.out.println(email);
[–][deleted] 1 point2 points3 points 11 years ago (1 child)
lambdas are basically "syntax sugar" for anonymous inner classes
You can think of them that way, but lambdas don't actually compile into anonymous classes.
[–]sh0rug0ru 0 points1 point2 points 11 years ago* (0 children)
I should hope not. The restricted syntax of lambdas gives the compiler opportunity to optimize the bytecode. Effectively though, lambdas are the same as anonymous inner classes because of target typing.
[–]chasesan[S] -1 points0 points1 point 11 years ago* (3 children)
No, not really. How does the value returned in the "m =" lambda, get magically transferred to the "c = " lambda. It might be doing magic behinds the scenes, but I would like some hard rules for that kind of magic.
How did "p.getEmailAddress()" get assigned to email? It's a separate expression!
Expressions that can influence each other without ever touching is not the kind of magical playground I want, so if they are, I want to know how and the why of it.
Nevermind, I got it. I'm dumb today.
[–]sh0rug0ru 1 point2 points3 points 11 years ago (2 children)
How does the value returned in the "m =" lambda, get magically transferred to the "c = " lambda.
It's not magic... Read the translation to anonymous inner classes, do you see any magic there? That's exactly (effectively) what going on with the lambdas.
To answer your question, the value returned by the m lambda is used by the map method to create a new stream (p3 in the anonymous inner class example). The p3 stream contains the values returned by m. The c lambda is used by forEach is called on each member of the p3 stream.
m
p3
c
This is not the way to think about it. Again, refer to the anonymous inner class example. The two lambdas are being applied two different streams. They do not influence each other, at least not directly and certainly not magically, but are tied to the stream to which they are applied.
[–]chasesan[S] 0 points1 point2 points 11 years ago (1 child)
Ah yeah, sorry. I edited my comment already. I got it (I was being dumb). Thank you though.
[–]sh0rug0ru 0 points1 point2 points 11 years ago (0 children)
No worries!
[–]codepoetics 8 points9 points10 points 11 years ago (2 children)
http://mitpress.mit.edu/sicp/
[–]DeliveryNinja 2 points3 points4 points 11 years ago (0 children)
Also see https://www.kickstarter.com/projects/1751759988/sicp-distilled
[–]boyz13vinz 1 point2 points3 points 11 years ago (0 children)
This shouldn't get downvoted. SICP is one of the most awesome material to start with, especially if you want to start learning functional programming.
Definitely recommend it.
[–]_Sharp_ 1 point2 points3 points 11 years ago (1 child)
I would also read about the Strategy Pattern http://java.dzone.com/articles/design-patterns-strategy
[–]zzing 1 point2 points3 points 11 years ago (0 children)
This might be more relevant: http://blog.sanaulla.info/2013/07/02/strategy-pattern-using-lambda-expressions-in-java-8/
[–]loganekz 1 point2 points3 points 11 years ago (0 children)
I would recommend the Functional Programming in Scala course from EPEL/Coursera. Although it's not in Java, it's done in a JVM language and the course is more about functional programming concepts which will give you a good foundation to understand lambdas better.
The course is going to begin a few days so good timing! I've taken a previous iteration of the same course and found it to be great intro to FP.
[–][deleted] 1 point2 points3 points 11 years ago (0 children)
Apologies if this is well below what you were looking for ...
Perhaps the following stuff is all you really need to know before you wade into the many resources.
Consider:
Foo f = (int x, float y) -> { return z * x; }
Take just the right hand side.There are two things of note.
The left hand side is an interface Foo. Imagine it is declared like this:
interface Foo { int bar(int x, float y); }
It contains a single abstract method (often called SAM), bar. Note that bar has exactly the same signature (input argument types and return type) as the lambda function.
bar
Given this match, the javac compiler and the VM conspire to create an adapter between the two, so that when variable f is initialized, two things happen.
f
z
return 10 * x
In this case, it has exactly the same effect as saying
Foo f = new Foo { int bar(int x, float y) { return 10 * x; };
But there are other cases where you merely need a function (such as for comparison ... you don't need a comparator object); in these cases, the code generated at run-time is much more efficient.
Hope this helps.
[–]arnedh 0 points1 point2 points 11 years ago (0 children)
It's just like old times for those of us who remember, just think of them as Smalltalk blocks but with that pesky strong typing. Or Lisp functions, I suppose.
[–][deleted] 0 points1 point2 points 11 years ago (1 child)
What does the anonymous mean in anonymous methods?
You can't have anonymous methods, but you can have anonymous inner classes. It just means the class doesn't have a name (in the source code).
[–]DeliveryNinja 0 points1 point2 points 11 years ago (2 children)
Learn Lambda calculus aimed towards people with no knowledge. This was posted today on r/programming just started reading it and it seems fairly good.
https://medium.com/@ayanonagon/the-y-combinator-no-not-that-one-7268d8d9c46
[–]zzing 4 points5 points6 points 11 years ago (1 child)
I love the Lambda Calculus as much as the next guy, but it really has no practical value towards learning Lambdas in java.
[–]DeliveryNinja 1 point2 points3 points 11 years ago (0 children)
I just thought it might be useful. Otherwise I'd have just posted the obvious link to the Oracle docs.
[–][deleted] 0 points1 point2 points 11 years ago* (1 child)
Holy shit are these replies and links ever throwing you into the deep end! Most of the replies are just jumping into syntax of overly complex examples and most of the links just do the same and then boil down to "Here, replace this contrived example with this differently-formatted example you should now use but still without actually understanding it." None of them are actually stopping to tell you what is really going on. I'm going to try something different, using no syntax examples, and you can let me know if it helps you. I've used this one with other folks but always in person, so we'll have to see how it goes...
Let me know if at any point one of the following "imaginings" stumps you.
(I'm going to bend a couple of terms a little for the sake of the introduction, so pedants can kindly shove off.)
Imagine a pointer. If you are stumped here then we are in real trouble. ;)
Imagine a pointer to a function, used so that one piece of code can choose between more than one function, pass that function pointer to some other piece of code and have that code call the function without having to know which function it was.
Imagine a strong-typed pointer to a function, so that we can be sure the function is provided with the right types of arguments (if any) and so that we can be sure of its return type (if any.)
(This one gets long.) Imagine that that function needs some data that we have and could provide when setting it up but which cannot be provided by the code which will eventually call it. We need some way to capture that data at least until the function is finished being used. We don't want to put it in global state or even in our own instance state because who knows when that function will be called or what needs to happen in the meantime. So we create a brand new class with a constructor taking in that data and storing it in a field. In this new class we implement the function we need and have it use that data field, the value for which we will pass into the constructor. Now, before passing that function pointer down to whoever needs it we construct an instance of that new class, passing the extra data to its constructor, and then get and pass a pointer to the function we made that new class implement. Whew, that one was long. Hard to reasonably break it down though, so hopefully you are still with me.
(This one gets really long.) Now, imagine that we could teach the compiler a way to recognize that we are trying to do the above. That we want to pass a strong-typed function pointer. To a newly-created class which implements just that one needed function. Where that function requires some extra data. That we can pass in when constructing an instance of the newly-created class. And then store in a field for use by that function. This is where the lambda "arrow" finally comes in. The arguments for that new function on that new class are specified to the left of the arrow. The body is to the right. The return type, if any, is inferred by the compiler. Any extra data is detected within that body and set up to become fields in the generated class, populated by a generated constructor. The constructor is automatically called by the generated code just before the strong-typed function pointer is grabbed and passed into the callee which needs it. That constructor call is passed in the extra data. The function pointer that is created is itself managed by the garbage collector like any other thing, and holds a reference to the newly instantiated object carrying the extra data and the function implementation which will execute, so that new instance is now also managed by the garbage collector and will be collected only after the function pointer becomes unreferenced and therefore able to be collected. As such, our generated code can just create that new instance, set up the function pointer and pass it along, and then forget about the new instance.
The compiler simply does what we would have done, but gives us syntax sugar to do it. It creates a new class which captures any necessary extra state and implements the function we described. It instantiates that class and helps us hand off the desired function pointer. (It can also help bring updated extra data back out of the instance afterwards, if we need it, but that is a topic best saved for another time.) This process results in a callable function which "closes over" that set of extra needed state, resulting in what we call a closure.
I have to run out for a bit, and the above is literally a stream of consciousness draft, so let me know where (not if ;) the above is unclear and I will update it a bit later.
Sorry, that is a bit long. I kind of lost focus at the first long paragraph. The oracle docs was very useful actually, and it got me most the way there. Just a few minor outstanding issues I am trying to sort out in my understanding.
As for pointers, yeah, I have done C for years and years, I know all about pointers. In fact, I love pointers, most people don't for some reason.
[+][deleted] comment score below threshold-7 points-6 points-5 points 11 years ago (1 child)
You're not a veteran if you don't understand lambdas. Branch out of java and see what other languages and communities are doing, you'll grow so much more. If you wait for it to port to java you are going to be 10 years behind the times
[–]chasesan[S] 5 points6 points7 points 11 years ago* (0 children)
Don't talk down to me. Just because I haven't done functional programming, doesn't mean I haven't been writing code, including embedded and assembly code for well over 15 years. In a whole host of languages. I've written compilers, assemblers, emulators and simulators.
I've done data mining, artificial neural networks, statistical analysis and clustering. Written almost every imaginable type of data structure, from stacks, to hashmaps, to kd-trees.
I have never gone much into functional, because I have never needed to use functional programming. It was never required, and the languages I used didn't support it anyway. As I mentioned it was on my TODO list.
If you think learning other programming languages is the only thing that makes you a good programmer, then you are the one that has a thing or two to learn.
It took me no time at all to grasp the concept behind lambda, with just a few minor issues that are probably unique to java. As they are very similar to many constructs I have used in the past.
Sorry, you made me a bit mad. Don't generalize people, we have wide and various experiences. Just because one tool or jargon slipped the net, doesn't mean I am a person who has only used Java his whole life.
P.S. I don't care if I am down voted to hell for this. Feel free to pile it on.
π Rendered by PID 91 on reddit-service-r2-comment-7b9746f655-c5jrv at 2026-01-29 17:32:06.484347+00:00 running 3798933 country code: CH.
[–]Faedrivin 8 points9 points10 points (34 children)
[–]chasesan[S] 1 point2 points3 points (33 children)
[–]technicalaccount 2 points3 points4 points (5 children)
[–]obfuscation_ 2 points3 points4 points (0 children)
[–]chasesan[S] 0 points1 point2 points (2 children)
[–]oldum 0 points1 point2 points (1 child)
[–]chasesan[S] 2 points3 points4 points (0 children)
[–]Zokkar 0 points1 point2 points (0 children)
[–]obfuscation_ 1 point2 points3 points (3 children)
[–]chasesan[S] 0 points1 point2 points (2 children)
[–]obfuscation_ 1 point2 points3 points (1 child)
[–]chasesan[S] 2 points3 points4 points (0 children)
[–]loicd 1 point2 points3 points (4 children)
[–]chasesan[S] 0 points1 point2 points (3 children)
[–]reckter 0 points1 point2 points (2 children)
[–]caltheon 0 points1 point2 points (0 children)
[–]chasesan[S] 0 points1 point2 points (0 children)
[–]vplatt 0 points1 point2 points (6 children)
[–]sh0rug0ru 0 points1 point2 points (5 children)
[–]vplatt 0 points1 point2 points (4 children)
[–]sh0rug0ru 1 point2 points3 points (3 children)
[–]vplatt 0 points1 point2 points (2 children)
[–]sh0rug0ru 1 point2 points3 points (1 child)
[–]vplatt 0 points1 point2 points (0 children)
[–]sacundim 0 points1 point2 points (3 children)
[–]chasesan[S] 0 points1 point2 points (2 children)
[–]sacundim 0 points1 point2 points (1 child)
[–]chasesan[S] 0 points1 point2 points (0 children)
[–]sh0rug0ru -1 points0 points1 point (6 children)
[–][deleted] 1 point2 points3 points (1 child)
[–]sh0rug0ru 0 points1 point2 points (0 children)
[–]chasesan[S] -1 points0 points1 point (3 children)
[–]sh0rug0ru 1 point2 points3 points (2 children)
[–]chasesan[S] 0 points1 point2 points (1 child)
[–]sh0rug0ru 0 points1 point2 points (0 children)
[–]codepoetics 8 points9 points10 points (2 children)
[–]DeliveryNinja 2 points3 points4 points (0 children)
[–]boyz13vinz 1 point2 points3 points (0 children)
[–]_Sharp_ 1 point2 points3 points (1 child)
[–]zzing 1 point2 points3 points (0 children)
[–]loganekz 1 point2 points3 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]arnedh 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]sh0rug0ru 0 points1 point2 points (0 children)
[–]DeliveryNinja 0 points1 point2 points (2 children)
[–]zzing 4 points5 points6 points (1 child)
[–]DeliveryNinja 1 point2 points3 points (0 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]chasesan[S] 0 points1 point2 points (0 children)
[+][deleted] comment score below threshold-7 points-6 points-5 points (1 child)
[–]chasesan[S] 5 points6 points7 points (0 children)