Javascript Objects but for Java - java

How do I write this in Java?
//js
const hello = {
foo: "bar",
test: "world",
name: "david"
}
I want have a very long object, then refer it back like hello[test] or hello[foo]
I've heard of hashmaps, but you can only create an empty one and then add elements into it.
I've got a really long list like that in js. How can I copy those into Java? Doing .put() one by one would take forever, and I don't think that's efficient.
And even if someone wrote a script to turn uwu: "owo" into hello.put("uwu", "owo");, it'd be ugly in the code with a big block of hello.put()s.
I also don't want to create a new file for that (it only has around 34 lines) and want to keep it in the code. Also, because I have three more like these with 20-40 keys and values in each of them, I don't want to create three extra files with just 30 lines in them. I also don't want to go into complexity of reading them.
Oh and also, I won't be changing the hashmap btw, just reading data like a constant.
In summary, can I do something like this in Java for long lists without doing .put()?
public HashMap<String, String> hello = new HashMap<String, String>(
"foo": "bar",
"test": "world",
"name": "david",
"uwu": "owo"
);
And refer to them like hello["name"]? I also don't want this thing.
public HashMap<String, String> hello = new HashMap<String, String>();
hello.put("foo", "bar");
hello.put("test", "world");
hello.put("name", "david");
hello.put("uwu", "owo");
//for 25 more lines
public HashMap<String, String> hello2 = new HashMap<String, String>();
hello2.put("stuff", "thing");
//... for around 20 more lines
//repeat for 3 more hashmaps

In modern Java (14 and later) you can use a record:
record Hello(String foo, String test, String world) { }
and create an instance like this:
final Hello hello = new Hello("bar", "world", "david");
You access the values like:
System.out.print(hello.foo());
Using a record has the advantage that your data is statically typed -- you can't mistype a key, or forget to remove usages of a key you've removed from the record.

IN Java 14 and beyond, I would recommand using a record, as explained in the other answer.
It's the safest and also probably the most efficient way.
For Java 9 to 14, you may use Map.of("hello", "world", "foo", "bar");.
But you may not be able to go beyond a certain number of key/value pairs.
For java 8 and below, or if you exceed the number of arguments allowed with Map.of, you don't have other choice than create an empty map and put key/value pairs one by one.
Note however that, performances aren't necessarily going to be worse.
You can of course reimplement your own version of Map.of with variable number of arguments.

Since you need something constant like, you can save those values in files and read from those files. For example save data in file in json format:
{
"foo": "bar",
"test": "world",
"name": "david"
}
Then parse this file to a Map.
public class Main {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map = mapper.readValue(ClassLoader.getSystemResourceAsStream("constants.json"), Map.class);
map.forEach((k, v) -> System.out.println(k + " -> " + v));
}
}
This example uses reading file as project resource and uses ObjectMapper to parse json to Map, but you can use any other tool for the same effect. If the data format is simple enough(string key to string value, no nested arrays, objects and such) you can save it in even simpler format and do the read, parse, add to map manually.

Related

Converting Linq queries to Java 8

Im traslating a old enterprise App who uses C# with Linq queries to Java 8. I have some of those queries who I'm not able to reproduce using Lambdas as I dont know how C# works with those.
For example, in this Linq:
from register in registers
group register by register.muleID into groups
select new Petition
{
Data = new PetitionData
{
UUID = groups.Key
},
Registers = groups.ToList<AuditRegister>()
}).ToList<Petition>()
I undestand this as a GroupingBy on Java 8 Lambda, but what's the "select new PetitionData" inside of the query? I don't know how to code it in Java.
I have this at this moment:
Map<String, List<AuditRegister>> groupByMuleId =
registers.stream().collect(Collectors.groupingBy(AuditRegister::getMuleID));
Thank you and regards!
The select LINQ operation is similar to the map method of Stream in Java. They both transform each element of the sequence into something else.
collect(Collectors.groupingBy(AuditRegister::getMuleID)) returns a Map<String, List<AuditRegister>> as you know. But the groups variable in the C# version is an IEnumerable<IGrouping<string, AuditRegister>>. They are quite different data structures.
What you need is the entrySet method of Map. It turns the map into a Set<Map.Entry<String, List<AuditRegister>>>. Now, this data structure is more similar to IEnumerable<IGrouping<string, AuditRegister>>. This means that you can create a stream from the return value of entry, call map, and transform each element into a Petition.
groups.Key is simply x.getKey(), groups.ToList() is simply x.getValue(). It should be easy.
I suggest you to create a separate method to pass into the map method:
// you can probably came up with a more meaningful name
public static Petition mapEntryToPetition(Map.Entry<String, List<AuditRegister>> entry) {
Petition petition = new Petition();
PetitionData data = new PetitionData();
data.setUUID(entry.getKey());
petition.setData(data);
petition.setRegisters(entry.getValue());
return petition;
}

How to read out of a yml map<string, Map<string, string>> structure with cfg4j?

I have the following yml file
test-files:
testSets:
smoke:
- "a" : "b"
video:
- "c" : "d"
I am trying to read this out using cfg4j but I don't seem to get the interface right.
What I want to get is a map with all the testSets with all the data for that set inside it.
So e.g. if I have the following map construction:
map<String, Map<String, String>>
I want to have in the first string the value smoke, in the second one a and the last one b etc.
The interface that I already tried to us for this is:
interface TestSets{
Map<String, Map<String, String>> testSets;
}
But this doesn't work.
Has someone any idea about how to read this out using the cfg4j lib?

Create a stream of the values in maps that are values in another map in Java

Sorry about the title of the question; it was kind of hard for me to make sense of it. If you guys have a better title, let me know and I can change it.
I have two types of objects, Bookmark and Revision. I have one large Map, like so:
Map<Long, Bookmark> mapOfBookmarks;
it contains key: value pairs like so:
1L: Bookmark1,
2L: Bookmark2,
...
Each Bookmark has a 'getRevisions()' method that returns a Map
public Map<Long, Revision> getRevisions();
I want to create a Stream that contains all revisions that exist under mapOfBookmarks. Essentially I want to do this:
List<Revision> revisions = new ArrayList<>();
for (Bookmark bookmark : mapOfBookmarks.values()) { // loop through each bookmark in the map of bookmarks ( Map<Long, Bookmark> )
for (Revision revision : bookmark.getRevisions().values()) { // loop through each revision in the map of revisions ( Map<Long, Revision> )
revisions.add(revision); // add each revision of each map to the revisions list
}
}
return revisions.stream(); // return a stream of revisions
However, I'd like to do it using the functionality of Stream, so more like:
return mapOfBookmarks.values().stream().everythingElseThatIsNeeded();
Which would essentially be like saying:
return Stream.of(revision1, revision2, revision3, revision4, ...);
How would I write that out? Something to note is that the dataset that it is looping through can be huge, making the list method a poor approach.
I'm using Windows 7 and Java 8
A flatmap is what you looking for. When you have streams contained within a stream that you wish to flatten, then flatmap is the answer,
List<Revision> all =
mapOfBookmarks.values().stream()
.flatMap(c -> c.getRevisions().values().stream())
.collect(Collectors.toList());
You are looking for the flatMap(mapper) operation:
Returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element.
In this case, we're making a Stream<Bookmark> by calling stream(), flat mapping it to the revisions of each bookmark and, finally, collecting that into a list with toList().
List<Revision> revisions =
mapOfBookmarks.values()
.stream()
.flatMap(bookmark -> boormark.getRevisions().values().stream())
.collect(Collectors.toList());
Note that your current code could also be improved by calling addAll instead of looping over each revisions:
for (Bookmark bookmark : mapOfBookmarks.values()) { // loop through each bookmark in the map of bookmarks ( Map<Long, Bookmark> )
revisions.addAll(bookmark.getRevisions().values());
}

How to serialize a complex map in java to JSON

I am facing a problem while serializing map of maps(or lists) into JSON. It can be upto any level. I am using GSON to convert map into JSON but I am not getting the desired output. Consider an example below:
Map<String, String> map = new HashMap<String, String>();
map.put("key1", "value1");
map.put("key2", new ArrayList<String>(){{add("value2");add("value3");}});
When I serialize this map, I get to the following output:
{
"key1" : "value1",
"key2" : "[value2, value3]"
}
It gets worse when I have map inside a map. The output which I want is:
{
"key1" : "value1",
"key2" : ["value2", "value3"]
}
Any idea how to get such output? I have already tried ObjectMapper and GsonBuilder.registerTypeAdapter but haven't got success so far.
Thanks in advance.
I don't think it's valid to store an ArrayList in a HashMap where a String is expected. I would've said that that code should fail, but I guess it must be succeeding, since it's not failing for you, and so what I'm assuming is happening is that when you insert it into the HashMap Java is actually calling toString() on it behind the scenes to cast it to String. So the value sitting in the HashMap is not actually an array; it was a string from the moment it was inserted. Thus, you're losing information that can't be salvaged downstream from the lossage.

looking for a smart and fast searching algorithm

lets say i have 2 arrays of the objects which are mapped to each other in the following schemna:
array1 :
String [] prog_types1 = {"Program1","Program2","Program3","Program4"};
and array2 :
String [] prog_types2 ={"SubProgram1","SubProgram2","SubProgram3","SubProgram4",
"SubProgram5","SubProgram6","SubProgram7","SubProgram8","SubProgram9","SubProgram10"};
as it understood from its names, prog_types2 is an extension for prog_types1, but has some repeated values, so the full mapping between these programs would looks liek this:
prog_types1 prog_types2
ProgramType1 SubProgramType1
ProgramType1 SubProgramType2
ProgramType1 SubProgramType7
ProgramType1 SubProgramType9
ProgramType2 SubProgramType12
ProgramType2 SubProgramType7
ProgramType2 SubProgramType9
ProgramType3 SubProgramType1
ProgramType3 SubProgramType2
ProgramType3 SubProgramType21
ProgramType3 SubProgramType27
ProgramType3 SubProgramType7
ProgramType5 SubProgramType12
ProgramType5 SubProgramType9
my question is : what is the best way to map these arrays to each other, from the perspective of faster processing and reuse?
I have implemented it as :
-- set of classes (class prog1 and prog2 and after put it into vector)...
-- hashtable with hashset
-- possible one more array
the way i am looking for should not consist of creating the same prog2 objects again for prog1 object, as it would be in all of the ways described earlier, but map it by the index position for example or in any other way.
just lookin for a nice algorythmical way to resolve it...
thanks in advance
p.s. it should be used within 1 package only between couple of classes and the main use of it would be a population of the prog2 types values based on the prog1 type value
p.s.2 java7
Using MultiMap from Guava Libraries, you could say:
Multimap<String, String> mmap = ArrayListMultimap.create();
mmap.put("Program1", "SubProgramType1");
mmap.put("Program1", "SubProgramType2");
// etc.
mmap.get("Program1")
would look like:
[SubProgramType1, SubProgramType2, SubProgramType7, SubProgramType9]
BTW, Hashtable is not used now for hashed collections, has been superceded by HashMap :)
IMO the best way would be a:
Map<String, List<String>> programs = new HashMap<String, List<String>>();
with the strings in the first list as keys and the corresponding subprograms composing the value list. Now the mapping is obvious:
ProgramType1 -> [SubProgramType1, SubProgramType2, SubProgramType7, SubProgramType9]
ProgramType2 -> [SubProgramType12, SubProgramType7, SubProgramType9]
ProgramType3 -> [SubProgramType1, SubProgramType2, SubProgramType21, SubProgramType27, SubProgramType7]
ProgramType5 -> [SubProgramType12, SubProgramType9]
Guava ListMultimap, that gives List<E>, not Collection<E> - little more pleasant.
private ListMultimap<String,Something> stuff = ArrayListMultimap.create();
// ...
public void add(String key, Something item) {
stuff.put(key, item);
}
public List<Something> get(String key) {
// might as well use the Lists convenience API while we're at it.
return Lists.newArrayList(stuff.get(key));
}
http://www.coffee-bytes.com/2011/12/22/guava-multimaps
btw, since i need :
-- separately use Program1 values
-- separately use SubProgram1 values
-- populate SubProgram1 values based on Program1 value
the easiest solution here would be to declare a double dimensional array with all the dublicates (as it dysplayed in full map schema) and for 1) and 2) populate data from it using non repeating algorythm and 3) loop cycle from 2nd dimension
so no reason to declare 3 objects, huge memory save and nice approach.
i am giving myself a star for it:)

Categories

Resources