Related
I'm trying to implement an action/reaction system in Java.
For that, I need to have all my methods stock in a container so I can easily call the response I need with the return of the action I want.
Being a C ++ developer and new to Java my first intuition was to create an array of function pointers (or at least reproduce it) so I tried to used anonymous subclasses. But didn't get the result I was looking for.
So I tried with lambdas, here is a sample of what I'm trying to do.
public class Test {
public Map<Integer, Vector<String>> actions = new HashMap<>();
public Map<Integer, Integer> responses = new HashMap<>();
public Test() {
Vector<String> v= new Vector<String>();
actions.put(0, action0());
actions.put(1, action1());
responses.put(0, response0(Vector<String>)); // How can I leave aside this argument which I don't know at this point ?
responses.put(1, response1(Vector<String>));
}
public Vector<String> action0() {...}
public Vector<String> action1() {...}
// This methods takes actions return as argument
public Integer response0 (Vector<String>) {...}
public Integer response1 (Vector<String>) {...}
public void run() {
// When I run, I want to be able to launch any of my responses with any of my actions return
responses.get(0)
}
}
Am I at least trying a good way to solve this problem ?
Thanks a lot
Your code has a few flaws, so I'll assume that getHashtag() and action1() were supposed to be the same, and similar for the other three.
Also, I'll assume that the second responses.put() should have been key 1, not 0. Also, the parameter to your responseX() methods need a name.
Anyway, you need a functional interface, so you can give the responseX() methods as Method References.
In your case, the responseX() methods take a Vector<String> as parameter, and returns an Integer, so the functional interface would be Function<Vector<String>, Integer>.
You can then build a map of those methods, to be executed later.
public Test() {
// Here we can build map of response methods first, if we like, even though Vectors don't exist yet
Map<Integer, Function<Vector<String>, Integer>> responseMethods = new HashMap<>();
responseMethods.put(0, this::response0);
responseMethods.put(1, this::response1);
// Now we build the action map of Vectors
Map<Integer, Vector<String>> actions = new HashMap<>();
actions.put(0, action0());
actions.put(1, action1());
// At this time, we can now execute the referenced methods to get the actual responses
Map<Integer, Integer> responses = new HashMap<>();
for (Integer key : actions.keySet()) {
Vector<String> v = actions.get(key);
Function<Vector<String>, Integer> responseMethod = responseMethods.get(key);
Integer response = responseMethod.apply(v);
responses.put(key, response);
}
}
public Vector<String> action0() {...}
public Vector<String> action1() {...}
public Integer response0(Vector<String> v) {...}
public Integer response1(Vector<String> v) {...}
You can even defer the execution of the action methods if you want:
public Test() {
// Here we can build map of response methods first, if we like, even though Vectors don't exist yet
Map<Integer, Function<Vector<String>, Integer>> responseMethods = new HashMap<>();
responseMethods.put(0, this::response0);
responseMethods.put(1, this::response1);
// Now we build the action map of Vectors
Map<Integer, Supplier<Vector<String>>> actionMethods = new HashMap<>();
actionMethods.put(0, this::action0);
actionMethods.put(1, this::action1);
// At this time, we can now execute the referenced methods to get the actual responses
Map<Integer, Integer> responses = new HashMap<>();
for (Integer key : actionMethods.keySet()) {
Supplier<Vector<String>> actionMethod = actionMethods.get(key);
Function<Vector<String>, Integer> responseMethod = responseMethods.get(key);
Vector<String> v = actionMethod.get();
Integer response = responseMethod.apply(v);
responses.put(key, response);
}
}
I'm a developer transitioning from C++ to Java.So I still dont have all the expertise to getting stuff done the Java Way.
I have the following class
class Site
{
String siteName;
Integer siteId;
Integer views;
Integer searches;
}
I maintain 2 maps to search over the objects of this class(using sitename or siteid)
HashMap<String, Site> siteNameToSiteMap;
HashMap<Integer, Site> siteIdToSiteMap;
However going forward, I have to add a one more field called parentBrand to the class Site. This will force me to create another Map to be able to search over it.
HashMap<String, Site> parentBrandToSiteMap;
Such "indexing" variables might increase going ahead and thus also increase the number of maps I maintain.
I remember using Boost Multi-indexed container while solving a similar issue while developing in C++. Is there an equivalent well supported, well documented library in Java that I can use. If no, is there a way I can refactor my code to solve my problem.
I'm surprised that there isn't a version of something like the boost multi-index containers available. (Maybe there is somewhere...) But its not too hard to hook up your own version in Java.
A rough, but working, version might look like this:
The basic site object
I've used a slightly different Site object, just to keep things simple (and because I didn't have access to this post on the bus...)
public class Site {
Integer id;
String name;
String rating;
// .. Constructor and toString removed for brevity
}
A wrapped version
I'm going to introduce some workhorse classes later, but they're a little ugly. This is just to show what the final interface would look like once you've wrapped it up a little:
class SiteRepository {
private final MultiMap<Site> sites = new MultiMap<>();
public final AbstractMap<String, Site> byName = sites.addIndex((site)->site.name);
public final AbstractMap<Integer,Site> byId = sites.addIndex((site)->site.id);
public final AbstractMap<String,List<Site>> byRating = sites.addMultiIndex((Site site)->site.rating);
public void add(Site s) { sites.add(s); }
}
SiteRepository repo = new SiteRepository();
repo.add(...);
Site site = repo.byId.get(1234);
repo.byId.forEach((Integer id, Site s) -> System.err.printf(" %s => %s\n", id, s));
The MultiMap core
Probably should be called MultiIndex since MultiMap means something else...
public static class MultiMap<V> {
public static class MultiMapIndex<K,V> extends AbstractMap<K,V> {
#Override
public Set<Entry<K, V>> entrySet() {
return map.entrySet();
}
HashMap<K,V> map = new HashMap<>();
}
public <K> MultiMapIndex<K,V> addIndex(Function<V, K> f) {
MultiMapIndex<K,V> result = new MultiMapIndex<>();
Consumer<V> e = (V v) -> result.map.put(f.apply(v), v);
mappers.add(e);
values.forEach(e);
return result;
}
public <K> MultiMapIndex<K,List<V>> addMultiIndex(Function<V, K> f) {
MultiMapIndex<K,List<V>> result = new MultiMapIndex<>();
Consumer<V> e = (V v) -> {
K key = f.apply(v);
List<V> list = result.map.get(key);
if (list == null) {
list = new ArrayList<>();
result.map.put(key, list);
}
list.add(v);
};
mappers.add(e);
values.forEach(e);
return result;
}
public void add(V v) {
values.add(v);
mappers.forEach( e -> e.accept(v));
}
private List<Consumer<V>> mappers = new ArrayList<>();
private List<V> values = new ArrayList<>();
}
More low level examples
public static void main(String[] args) {
// Create a multi-map
MultiMap<Site> multiMap = new MultiMap<>();
// Add an index by Site.id
MultiMapIndex<Integer, Site> byId = multiMap.addIndex((site)->site.id);
// Add some entries to the map
multiMap.add(new Site(1234,"A Site","A"));
multiMap.add(new Site(4321,"Another Site","B"));
multiMap.add(new Site(7777,"My Site","A"));
// We can add a new index after the entries have been
// added - this time by name.
MultiMapIndex<String, Site> byName = multiMap.addIndex((site)->site.name);
// Get a value by Id.
System.err.printf("Get by id=7777 = %s\n", byId.get(7777));
// Get a value by Name
System.err.printf("Get by name='A Site' = %s\n", byName.get("A Site"));
// We can do usual mappy things with the indexes,
// such as list the keys, or iterate over all entries
System.err.printf("byId.keys() = %s\n", byId.keySet());
byId.forEach((Integer id, Site s) -> System.err.printf(" %s => %s\n", id, s));
// In some cases the map is not unique, so I provide a
// way to get all entries with the same value as a list.
// in this case by their rating value.
MultiMapIndex<String, List<Site>> byRating = multiMap.addMultiIndex((Site site)->site.rating);
System.err.printf("byRating('A') = %s\n", byRating.get("A"));
System.err.printf("byRating('B') = %s\n", byRating.get("B"));
// Adding stuff after creating the indices is fine.
multiMap.add(new Site(3333,"Last Site","B"));
System.err.printf("byRating('A') = %s\n", byRating.get("A"));
System.err.printf("byRating('B') = %s\n", byRating.get("B"));
}
}
I think you can search your objects over List :
List<Site> sites;
for (Site s : sites) {
if (s.getSiteName().equal(siteName)) {
// do something
}
if (s.getSiteId().equal(siteId)) {
// do something
}
}
You should create a Bean (Container) as Java is not requiring code optimisation as it will be optimised by the JIT compiler anyway.
public class SiteMap {
String siteName;
Integer siteId;
String parentBrand;
.... Getters and setters ...
}
List<SiteMap> myList = new ArrayList<>();
If you need to compare or sort then you can implement Comparable interface on the SiteMap class allowing you to sort the details if needed.
you can, if using Java 8 then also use Streams to filter or fetch the one you want. as there is a fetchFirst
SiteMap mysite = myList.stream()
.filter(e -> e.siteName.equals("Amazon.com"))
.findFirst()
.get();
In my Java project, I have a need to work with a handful of strings (about 10-30 at a time). I want a data structure to hold them, with properties like so:
Can assign a unique name to each string
The unique names can be used in the code just as if they were variables, with support for IDE auto-complete, no calling getValue() or toString(), etc.
Can iterate over each value in the data structure
In practice, I'd want the code to look something like this:
MagicalDataStructure<String> mds = new MagicalDataStructure(
FirstString = "foo",
SecondString = "bar",
);
/*
This section would output:
foo
bar
*/
for (String value : mds) {
System.out.println(value);
}
/*
This section would output:
The first value is: foo
*/
System.out.println("The first value is: " + FirstString);
Things I've considered:
A class full of static finals. This satisfies #1 and #2, but I can't iterate over them -- at least not without resorting to dark-mojo reflection.
A dictionary. This satisfies #1 and #3, but the keys wouldn't be auto-completable, and there's additional syntax involved in accessing the values.
An enum. This also solves #1 and #3, but accessing the string value takes a little bit of extra code.
Is there a data structure, library, etc that will do what I want?
I would definitely favor a Map for this:
public enum PagePath {
PATH1,
PATH2,
// etc.
}
public static final Map<PagePath, String> ALL_PATHS;
static {
Map<PagePath, String> paths = new EnumMap<>(PagePath.class);
paths.put(PagePath.PATH1, "/html/div[0]/h1");
paths.put(PagePath.PATH2, "/html//form/input[id='firstname']");
// etc.
// Make sure no one breaks things by removing entries
// or by adding enum constants while forgetting to account
// for them in the above Map.
if (!paths.keySet().equals(EnumSet.allOf(PagePath.class))) {
throw new RuntimeException(
"Map does not have entries for all PagePath constants!");
}
ALL_PATHS = Collections.unmodifiableMap(paths);
}
Another possibility, as you’ve mentioned, is using String constants. You can place the initialization of those constants inside the initialization of the “all values” list, to make sure none of them are forgotten:
public static final String PATH1;
public static final String PATH2;
// etc.
public static final Collection<String> ALL_PATHS;
static {
ALL_PATHS = Collections.unmodifiableCollection(Arrays.asList(
PATH1 = "/html/div[0]/h1",
PATH2 = "/html//form/input[id='firstname']",
// etc.
));
}
If someone removes a constant, they’ll be forced to remove its initialization from the Arrays.asList call. If someone adds a constant, and keeps it consistent with the other constants’ declarations, they will be forced to add it to the ALL_PATHS List, since failing to do so would mean it never gets initialized, which compiler will catch.
If your strings are properties your may want to use RessourceBundle or Properties. This can be use to solve problem 1/3.
To solve problem 2, you may create Enum that are Keys to your HashMap so that you need to write hashMap.get(enum) that will auto-complete everything. This solution add words but benefit from auto-completion.
Can you just write a custom method to return the string values using enum?
public enum MagicalDataStructure {
FirstString("foo"),
SecondString("bar");
String value;
MagicalDataStructure(String value) {
this.value = value;
}
public static List<String> getMagicalStrings() {
List<String> strings = new ArrayList<String>();
for (MagicalDataStructure item : MagicalDataStructure.values()) {
strings.add(item.value);
}
return strings;
}
}
And call the function wherever you need to iterate:
public static void main(String[] args) {
for (String magicalString: MagicalDataStructure.getMagicalStrings()) {
System.out.println(magicalString);
}
}
How about this :) The main idea here is the following we use the EnumMap as a base for our CustomEnumMap. My understanding is that you don't need put methods so our first task is to actually throw Unsupported Operation for them. The second step is to define the different enums with the values they are actually representing. The third step is achieved through a static method that converts any Enumeration into our CustomEnumMap. How the map is later used you can see for yourself.
There is one place for improvement though and it is the implementation of the static method. Unfortunately I am just learning java 8 lambdas so I was not able to implement it fast in a good way. But I will work on that and will give you the final implementation of this method later. Or is someone wants to help me out with it is welcome.
public static class CustomEnumMap<K extends Enum<K>,V> extends EnumMap<K, V> {
public CustomEnumMap(EnumMap<K, ? extends V> m) {
super(m);
}
#Override
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
#Override
public void putAll(Map<? extends K, ? extends V> m) {
throw new UnsupportedOperationException();
}
}
public static enum EnumA {
FIRST("value1"),SECOND("value2"),THREE("value3");
private String value;
private EnumA(String value) {
this.value = value;
}
public String toString() {
return value;
}
}
public static enum EnumB {
FIRST("value1"),SECOND("value2");
private String value;
private EnumB(String value) {
this.value = value;
}
public String toString() {
return value;
}
}
public static <T extends Enum<T>> CustomEnumMap<T, String> toMap(T[] myenum) {
return new CustomEnumMap<T,String>(new EnumMap<T,String>( Arrays.stream(myenum).collect(Collectors.toMap(t->(T)t, t->t.toString()))));
}
public static void main(String args[]) {
CustomEnumMap<EnumA, String> enumA = toMap(EnumA.values());
CustomEnumMap<EnumA, String> enumB = toMap(EnumA.values());
for (String stringA : enumA.values()) {
System.out.print(stringA);
}
System.out.println("");
for (String stringB : enumB.values()) {
System.out.print(stringB);
}
}
What's the best way to accomplish this problem? I want to call a particular method for the first time when I am running my application but second time it should be called only whenever there is any change. If there is no change then I don't want to call that method.
I want to call process method for the first time when I am running my application and it should print out like this- I don't want to use TestingFramework entry in process method call.
{Answer-A=1.0.0, Answer-B=1.0.0}
But after that I have a background thread running which will call getAttributesFromDatabase method again so now I want to print out only the information that got changed but if there is no change then I don't want to call process method again.
Suppose any value got changed for either Animal-A or Animal-B, then it should print out only the change information only..
Let's take an example- Suppose second time when my background thread is running, and map entry is like this without any change-
TestingFramework 1.0.0
Answer-A 1.0.0
Asnwer-B 1.0.0
then I don't want to call process method again as there was no change. But somehow supposed the value entry got changed for Answer-A or Answer-B, then at that time, I want to call process method with the entry that got changed.
I hope the question is clear enough.
public static Map<String, String> frameworkInfo = new LinkedHashMap<String, String>();
public static Map<String, String> bundleList = new LinkedHashMap<String, String>();
public static Map<String, String> newBundleList = new LinkedHashMap<String, String>();
private static Map<String, String> oldBundleList = new LinkedHashMap<String, String>();
public static void main(String[] args) {
getAttributesFromDatabase();
loggingAfterEveryXMilliseconds();
}
private static void getAttributesFromDatabase() {
Map<String, String> bundleInformation = new LinkedHashMap<String, String>();
bundleInformation = getFromDatabase();
if(TestingFrameworkInfo.get("TestingFramework") != (bundleInformation.get("TestingFramework"))) {
TestingFrameworkInfo.put("TestingFramework", bundleInformation.get("TestingFramework"));
String version = TestingFrameworkInfo.get("TestingFramework");
printTestingFrameworkBundle("TestingFramework", version);
}
bundleInformation.remove("TestingFramework");
if(!bundleInformation.isEmpty()) {
oldBundleList = bundleList;
bundleList = bundleInformation;
}
final Map<String, MapDifference.ValueDifference<String>> entriesDiffering = Maps.difference(oldBundleList, bundleList).entriesDiffering();
if (!entriesDiffering.isEmpty()) {
for (String key : entriesDiffering.keySet()) {
newBundleList.put(key, bundleList.get(key));
System.out.println("{" + key + "=" + bundleList.get(key) + "}");
}
process(newBundleList);
}
process(bundleList);
}
private static void process(final Map<String, String> test) {
System.out.println(test);
}
private static Map<String, String> getFromDatabase() {
Map<String, String> hello = new LinkedHashMap<String, String>();
String version0 = "1.0.0";
String version1 = "1.0.0";
String version2 = "1.0.0";
hello.put("TestingFramework", version0);
hello.put("Answer-A", version1);
hello.put("Answer-B", version2);
return hello;
}
private static void loggingAfterEveryXMilliseconds() {
new Thread() {
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
getAttributesFromDatabase();
}
}
}.start();
}
With the below code, I have, it will call the process method for the first time and second time when there is no change then again it calls the process method which I don't want at all. Can anybody help me with this?
I am pretty much sure, I am missing one key thing here, and then it will start working I guess.
Updated:-
I am still working on this. Can anybody help me with this?
If your database is an RDBMS, you could put the logic to detect a change there, i.e. use a trigger to update a last modified column that your application would poll and call your process method when it changes.
I have several Java enums that looks something like below (edited for confidentiality, etc).
In each case, I have a lookup method that I'm really not satisfied with; in the example below, it is findByChannelCode.
public enum PresentationChannel {
ChannelA("A"),
ChannelB("B"),
ChannelC("C"),
ChannelD("D"),
ChannelE("E");
private String channelCode;
PresentationChannel(String channelCode) {
this.channelCode = channelCode;
}
public String getChannelCode() {
return this.channelCode;
}
public PresentationChannel findByChannelCode(String channelCode) {
if (channelCode != null) {
for (PresentationChannel presentationChannel : PresentationChannel.values()) {
if (channelCode.equals(presentationChannel.getChannelCode())) {
return presentationChannel;
}
}
}
return null;
}
}
The problem is, I feel silly doing these linear lookups when I could just be using a HashMap<String, PresentationChannel>. So I thought of the solution below, but it's a little messier that I would hope and, more to the point, I didn't care to re-invent the wheel when surely someone else has come across this. I wanted to get some of the sage wisdom of this group: what is the proper way to index an enum by value?
My solution:
ImmutableMap<String, PresentationChannel> enumMap = Maps.uniqueIndex(ImmutableList.copyOf(PresentationChannel.values()), new Function<PresentationChannel, String>() {
public String apply(PresentationChannel input) {
return input.getChannelCode();
}});
and, in the enum:
public static PresentationChannel findByChannelCode(String channelCode) {
return enumMap.get(channelCode);
}
I think you're using non-JDK classes here right?
A similar solution with JDK API:
private static final Map<String, PresentationChannel> channels = new HashMap<String, PresentationChannel>();
static{
for (PresentationChannel channel : values()){
channels.put(channel.getChannelCode(), channel);
}
}
I wanted to get some of the sage wisdom of this group: what is the proper way to index an enum by value?
Quite possibly not doing it at all.
While hash tables provide O(1) lookup, they also have quite a large constant overhead (for hash calculations etc), so for small collections a linear search may well be faster (if "the efficient way" is your definition of "the proper way").
If you just want a DRY way to do it, I suppose Guava's Iterables.find is an alternative:
return channelCode == null ? null : Iterables.find(Arrays.asList(values()),
new Predicate<PresentationChannel>() {
public boolean apply(PresentationChannel input) {
return input.getChannelCode().equals(channelCode);
}
}, null);
Why don't you name your members A, B, C, D, E and use valueOf?
I was looking for something similar and found on this site a simple, clean and straight to the point way. Create and initialize a static final map inside your enum and add a static method for the lookup, so it would be something like:
public enum PresentationChannel {
ChannelA("A"),
ChannelB("B"),
ChannelC("C"),
ChannelD("D"),
ChannelE("E");
private String channelCode;
PresentationChannel(String channelCode) {
this.channelCode = channelCode;
}
public String getChannelCode() {
return this.channelCode;
}
private static final Map<String, PresentationChannel> lookup
= new HashMap<String, PresentationChannel>();
static {
for(PresentationChannel pc : EnumSet.allOf(PresentationChannel.class)) {
lookup.put(pc.getChannelCode(), pc);
}
}
public static PresentationChannel get(String channelCode) {
return lookup.get(channelCode);
}
}
for few values that's ok, iteration through the values array(). One note only: use smth like that. values() clones the array on each invocation.
static final PresentationChannel[] values=values();
static PresentationChannel getByCode(String code){
if (code==null)
return null;
for(PresentationChannel channel: values) if (code.equals(channel.channelCode)) return channel;
return null;
}
if you have more Channels.
private static final Map<String code, PresentationChannel> map = new HashMap<String code, PresentationChannel>();
static{//hashmap sucks a bit, esp if you have some collisions so you might need to initialize the hashmap depending on the values count and w/ some arbitrary load factor
for(PresentationChannel channel: values()) map.put(channel.channelCode, channel);
}
static PresentationChannel getByCode(String code){
return map.get(code);
}
Edit:
So implement an helper interface, like shown below, another example why java syntax generics blows and sometimes - better not used.
Usage PresentationChannel channel = EnumRepository.get(PresentationChannel.class, "A");
There will be overhead but well, it's quite fool proof.
public interface Identifiable<T> {
T getId();
public static class EnumRepository{
private static final ConcurrentMap<Class<? extends Identifiable<?>>, Map<?, ? extends Identifiable<?>>> classMap = new ConcurrentHashMap<Class<? extends Identifiable<?>>, Map<?,? extends Identifiable<?>>>(16, 0.75f, 1);
#SuppressWarnings("unchecked")
public static <ID, E extends Identifiable<ID>> E get(Class<E> clazz, ID value){
Map<ID, E> map = (Map<ID, E>) classMap.get(clazz);
if (map==null){
map=buildMap(clazz);
classMap.putIfAbsent(clazz, map);
}
return map.get(value);
}
private static <ID, E extends Identifiable<ID>> Map<ID, E> buildMap( Class<E> clazz){
E[] enumConsts = clazz.getEnumConstants();
if (enumConsts==null)
throw new IllegalArgumentException(clazz+ " is not enum");
HashMap<ID, E> map = new HashMap<ID, E>(enumConsts.length*2);
for (E e : enumConsts){
map.put(e.getId(), e);
}
return map;
}
}
}
enum X implements Identifiable<String>{
...
public String getId(){...}
}
Minor warning: if you put Identifiable somewhere out there, and many projects/wepapp depend on it (and share it) and so on, it's possible to leak classes/classloaders.
Here is another way to implement an unmodifiable map:
protected static final Map<String, ChannelCode> EnumMap;
static {
Map<String, ChannelCode> tempMap = new HashMap<String, ChannelCode>();
tempMap.put("A", ChannelA);
tempMap.put("B", ChannelB);
tempMap.put("C", ChannelC);
tempMap.put("D", ChannelD);
tempMap.put("E", ChannelE);
EnumMap = Collections.unmodifiableMap(tempMap);
}
You can use EnumMap.get(someCodeAthroughE) to quickly retrieve the ChannelCode. If the expression is null then your someCodeAthroughE was not found.
If you are expecting the provided channelCode to always be valid then you can just try and get the correct instance of the enum using the valueOf() method. If the provided value is invalid you can return null or propagate the exception.
try {
return PresentationChannel.valueOf(channelCode);
catch (IllegalArgumentException e) {
//do something.
}