This question already has an answer here:
Map.of() vs. Collections.emptyMap()
(1 answer)
Closed 1 year ago.
As far as I can see, the contracts of both are identical. Seems rather pointless to implement a whole new empty set for Set.of().
I would presume the standard library implementors are aware of Collections.emptySet(), so there must be a specific reason I am not seeing. Due to the very generic method names, searching in mailing lists is impossible, so I am not sure if this was discussed.
(BTW, it seems Set.of() just uses a SetN with an empty input array, so it will probably be less efficient than emptySet() as well.)
There is a single difference "code-wise", that I am aware of.
Collections.emptySet().contains(null); // false
Set.of().contains(null); // NullPointerException
So they are not inter-changeable.
Set.of() uses a nice clean helper from ImmutableCollections which was introduced with Java 9.
Collections on the other hand was says since 1.2, and was only "adapted" to generics and such things over time.
So:
the Collections implementation is historically grown, and you would probably not be doing it like that any more today
so, when introducing the functionality in a new context, you do it in a different way.
And more importantly: all the of methods within Set are just delegating to ImmutableCollections. And then it makes no sense that of() would be implemented in a completely different way than all the other of(x) methods.
Related
How to return a singleton object for an entity, what would be more appropriate to use?
https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#singletonList-T-
https://docs.oracle.com/javase/9/docs/api/java/util/List.html#of-E-
API Support: SingletonList support sorting API which is not in the case of List.Of
Null Support: If you're planning (for some strange reason) to intentionally create a single-element list with a null element, you cannot use List:of. It will NullPointerException your face (yes, friends, "NullPointerException" can be used as verb). The same is true for Array::asList and the Stream-based approaches.
Collections::singletonList will happily create a List of null.
Performance: Throughput is slightly higher and average execution time is trivially faster for Collections::singletonList than List::of, but they offer basically identical performance.
Conclusion:
Both Collections::singletonList and List:of are great choices for creating single-element lists. If you're fortunate enough to be using a version of Java that supports both methods (9 and above), then I recommend going with List:of for its ease of use, readability, and better-documented immutability.
Either. No way to make a more specific recommendation without a specific situation.
Or take Dr. Joshua Bloch’s advice in Effective Java and use an enum. See tutorial on enums by Oracle.
public enum ExampleSingleton {
INSTANCE;
}
Usage:
System.out.println(
ExampleSingleton.INSTANCE
);
You can add a constructor and methods to that enum class, if needed. An enum can also implement interfaces. And, new in Java 16, an enum can be defined locally.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I'm wondering what the best way is in Java 8 to work with all the values of an enum. Specifically when you need to get all the values and add it to somewhere, for example, supposing that we have the following enum:
public enum Letter {
A, B, C, D;
}
I could of course do the following:
for (Letter l : Letter.values()) {
foo(l);
}
But, I could also add the following method to the enum definition:
public static Stream<Letter> stream() {
return Arrays.stream(Letter.values());
}
And then replace the for from above with:
Letter.stream().forEach(l -> foo(l));
Is this approach OK or does it have some fault in design or performance? Moreover, why don't enums have a stream() method?
I'd go for EnumSet. Because forEach() is also defined on Iterable, you can avoid creating the stream altogether:
EnumSet.allOf(Letter.class).forEach(x -> foo(x));
Or with a method reference:
EnumSet.allOf(Letter.class).forEach(this::foo);
Still, the oldschool for-loop feels a bit simpler:
for (Letter x : Letter.values()) {
foo(x);
}
Three questions: three-part answer:
Is it okay from a design point of view?
Absolutely. Nothing wrong with it. If you need to do lots of iterating over your enum, the stream API is the clean way to go and hiding the boiler plate behind a little method is fine. Although I’d consider OldCumudgeon’s version even better.
Is it okay from a performance point of view?
It most likely doesn’t matter. Most of the time, enums are not that big. Therefore, whatever overhead there is for one method or the other probably doesn’t matter in 99.9% of the cases.
Of course, there are the 0.1% where it does. In that case: measure properly, with your real-world data and consumers.
If I had to bet, I’d expect the for each loop to be faster, since it maps more directly to the memory model, but don’t guess when talking performance, and don’t tune before there is actual need for tuning. Write your code in a way that is correct first, easy to read second and only then worry about performance of code style.
Why aren’t Enums properly integrated into the Stream API?
If you compare Java’s Stream API to the equivalent in many other languages, it appears seriously limited. There are various pieces that are missing (reusable Streams and Optionals as Streams, for example). On the other hand, implementing the Stream API was certainly a huge change for the API. It was postponed multiple times for a reason. So I guess Oracle wanted to limit the changes to the most important use cases. Enums aren’t used that much anyway. Sure, every project has a couple of them, but they’re nothing compared to the number of Lists and other Collections. Even when you have an Enum, in many cases you won’t ever iterate over it. Lists and Sets, on the other hand, are probably iterated over almost every time. I assume that these were the reasons why the Enums didn’t get their own adapter to the Stream world. We’ll see whether more of this gets added in future versions. And until then you always can use Arrays.stream.
My guess is that enums are limited in size (i.e the size is not limited by language but limited by usage)and thus they don't need a native stream api. Streams are very good when you have to manipulate transform and recollect the elements in a stream; these are not common uses case for Enum (usually you iterate over enum values, but rarely you need to transform, map and collect them).
If you need only to do an action over each elements perhaps you should expose only a forEach method
public static void forEach(Consumer<Letter> action) {
Arrays.stream(Letter.values()).forEach(action);
}
.... //example of usage
Letter.forEach(e->System.out.println(e));
I think the shortest code to get a Stream of enum constants is Stream.of(Letter.values()). It's not as nice as Letter.values().stream() but that's an issue with arrays, not specifically enums.
Moreover, why don't enums have a stream() method?
You are right that the nicest possible call would be Letter.stream(). Unfortunately a class cannot have two methods with the same signature, so it would not be possible to implicitly add a static method stream() to every enum (in the same way that every enum has an implicitly added static method values()) as this would break every existing enum that already has a static or instance method without parameters called stream().
Is this approach OK?
I think so. The drawback is that stream is a static method, so there is no way to avoid code duplication; it would have to be added to every enum separately.
I was reading again Brian Goetz document on the State of Lambda where he details many of the reasons why Java needed lambda expressions.
In one of the paragraphs he wrote:
Given the increasing relevance of callbacks and other functional-style
idioms, it is important that modeling code as data in Java be as
lightweight as possible. In this respect, anonymous inner classes are
imperfect for a number of reasons, primarily:
Bulky syntax
Confusion surrounding the meaning of names and this
Inflexible class-loading and instance-creation semantics
Inability to capture non-final local variables
Inability to abstract over control flow
From this list of imperfections I believe I understand reasonably well the items (1), (2) and (4).
But I have no clue of what exactly the problems are in (3) and (5).
Can anybody out there provide any examples of how these two could be an issue when using anonymous classes?
Not all the projects I work on are yet on Java 8 and so I think it is important to understand these shortcomings and above all see clearly how things are better now with Java 8 lambdas. Also, since Brian was one of the leaders of the project lambda I thought it was worth my time to give it some thought to what he meant by this, it could lead me to an epiphany :-)
Well 5. Inability to abstract over control flow is easy.
Lambda's are great to iterate over all the elements in a collection.
aCollection.forEach( myLambda)
The old way you would have to use for loops or Iterators or something similar.
for( ....){
//same code as what's in the lambda
}
This is called internal iteration. We have to tell the collection not only what do do with each element in the collection BUT ALSO HOW TO GET EACH ELEMENT. This code iterates through all the objects in order sequentially. Sometimes that isn't the best for performance reasons.
Lambdas allow us to do external iteration. We only tell the collection what to do with each element. How each element is accessed and in what order is up to the Collection implementation to do it the most efficent way it can using internal implementation knowledge. It may even be parallel not sequential.
3. Inflexible class-loading and instance-creation semantics
Is a lower level issue with how Anonymous classes are loaded and instantiated. I will point you to this article: http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood
But basically
anonymous classes require making new class files for each one (MyClass$1 etc). This extra class has to be loaded. Lambdas don't make new class files and their byte code is created dynamically at runtime.
Future versions of Java may be able to make Lambdas differently under the hood. By generating the lambda bytecode at runtime, future versions can safely change how Lambdas get created without breaking anything
I also want to add another thing about (3). "Instance-creation" might refer to the fact that when you create an instance of an anonymous class (new ...), just like when you create an instance of any class, you are guaranteed to get a new object. So the reference guaranteed to compare unequal != to the reference to any other object.
On the other hand, for lambdas, there is no guarantee that running a lambda expression twice will evaluate to two different objects. In particular, if the lambda doesn't capture any variables, then all instances of the lambda are functionally identical. In this case, it could just allocate one object statically and use it for the duration of the program. Allocating lots of objects is not cheap, so in the cases where it can avoid creating more objects, it makes the program more efficient.
I am coding in Android a lot lately, Though I am comfortable in JAVA, but missing some
ideas about core concepts being used there.
I am interested to know whether any performance difference is there between these 2 codes.
First Method:
//Specified as member variable.
ArrayList <String> myList = new ArrayList <String>();
and using as String temp = myList.get(1);
2nd Method:
ArrayList myList = new ArrayList(); //Specified as member variable.
and using
String temp1 = myList.get(1).toString();
I know its about casting. Does the first method has great advantage over the second,
Most of the time in real coding I have to use second method because arraylist can take different data types, I end up specifying
ArrayList <Object> = new ArrayList <Object>();
or more generic way.
In short, there's no performance difference worth worrying about, if it exists at all. Generic information isn't stored at runtime anyway, so there's not really anything else happening to slow things down - and as pointed out by other answers it may even be faster (though even if it hypothetically were slightly slower, I'd still advocate using generics.) It's probably good to get into the habit of not thinking about performance so much on this level. Readability and code quality are generally much more important than micro-optimisations!
In short, generics would be the preferred option since they guarantee type safety and make your code cleaner to read.
In terms of the fact you're storing completely different object types (i.e. not related from some inheritance hierarchy you're using) in an arraylist, that's almost definitely a flaw with your design! I can count the times I've done this on one hand, and it was always a temporary bodge.
Generics aren't reified, which means they go away at runtime. Using generics is preferred for several reasons:
It makes your code clearer, as to which classes are interacting
It keeps it type safe: you can't accidentally add a List to a List
It's faster: casting requires the JVM to test type castability at runtime, in case it needs to throw a ClassCastException. With Generics, the compiler knows what types things must be, and so it doesn't need to check them.
There is a performance difference in that code:
The second method is actually slower.
The reason why:
Generics don't require casting/conversion (your code uses a conversion method, not a cast), the type is already correct. So when you call the toString() method, it is an extra call with extra operations that are unnecessary when using the method with generics.
There wouldn't be a problem with casting, as you are using the toString() method. But you could accidentally add an incorrect object (such as an array of Strings). The toString() method would work properly and not throw an exception, but you would get odd results.
As android is used for Mobiles and handheld devices where resources are limited you have to be careful using while coding.
Casting can be overhead if you are using String data type to store in ArrayList.
So in my opinion you should use first method of being specific.
There is no runtime performance difference because of "type erasure".
But if you are using Java 1.5 or above, you SHOULD use generics and not the weakly typed counterparts.
Advantages of generics --
* The flexibility of dynamic binding, with the advantage of static type-checking. Compiler-detected errors are less expensive to repair than those detected at runtime.
* There is less ambiguity between containers, so code reviews are simpler.
* Using fewer casts makes code cleaner.
It is possible to add and remove elements from an enum in Java at runtime?
For example, could I read in the labels and constructor arguments of an enum from a file?
#saua, it's just a question of whether it can be done out of interest really. I was hoping there'd be some neat way of altering the running bytecode, maybe using BCEL or something. I've also followed up with this question because I realised I wasn't totally sure when an enum should be used.
I'm pretty convinced that the right answer would be to use a collection that ensured uniqueness instead of an enum if I want to be able to alter the contents safely at runtime.
No, enums are supposed to be a complete static enumeration.
At compile time, you might want to generate your enum .java file from another source file of some sort. You could even create a .class file like this.
In some cases you might want a set of standard values but allow extension. The usual way to do this is have an interface for the interface and an enum that implements that interface for the standard values. Of course, you lose the ability to switch when you only have a reference to the interface.
Behind the curtain, enums are POJOs with a private constructor and a bunch of public static final values of the enum's type (see here for an example). In fact, up until Java5, it was considered best-practice to build your own enumeration this way, and Java5 introduced the enum keyword as a shorthand. See the source for Enum<T> to learn more.
So it should be no problem to write your own 'TypeSafeEnum' with a public static final array of constants, that are read by the constructor or passed to it.
Also, do yourself a favor and override equals, hashCode and toString, and if possible create a values method
The question is how to use such a dynamic enumeration... you can't read the value "PI=3.14" from a file to create enum MathConstants and then go ahead and use MathConstants.PI wherever you want...
I needed to do something like this (for unit testing purposes), and I came across this - the EnumBuster:
http://www.javaspecialists.eu/archive/Issue161.html
It allows enum values to be added, removed and restored.
Edit: I've only just started using this, and found that there's some slight changes needed for java 1.5, which I'm currently stuck with:
Add array copyOf static helper methods (e.g. take these 1.6 versions: http://www.docjar.com/html/api/java/util/Arrays.java.html)
Change EnumBuster.undoStack to a Stack<Memento>
In undo(), change undoStack.poll() to undoStack.isEmpty() ? null : undoStack.pop();
The string VALUES_FIELD needs to be "ENUM$VALUES" for the java 1.5 enums I've tried so far
I faced this problem on the formative project of my young career.
The approach I took was to save the values and the names of the enumeration externally, and the end goal was to be able to write code that looked as close to a language enum as possible.
I wanted my solution to look like this:
enum HatType
{
BASEBALL,
BRIMLESS,
INDIANA_JONES
}
HatType mine = HatType.BASEBALL;
// prints "BASEBALL"
System.out.println(mine.toString());
// prints true
System.out.println(mine.equals(HatType.BASEBALL));
And I ended up with something like this:
// in a file somewhere:
// 1 --> BASEBALL
// 2 --> BRIMLESS
// 3 --> INDIANA_JONES
HatDynamicEnum hats = HatEnumRepository.retrieve();
HatEnumValue mine = hats.valueOf("BASEBALL");
// prints "BASEBALL"
System.out.println(mine.toString());
// prints true
System.out.println(mine.equals(hats.valueOf("BASEBALL"));
Since my requirements were that it had to be possible to add members to the enum at run-time, I also implemented that functionality:
hats.addEnum("BATTING_PRACTICE");
HatEnumRepository.storeEnum(hats);
hats = HatEnumRepository.retrieve();
HatEnumValue justArrived = hats.valueOf("BATTING_PRACTICE");
// file now reads:
// 1 --> BASEBALL
// 2 --> BRIMLESS
// 3 --> INDIANA_JONES
// 4 --> BATTING_PRACTICE
I dubbed it the Dynamic Enumeration "pattern", and you read about the original design and its revised edition.
The difference between the two is that the revised edition was designed after I really started to grok OO and DDD. The first one I designed when I was still writing nominally procedural DDD, under time pressure no less.
You can load a Java class from source at runtime. (Using JCI, BeanShell or JavaCompiler)
This would allow you to change the Enum values as you wish.
Note: this wouldn't change any classes which referred to these enums so this might not be very useful in reality.
A working example in widespread use is in modded Minecraft. See EnumHelper.addEnum() methods on Github
However, note that in rare situations practical experience has shown that adding Enum members can lead to some issues with the JVM optimiser. The exact issues may vary with different JVMs. But broadly it seems the optimiser may assume that some internal fields of an Enum, specifically the size of the Enum's .values() array, will not change. See issue discussion. The recommended solution there is not to make .values() a hotspot for the optimiser. So if adding to an Enum's members at runtime, it should be done once and once only when the application is initialised, and then the result of .values() should be cached to avoid making it a hotspot.
The way the optimiser works and the way it detects hotspots is obscure and may vary between different JVMs and different builds of the JVM. If you don't want to take the risk of this type of issue in production code, then don't change Enums at runtime.
You could try to assign properties to the ENUM you're trying to create and statically contruct it by using a loaded properties file. Big hack, but it works :)