Categories
discuss

How to merge List of Maps of Maps into a Map of Maps?

Could you help me with Java Streams?

As you can see from the title I need to merge List<Map<String, Map<String, Genuineness>>> into Map<String, Map<String, Genuineness>>.

The list is represented as List<Map<String, Map<String, Genuineness>>> and looks like:

[  
   {  
      "USER_1":{  
         "APP_1":{  
            "total":1,
            "totalGenuine":1,
            "totalDevelopment":1
         }
      },
      "USER_2":{  
         "APP_1":{  
            "total":1,
            "totalGenuine":1,
            "totalDevelopment":1
         },
         "APP_2":{  
            "total":2,
            "totalGenuine":2,
            "totalDevelopment":2
         }
      }
   },
   {  
      "USER_1":{  
         "APP_1":{  
            "total":1,
            "totalGenuine":1,
            "totalDevelopment":1
         }
      },
      "USER_2":{  
         "APP_1":{  
            "total":1,
            "totalGenuine":1,
            "totalDevelopment":1
         },
         "APP_2":{  
            "total":2,
            "totalGenuine":2,
            "totalDevelopment":2
         }
      }
   }
]

So, as you can see, duplicate keys could be everywhere. My goal is to combine them into Map<String, Map<String, Genuineness>> by merging Genuineness. Merge Genuineness simply means return a new object with summed up values total, totalGenuine, and totalDevelopment.

Here is my implementation that fails:

final Map<String, Map<String, Genuineness>> map = taskHandles.stream().map(this::mapTaskHandle)
                .flatMap(m -> m.entrySet().stream()).collect(
                        Collectors.toMap(Map.Entry::getKey, e -> e.getValue().entrySet().stream()
                                .collect(
                                        Collectors.toMap(Map.Entry::getKey,
                                                g -> new Genuineness(g.getValue().getTotal(), g.getValue().getTotalGenuine(), g.getValue().getTotalDevelopment()),
                                                (g1, g2) -> new Genuineness(g1.getTotal() + g2.getTotal(),
                                                        g1.getTotalGenuine() + g2.getTotalGenuine(),
                                                        g1.getTotalDevelopment() + g2.getTotalGenuine()
                                                )
                                        )
                                )
                        )
                );

It fails with message:

java.lang.IllegalStateException: Duplicate key {TEST_33_33_APP_1=live.attach.billing.domain.model.billing.Genuineness@951b6fe}

So, seems that in my implementation I’ve pointed how to combine inner map but didn’t make a merging of values of outer map and I don’t know how to do it.

I greatly appreciate your help. Thank you in advance!

UPDATE: Expected output:

   {  
      "USER_1":{  
         "APP_1":{  
            "total":2,
            "totalGenuine":2,
            "totalDevelopment":2
         }
      },
      "USER_2":{  
         "APP_1":{  
            "total":2,
            "totalGenuine":2,
            "totalDevelopment":2
         },
         "APP_2":{  
            "total":4,
            "totalGenuine":4,
            "totalDevelopment":4
         }
      }
   }

Answer

Honestly, this is a horrible data structure to work with and the maintainers of this code will have a hard time finding out problems that arise.

You should take a step back and consider refactoring the code, any way you can solve the missing part by using the following merge function in the outmost toMap:

(l, r) -> {
      r.forEach((k, v) -> l.merge(k, v,
                    (bi, bii) -> new Genuineness(bi.getTotal() + bii.getTotal(),
                               bi.getTotalGenuine() + bii.getTotalGenuine(),
                               bi.getTotalDevelopment() + bii.getTotalGenuine())));
       return l;
}

Full code:

taskHandles.stream().map(this::mapTaskHandle)
                .flatMap(m -> m.entrySet().stream()).collect(
                        Collectors.toMap(Map.Entry::getKey, e -> e.getValue().entrySet().stream()
                                .collect(
                                        Collectors.toMap(Map.Entry::getKey,
                                                g -> new Genuineness(g.getValue().getTotal(), g.getValue().getTotalGenuine(), g.getValue().getTotalDevelopment()),
                                                (g1, g2) -> new Genuineness(g1.getTotal() + g2.getTotal(),
                                                        g1.getTotalGenuine() + g2.getTotalGenuine(),
                                                        g1.getTotalDevelopment() + g2.getTotalGenuine()
                                                )
                                        )
                                ),(l, r) -> {
                                  r.forEach((k, v) -> l.merge(k, v,
                                          (bi, bii) -> new Genuineness(bi.getTotal() + bii.getTotal(),
                                                  bi.getTotalGenuine() + bii.getTotalGenuine(),
                                                  bi.getTotalDevelopment() + bii.getTotalGenuine())));
                                  return l;
                                }

                        )
                );

Ideone

Categories
discuss

How do I close a thread local autocloseable used in parallel stream?

I have a ThreadLocal variable. I would like to use it like this:

ThreadLocal<AutoCloseable> threadLocal = new ThreadLocal<AutoCloseable>(); // pseudocode
ForkJoinPool fj = new ForkJoinPool(nThreads);
fj.submit(
    () -> myStream.parallel().forEach(e -> {
        /*I want to use the thread local autocloseable here, 
          but how do I close it when this parallel processing is done?*/
    })
);

Answer

ThreadLocal are closed after the thread using them dies. If you want control over this you need to use a map instead.

// do our own thread local resources which close when we want.
Map<Thread, Resource> threadLocalMap = new ConcurrentHashMap<>();

fj.submit(
() -> myStream.parallel().forEach(e -> {
     Resource r = threadLocalMap.computeIfAbsent(Thread.currentThread(), t -> new Resource();
    // use the thread local autocloseable here, 
})

// later once all the tasks have finished.
// close all the thread local resources when the parallel processing is done
threadLocalMap.values().forEach(Utils::closeQuietly);

It’s common to have a method which closes resources without throwing an exception. Chronicle has one but so do many other libraries.

public static void closeQuietly(Closeable c) {
    if (c != null) {
       try {
           c.close();
       } catch (IOException ioe) {
           // ignore or trace log it
       }
    }
}

Most likely you have a method do this in your project already https://www.google.co.uk/search?q=public+static+void+closequietly+Closeable

Categories
discuss

CompletableFuture in Java8

I have this piece of code that I wanted to refactor to Java 8

List<String> menus = new ArrayList<String>();           
for (Menu menu : resto1.getMenu()) {            
    MainIngredient mainIngredient = MainIngredient.getMainIngredient(menu.getName());           
    if (mainIngredient.getIngredient().indexOf("Vegan")!=-1) {
        menus.add(menu.getName());
    }                   
}

After refactoring this simple loop it seems like too much code… am I using CompletableFutures correctly?

ExecutorService executorService = Executors.newCachedThreadPool();
List<CompletableFuture<MainIngredient>> priceFutureList = resto1.getMenu().stream()
    .map(menu -> CompletableFuture.supplyAsync(
        () -> MainIngredient.getMainIngredient(menu.getName()), executorService))
    .collect(Collectors.toList());        

CompletableFuture<Void> allFuturesDone = CompletableFuture.allOf(
    priceFutureList.toArray(new CompletableFuture[priceFutureList.size()]));

CompletableFuture<List<MainIngredient>> priceListFuture =        
    allFuturesDone.thenApply(v -> priceFutureList.stream()
        .map(CompletableFuture::join)
        .collect(toList()));

Answer

Why not just?

List<String> menus = resto1.getMenu()
                           .stream()
                           .map(m -> MainIngredient.getMainIngredient(m.getName()))
                           .filter(m -> m.getIngredient().indexOf("Vegan")!=-1)
                           .collect(toCollection(ArrayList::new));

is your imperative approach really slow that you have to use CompletableFuture?

Categories
discuss

Why doesn’t Java have an EmptyQueueException? [closed]

In the pop method of java.util.Stack, it throws an EmptyStackException if the Stack is empty. But the remove method of java.util.Queue (which is similar to pop in the Stack class) instead throws a NoSuchElementException. Why is there this inconsistency in Java?

Answer

The Stack class is a legacy class from the Java 1.0 days, prior to the introduction of the collections framework. Its interface has to be backwards compatible … and that is how it was designed.

By contrast, the Queue interface was introduced in the Java 1.5 revision of the collections framework. By that time, the NoSuchElementException had been chosen by the designers as the best way to express this kind of error condition1.

Note that NoSuchElementException could have been used in Stack since both classes existed in Java 1.0, but clearly, the designers had other ideas back then2.

So this is just a historical anomaly that has arisen due to the way that the Java APIs have evolved. It cannot be fixed without breaking binary compatibility for existing applications that use the Stack class.


1 – You may disagree with that, but you asked why, and this is why.

2 – Or maybe they were just too rushed to get the API design correct. The Java 1.0 release was made under extreme pressure to meet a perceived market opportunity. A few mistakes were made and could not be corrected in time. Other examples include the Enumeration API, the deprecated Thread methods, the Hashtable and Vector classes, StringBuffer and so on. But once Java 1.1 was released, it was too late.

Categories
discuss

Adding custom layout in an AlertDialog

How to I use my xml as a layout for my dialog? This class is used to show a dialog but the problem is i want to set my own layout.

 public static void showRateDialog(final Context mContext, final SharedPreferences.Editor editor) {
    final Dialog dialog = new Dialog(mContext);
    dialog.setTitle("Rate " + APP_TITLE);

    LinearLayout ll = new LinearLayout(mContext);
    ll.setOrientation(LinearLayout.VERTICAL);

    TextView tv = new TextView(mContext);
    tv.setText("If you enjoy using " + APP_TITLE + ", please take a moment to rate it. Thanks for your support!");
    tv.setWidth(240);
    tv.setPadding(4, 0, 4, 10);
    ll.addView(tv);

    Button b1 = new Button(mContext);
    b1.setText("Rate " + APP_TITLE);
    b1.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + APP_PNAME)));
            dialog.dismiss();
        }
    });
    ll.addView(b1);

    Button b2 = new Button(mContext);
    b2.setText("Remind me later");
    b2.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            dialog.dismiss();
        }
    });
    ll.addView(b2);

    Button b3 = new Button(mContext);
    b3.setText("No, thanks");
    b3.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            if (editor != null) {
                editor.putBoolean("dontshowagain", true);
                editor.commit();
            }
            dialog.dismiss();
        }
    });
    ll.addView(b3);

    dialog.setContentView(ll);
    dialog.show();
}

I want it to have 3 buttons and a picture. Is it possible to do so?

Answer

You can set custom layout to your dialog like below:

Create a custom layout file:

custom.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >

<TextView
    android:id="@+id/text1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textColor="#FFF" />

<TextView
    android:id="@+id/text2"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textColor="#FFF"/>

</RelativeLayout>

Then in your activity:

// custom dialog
final Dialog dialog = new Dialog(context);
dialog.setContentView(R.layout.custom);
dialog.setTitle("Title");

// set the custom dialog components - text, image and button
TextView text = (TextView) dialog.findViewById(R.id.text1);
text.setText("Text view 1");

TextView text = (TextView) dialog.findViewById(R.id.text2);
text.setText("Text view 2");
dialog.show();
Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..