I have a Properties object with approximately 10k elements in it. And I want to remove entries(key/value) that their key start with a specific text. Currently, I am using this code to do so:
Properties temp = new Properties();
myProperties.keySet().forEach(key -> {
if (!key.toString().startsWith("specificText")){
temp.setProperty(key, myProperties.get(key));
}
});
myProperties = temp;
Another solution is using putAll instead of calling setProperty multiple times:
Properties temp = new Properties();
temp.putAll(myProperties.entrySet().stream()
.filter(entry -> !entry.getKey().toString().startsWith("specificText")
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
myProperties= temp;
But none of the above solutions are efficient enough for my work. I am sure there should be a better way to remove unwanted properties. Any help is greatly appreciated.
Modifying a Map’s keySet directly affects the Map itself:
myProperties.keySet().removeIf(key -> key.toString().startsWith("specificText"));
From the documentation of Map.keySet():
The set supports element removal, which removes the corresponding mapping from the map…
Related
Map<Long, Employee.status> prevStatus = empRecords.stream()
.collect(Collectors.toMap(employeeRecord::getEmloyeeID,
employeeRecord::getEmployeeStatus));
I already have the above code, I need to add a similar operation but instead of creating a new Map I want to add the result to the existing map.
prevStatus = empRecords.stream()
.collect(Collectors.**toMap**(employeeRecord::getEmloyeeID,
employeeRecord::**getUSEmployeeStatus**));
You can create a new Map and add its entries to the existing Map:
prevStatus.putAll(
empRecords.stream()
.collect(Collectors.toMap(employeeRecord::getEmloyeeID,
employeeRecord::getUSEmployeeStatus)));
Or you can use forEach instead of collect:
empRecords.stream()
.forEach(emp -> prevStatus.put(emp.getEmloyeeID (),
emp.getEmployeeStatus()));
This is expected code
empRecords.stream()
.collect(Collectors.toMap(employeeRecord::getEmloyeeID,
employeeRecord::getEmployeeStatus,(newVal,oldVal)->newVal,()->existingMap));
Where (newVal,oldVal)->newVal logic is for what if key is already present in existing Map and
existingMap is your existing map. Make sure existingMap is not null. If it is null going with new HashMap what you shared in your code itself fine.
Sorry for some kind of theoretical question, but I'd like to find a way of quick reading someone else's functional code, building chain of methods use templates.
For example:
Case 1.
When I see use of .peek method or .wireTap from Spring Integration, I primarily expect logging, triggering monitoring or just transitional running external action, for instance:
.peek(params ->
log.info("creating cache configuration {} for key class \"{}\" and value class \"{}\"",
params.getName(), params.getKeyClass(), params.getValueClass()))
or
.peek(p ->
Try.run(() -> cacheService.cacheProfile(p))
.onFailure(ex ->
log.warn("Unable to cache profile: {}", ex.toString())))
or
.wireTap(sf -> sf.handle(msg -> {
monitoring.profileRequestsReceived();
log.trace("Client info request(s) received: {}", msg);
Case 2.
When I see use of .map method or .transform from Spring Integration, I understand that I'm up to get result of someFunction(input), for instance:
.map(e -> GenerateTokenRs.builder().token(e.getKey()).phoneNum(e.getValue()).build())
or
.transform(Message.class, msg -> {
ErrorResponse response = (ErrorResponse) msg.getPayload();
MessageBuilder builder = some tranforming;
return builder.build();
})
Current case.
But I don't have such a common view to .flatMap method.
Would you give me your opinion about this, please?
Add 1:
To Turamarth: I know the difference between .map and .flatMap methods. I actively use both .map, and .flatMap in my code.
But I ask community for theirs experience and coding templates.
It always helps to study the signature/javadoc of the streamish methods to understand them:
The flatMap() operation has the effect of applying a one-to-many transformation to the elements of the stream, and then flattening the resulting elements into a new stream.
So, typical code I expect, or wrote myself:
return someMap.values().stream().flatMap(Collection::stream)
The values of that map are sets, and I want to pull the entries of all these sets into a single stream for further processing here.
In other words: it is about "pulling out things", and getting them into a stream/collection for further processing.
I've found one more use template for .flatMap.
Let's have a look at the following code:
String s = valuesFromDb
.map(v -> v.get(k))
.getOrElse("0");
where Option<Map<String, String>> valuesFromDb = Option.of(.....).
If there's an entry k=null in the map, then we'll get null as a result of code above.
But we'd like to have "0" in this case as well.
So let's add .flatMap:
String s = valuesFromDb
.map(v -> v.get(k))
.flatMap(Option::of)
.getOrElse("0");
Regardless of having null as map's value we will get "0".
I have a list of instances where I need to create another list of instances using the instances in the first list.
As the example shown below, I can use a foreach or a for loop. Is there a better way to do this more efficiently?
List<Mesage> messages;
List<ArchMessage> archMessages = new ArrayList<>();
for(Message message : messages) {
archMessages.add(new ArchMessage(message));
}
You can use Java 8 Streams:
List<ArchMessage> archMessages =
messages.stream()
.map(message -> new ArchMessage(message))
.collect(Collectors.toList());
or
List<ArchMessage> archMessages =
messages.stream()
.map(ArchMessage::new)
.collect(Collectors.toList());
If you're unable to use streams from Java 8, Apache Commons Collections library provides the following:
http://commons.apache.org/proper/commons-collections/
Collection<ArchMessage> archMessages = CollectionUtils.collect(messages, new Transformer() {
public Object transform(Object o) {
return new ArchMessage((Mesage) o);
}
});
That's as efficient as it gets but let's say your code could benefit from parallelism then using the streams API would be ideal as we can get parallelism for free
by using parallelStream e.g.
List<ArchMessage> resultSet = messages.parallelStream()
.map(ArchMessage::new)
.collect(Collectors.toList());
Other than that your current approach seems good and readable.
Feedback to your recherche:
I would recommend to don't use a foreach. It will throw your efficient down cause of an inner request at each. I would recommend to use a for each time..
This is under multi-threading
I have read topics about HashMap and cannot find relevant questions/answers
The code:
private Map<String, String> eventsForThisCategory;
...
Map<String, String> getEventsForThisCategory() {
if (eventsForThisCategory == null) {
Collection<INotificationEventsObj> notificationEvents = notificationEventsIndex.getCategoryNotificationEvents(getCategoryId());
eventsForThisCategory = new HashMap<String, String>();
for(INotificationEventsObj notificationEvent : notificationEvents) {
eventsForThisCategory.put(notificationEvent.getNotificationEventID(), notificationEvent.getNotificationEventName());
}
logger.debug("eventsForThisCategory is {}", eventsForThisCategory);
}
return eventsForThisCategory;
}
The output:
app_debug.9.log.gz:07 Apr 2016 13:47:06,661 DEBUG [WirePushNotificationSyncHandler::WirePushNotification.Worker-1] - eventsForThisCategory is {FX_WIRE_DATA=Key Economic Data, ALL_FX_WIRE=All, ALL_FX_WIRE=All, FX_WIRE_HEADLINES=Critical Headlines}
How is it possible?
I am quite sure that your map won't have two equal keys at the same time. What you see is an effect of modifying the map while iterating iver it (in toString()). When the second "ALL_FX_WIRE" is written, the first one won't be present in the map any more.
You already know that HashMap is not threadsafe. Plus eventsForThisCategory can get modified by another thread while eventsForThisCategory.toString() is running. So this has to be expected.
Make sure eventsForThisCategory is not modified by multiple threads at the same time (or switch to ConcurrentHashMap), and make sure it is not modified while toString() is running (it is called when you create the debug output).
HashMap is not threadSafety in multi-threading.
you can try to use Collections.synchronizedMap() to wrap you hashMap instance
or use the ConcurrentHashMap maybe better
How can i read a list of users from the configuration file in play framework?
i have tried doing something like this:
users=[{uid:123,pwd:xyz},{uid:321,pwd:abc}]
from the play application
List<Object> uids = Play.application().configuration().getList("users");
will give me this a list of objects, if I iterate through the list i get each object as
{uid=123,pwd=xyz} and {uid=321,pwd=abc}
at this point i don't know how i can elegantly get the value of the uid, i can do some hacky job as omit the first and last bracket and parse for the before after equal sign, but it would be too ugly! any idea? (the application is written in java)
thanks
A Scala implementation that avoids the deprecated getConfigList method would rely on retrieving a Seq[Configuration] as follows:
case class UserConfig(uid: Int, pwd: String)
val userConfigs: Seq[UserConfig] = configuration.get[Seq[Configuration]]("users").map { userConfig =>
UserConfig(userConfig.get[Int]("uid"), userConfig.get[String]("pwd"))
}
Since I had recently the same problem and this is still unanswered,
here is my suggestion:
List<User> users = getConfig().getConfigList("users").stream().map(
config -> new User(config.getString("uid"), config.getBoolean("pwd"))
).collect(Collectors.toList());
As far as I know there are no tuples or anything in Java, you need to use either an object or a list with two elements. I decided to go for an object here, you can also return a list.
A list of uid's sounds to me like:
# List of UID's
users=[123,456,789] // every number represents a UID
Then you can get this list as:
List<Object> uids = Play.application().configuration().getList("users");
And then do what you want with this:
for (Iterator<Object> iterator = uids.iterator(); iterator.hasNext();) {
Object object = (Object) iterator.next();
System.out.println(object);
}
Is this what you are looking for?
BTW, you can read more about Play Framework configuration options: http://www.playframework.com/documentation/2.1.0/Configuration