Java 8 StringJoiner demo

24 01 2016

Finally Java has convenient and intuitive API for joining strings with delimiters! Since Java 8 there is StringJoiner class. It is an API that you may know from Guava Joiner classes (see my post: https://looksok.wordpress.com/2015/10/17/guava-joiner-join-all-strings-in-an-array-or-map/). Here is a short StringJoiner demo.

Basic String joins

The most basic usage is to create StringJoiner instance with delimiter as a constructor param and add() strings:

StringJoiner joiner = new StringJoiner(",");
joiner.add("apple");
joiner.add("banana");
joiner.add("orange");

System.out.println("Joiner result is: " + joiner.toString());

The result is:

Joiner result is: apple,banana,orange

If you prefer, you can chain add() calls:

StringJoiner joiner = new StringJoiner(",")
    .add("apple")
    .add("banana")
    .add("orange");

Join Collection of Strings

If you have Collection of Strings, the new static String.join() method can join them:

List<String> list = Arrays.asList("apple", "banana", "orange");
String joined = String.join(", ", list);

System.out.println("Join Array result is: " + joined);

With the result of:

Join Array result is: apple, banana, orange

Join inline

You can prepare joined String in one line with String.join() overloaded with varargs, like that:

String.join(", ", "apple", "banana", "orange");

Joining Collector in Stream API

When using streams you have joining Collector at your disposal:

List<String> list = Arrays.asList("apple", "banana", "orange");
String joined = list.stream()
        .collect(Collectors.joining(", "));

System.out.println("Joined with collector: " + joined);

This will result with:

Joined with collector: apple, banana, orange

Source Code

As always, I share with you the source code for this demo on my github: https://github.com/yacekmm/looksok/tree/StringJoinerDemo/Java/JavaDemo





Guava Multimap demo

16 08 2015

The problem

Handling maps that store collection of items under each key is very common. The thing I have in mind is this:

Map<String, List<Integer>> playerScoresMap = new HashMap<String, List<Integer>>();

Let’s assume that it stores scores for players. The player name is the key, and the value is a list of points scored by the player in following rounds. The task is to add a new score for the player after the round.

Plain Java solution

The HashMap solution requires you to:

  1. check if the player key already exist in map
    1. if it does not exist – add the key and create new array with score
    2. if it exists, get its current score array
  2. add new score to the array
  3. store the array under the user key

Source code for it is:

private static void addToOldStyleMultimap(String playerName, int scoreToAdd) {
    List<Integer> scoresList = new ArrayList<Integer>();
    if(playerScoresMap.containsKey(playerName)){
        scoresList = playerScoresMap.get(playerName);
    }

    scoresList.add(scoreToAdd);
    playerScoresMap.put(playerName, scoresList);
}

Guava solution

Guava has dedicated type for maps of that kind. Java’s:

Map<String, List<Integer>> playerScoresMap = new HashMap<String, List<Integer>>();

is equal to Guava’s Multimap:

Multimap<String, Integer> playerScoresMultimap = HashMultimap.create();

The difference is noticable in adding scores use case. To add new score for the player just make a call:

private static void addToGuavaMultimap(String playerName, Integer scoreToAdd) {
    playerScoresMultimap.put(playerName, scoreToAdd);
}

Guava’s Multimap does all checks for you. If player key exists, it adds new score to its score array. If it does not exist, a new key with one element score array is added.

Guava Example

Calling addToGuavaMultimap in the following manner:

addToGuavaMultimap("Alan", 2);
addToGuavaMultimap("Alan", 4);
addToGuavaMultimap("Alan", 6);
addToGuavaMultimap("Paul", 87);
System.out.println("Guava multimap result: " + playerScoresMultimap);

results with output:

Guava multimap result: {Alan=[4, 2, 6], Paul=[87]}

Source code download

The source code for this post is on my github: https://github.com/yacekmm/looksok/tree/GuavaCacheDemo





Guava Cache basic demo

25 07 2015

Here I go with the caching! Caching (and cache invalidation) is second one of the most difficult thing to do while programming (the first one is the naming things problem :P ). I’ll show the demo with Guava Cache (18.0). Source Code for this tutorial is on my GitHub: https://github.com/yacekmm/looksok/tree/GuavaCacheDemo/Guava/GuavaCacheDemo

Caches Explained

You may want to get familiar with this article to get the idea of how cache works: https://code.google.com/p/guava-libraries/wiki/CachesExplained.

The Demo Introduction

Here I explain the basic app that accesses data via DAO. Let’s assume that data access is costly so the cache is needed. I want cache entries to expire after specified amount of time. Pretty simple.

Build Cache

Guava provides the cache builder. In my case I make use of it is as follows:

cache = CacheBuilder.newBuilder()
        .expireAfterWrite(5, TimeUnit.SECONDS)
        .build(new CacheLoader<String, String>() {
            @Override
            public String load(String key) throws Exception {
                return dataDao.getValueForKey(key);
            }
        });

I do two things here:

  1. set the desired expiration algorithm and time – entry will become invalid in 5 seconds after it was created or updated
  2. provide the method to load entry – Guava Cache will call this method when you will try to retrieve the value from the cache for the first time (when entry was not found in it yet) or if requested entry has expired. Here that method makes call to my DAO.

Expiration

Among few types of eviction (Size-based, timed, Reference-based) I use Timed eviction, There are two algorythms of expiration in that case. From guava doc:

  • expireAfterAccess(long, TimeUnit) Only expire entries after the specified duration has passed since the entry was last accessed by a read or a write.
  • expireAfterWrite(long, TimeUnit) Expire entries after the specified duration has passed since the entry was created, or the most recent replacement of the value. This could be desirable if cached data grows stale after a certain amount of time.

expireAfterAccess works different. In opposed to expireAfterWrite, it expires entry if it was not accessed in cache in specified time. So if you constatly read that value within its expiration time, it will not get refreshed. expireAfterWrite expires entries based on its age in cache. So it will be refreshed if validity period passed, no matter how freqently you access it (it is done in lazy way, so if time passed, the value will be refreshed only when requested from cache).

Expiration details

In this StackOverflow answer the details are explained by Guava team member:

The Guava Cache implementation expires entries in the course of normal maintenance operations, which occur on a per-segment basis during cache write operations and occasionally during cache read operations. Entries usually aren’t expired at exactly their expiration time, just because Cache makes the deliberate decision not to create its own maintenance thread, but rather to let the user decide whether continuous maintenance is required.

I’m going to focus on expireAfterAccess, but the procedure for expireAfterWrite is almost identical. In terms of the mechanics, when you specify expireAfterAccess in the CacheBuilder, then each segment of the cache maintains a linked list access queue for entries in order from least-recent-access to most-recent-access. The cache entries are actually themselves nodes in the linked list, so when an entry is accessed, it removes itself from its old position in the access queue, and moves itself to the end of the queue.

When cache maintenance is performed, all the cache has to do is to expire every entry at the front of the queue until it finds an unexpired entry. This is straightforward and requires relatively little overhead, and it occurs in the course of normal cache maintenance. (Additionally, the cache deliberately limits the amount of work done in a single cleanup, minimizing the expense to any single cache operation.) Typically, the cost of cache maintenance is dominated by the expense of computing the actual entries in the cache.

The demo and the test

Test mechanism is simple. I set the cache entry expiration time to 5 seconds, and set up a loop to retrieve value from cache each second.

for (int i = 0; i < 20; i++) {
    cacheDemo.getValue("Blue");
    Thread.sleep(1000);
}

I have also added the log line in DAO on each data retrieval and a log line on cache value request. One in five log lines is a log by DAO data retrieval method. The cache value is a string with a timestamp. Notice that it gets updated each time the data is retrieved. This is how console output look like (bold lines are logged by DAO on data request):

Hello, Cache!
returning value from dao: value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
returning value from dao: value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
returning value from dao: value for key Blue, refreshed from DAO at 20:51:07.703
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:07.703
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:07.703
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:07.703
...

Get the source code

Source code for this demo is on my GitHub: https://github.com/yacekmm/looksok/tree/GuavaCacheDemo/Guava/GuavaCacheDemo





Java 8 streams demo part 2: Stream of custom objects

11 07 2015

Following the List with primitive types like in post here: Java 8 Streams demo, now it’s time to demonstrate streams with custom objects. Please read mentioned post first to get the idea of this one faster.

Introduction

Now I want to have a list of Users. User is a POJO having a name and age. I am going to filter out users younger than 18 years and sort them in list by their age, ascending. At the beginning I have a list of users:

List<User> users = new ArrayList<User>();
users.add(new User("John", 21));
users.add(new User("Jack", 13));
users.add(new User("Joe", 56));
users.add(new User("Michelle", 37));

Filtering and sorting stream
I convert the list to the stream with the stream() method, filter and sort items. Item is now the User class instance, so I can call its instance methods like getAge().

users.stream()
        .filter(item -> item.getAge() > 18)
        .sorted((item1, item2) -> (item1.getAge() - item2.getAge()))
        .forEach(System.out::println);

Result
As a result I get adult users, sorted by age:

User{name='John', age=21}
User{name='Michelle', age=37}
User{name='Joe', age=56}

Source Code

Find the source Code for this tutorial on my github: https://github.com/yacekmm/Java8Streams/tree/StreamWithObject





Android SQLite schema migration with patches

3 05 2014

When upgrading your Android application you often need to change its data model. When the model is stored in SQLite database, then its schema must be updated as well. I recommend the concept of patching and versioning the database This is very well described in this article:

http://www.greenmoonsoftware.com/2012/02/sqlite-schema-migration-in-android/

The idea behind it

Android lets you upgrade the schema version, detect its changes and react to it when user installs new app version with higher schema version. The SQLiteOpenHelper class that will notify you about this.

You need to override its onUpgrade() method. When onUpgrade() detects that current version is lower than new one, it can apply patches in order and migrate schema to the desired version.

I used that algorythm in one of my apps and it worked very well.





Custom Java Annotation tutorial – How often do you use them?

22 02 2014

@Override, @Test and @Deprecated annotations are widely used. They make code more readable and clean. You can facilitate Java Annotations features fully by creating your custom annotation for classes, fields etc.

The use case

Simple example, I figured out to illustrate this post, regards the PersonInfo class. This is in fact data class that contains… well… person info. Some of the data in it may be sensitive personal data (like email address), and some not personal (like name) and some may even not be personal data (like storageId in my example).
Let’s assume that the user of this class needs two print methods: first printing all data, and second to print data that is not sensitive.

The Idea behind it

To mark PersonInfo fields as sensitive data or not, I use custom annotation: @PersonData, that indicates that field is in fact person data, and a flag indicating if it is sensitive (class’ field annotation). Then my print method finds all annotated fields, checks the ‘sensitive’ flag value and decides whether to print particular field, or not.

This finding is made by reflection, the one that is safe and will not cause many errors in runtime, because it operates on classess well known during compilation time.

The source code

As always in my tutorials, you can download the source code from here.

1. How to use a custom annotation

This is the result of applying my custom annotation:

public class PersonInfo {

 @PersonalData(isSensitive=false)
  private String name;

 @PersonalData(isSensitive=false)
  private String surname;

 @PersonalData(isSensitive=true)
  private String email;

 @PersonalData(isSensitive=true)
  private String phoneNumber;

  private long storageId;

 ...
 }

LooksOK, doesn’t it?

2. Parse annotatated fields

The print method (overloaded toString() in my case) algorythm is as follows:

1. it iterates all the fields in PersonInfo class

2. if field is annotated with PersonalData annotation, it checks the ‘sensitive’ flag value

3. if value is marked as sensitive it may decide whether to print it or not

The reflection is used to find all class fields and read their annotations. The method is designed to use it in PersonInfo class, since it uses this object. If you’d wish to put it in another file, you’d have to pass the class as a parameter. Analyze method’s body carefully:

public String processAnnotations(boolean includeSensitiveData) {
  StringBuilder sb = new StringBuilder();
  try{
   for(Field classField : this.getClass().getDeclaredFields()) {
    for(Annotation annotation : classField.getAnnotations()) {
     if(annotation.annotationType() == PersonalData.class) {
      PersonalData personalData = (PersonalData) annotation;
      String result = printPersonalData(includeSensitiveData, classField, personalData);
      sb.append(result);
     }
    }
   }
  } catch (IllegalArgumentException | IllegalAccessException e) {
   e.printStackTrace();
  }

 return sb.toString();
 }

Note: Use Java 7 to compile it. Otherwise refactor the catch block to two separate blocks, each catching one exception.

The printPersonalData() method is as follows:

private String printPersonalData(boolean includeSensitiveData, Field classField, PersonalData personalData)
   throws IllegalAccessException {
  StringBuilder sb = new StringBuilder();
  if(personalData.isSensitive()){
   if(includeSensitiveData){
    sb.append(buildText(classField));
   }
  }else{
   sb.append(buildText(classField));
  }
  return sb.toString();
 }

And buildText() is the simple one. It concatenates the field’s name and its value:

private String buildText(Field f) throws IllegalArgumentException, IllegalAccessException {
  return f.getName() + ": " + f.get(this) + "\n";
 }

3. Create your annotation

Creating custom annotation is as simple as creating Java interface. This is the PersonalData annotation’s implementation:

@Documented
 @Target(ElementType.FIELD)
 @Retention(RetentionPolicy.RUNTIME)

public @interface PersonalData {
  boolean isSensitive();
 }

The interface definitione is simple. It is syntaxed like any other java interface, but with the @interface annotation. The interface withoud methods would be enough to make it work. The boolean isSensitive(); method declaration gives the ability to define more details while annotating the field.

There are three builtin annotations used in front of @interface definition. This is their meaning:

@Documented means that this annotation will appear in JavaDoc

@Target(ElementType.FIELD) indicates that this annotation may be used with fields only. Other options are methods, types, packages, etc.

@Retention(RetentionPolicy.RUNTIME) means that annotation will be preserved at runtime. Other option is SOURCE, meaning that it would be available only at development time.

4. Get the source code

You are welcome to tinker with my code freely, on your own. Just download the source code from here.

Did I help you?
I manage this blog and share my knowledge for free, sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!





Android status bar notifications [complete tutorial with source code]

1 02 2014

Displaying status bar notification is a common way to unobtrusively inform user that something has happened (like new GMail message notification). In your app you can display it whenever you want. I will guide you how to do it from basics. This is how notifications are presented to the user:

Status bar notifications

Status bar notifications

Google’s documentation regarding the notifications is here.

Source Code

All the source code for this tutorial you can download here.

1. Create Basic notification

Notification consists of three obligatory parameters: title text, content text and small icon image. Here is the code that creates such notification:

private Notification createBasicNotification() {
	NotificationCompat.Builder builder = new Builder(getApplicationContext());
	Notification notification = builder
			.setSmallIcon(R.drawable.me)
			.setContentTitle(getString(R.string.notif_title))
			.setContentText(getString(R.string.notif_text))
			.build();

	return notification;
}

2. Display Basic Notification

After it is built, you can display it to the user with NotificationManager:

private void displayNotification(Notification notification) {
	NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
	notificationManager.notify(myNotificationId , notification);
}

Where myNotificationId is final int and is equal to 1:

private static final int myNotificationId = 1;

Thanks to this ID later you can refer to that notification and update its content  or hide it when you need it.

This is how the notification looks like right now:

notif_my_custom

3. Auto Hide notification after it is touched

As for now nothing happens when user touches notification. To make it disappear after touch add this clause to the builder:

setAutoCancel(true)

4. Start activity after notification is touched

The most common action after user selects notification is to open activity presenting the detailed data that caused notification to be issued. You have to assign PendingIntent to notification in order to do it:

private PendingIntent preparePendingIntent() {
	Intent intent = new Intent(getApplicationContext(), MainActivity.class);
	intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

	PendingIntent pendingIntent = PendingIntent.getActivity(
			getApplicationContext(), 
			0, 
			intent, 
			PendingIntent.FLAG_UPDATE_CURRENT);
	return pendingIntent;
}

After that, you assign this intent to notification with the builder command:

.setContentIntent(notificationIntent)

Now you have a basic notification that can issue certain action. Further customization is optional and introduced in newer versions of Android. Since possibilities are quite big, it is worth to continue improving the notification.

5. Filling in remaining small notification fields

Here is the code to fill in the remaining fields of small notification (this should be called on bilder object):

.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.me))
.setContentInfo(getString(R.string.notif_contentInfo))
.setWhen(Calendar.getInstance().getTimeInMillis() + 1000*60+60)
.setVibrate(vibrationPattern)

In order to make vibrations work you need to define pattern (mine is quite sophisticated :P):

long[] vibrationPattern = {0, 200, 800, 200, 600, 200, 400, 200, 200, 200, 100, 200, 50, 200, 50, 200, 50, 200, 500, 200};

but it surely can be simplier:

// Start without a delay
// Vibrate for 100 milliseconds
// Sleep for 1000 milliseconds
long[] pattern = {0, 100, 1000};

and require an VIBRATE permission in android manifest

<uses-permission android:name="android.permission.VIBRATE"/>

6. Apply big style to the notification

What actually is the Big Style? It is the notification with list of String. This is so called InboxStyle, since it is mainy used by GMail to notify user of incoming list of messages. This is how it looks like:

Notice that most of the elements are the same, except the 7 – the details list. Remember that big style works only for android versions higher than or equal to 4.2.

So now – how to build this list? Just create the notificationas it is done until now, and apply style to the builder:

.setStyle(inboxStyle)

And the inboxStyle is built like this:

private InboxStyle prepareBigNotificationDetails() {
	NotificationCompat.InboxStyle result = new InboxStyle();
	result.setBigContentTitle(getString(R.string.notif_inboxStyleTitle));
	result.addLine(getString(R.string.notif_inboxStyle_line1));
	result.addLine(getString(R.string.notif_inboxStyle_line2));
	result.addLine(getString(R.string.notif_inboxStyle_line3));
	result.addLine(getString(R.string.notif_inboxStyle_line4));
	result.addLine(getString(R.string.notif_inboxStyle_line5));
	result.addLine(getString(R.string.notif_inboxStyle_line6));
	return result;
}

Now test it (remember that only android 4.2 or higher will handle such notification). The result is like this:

InboxStyle notification

InboxStyle notification

notice that fields displayed on small notification are not visible in this style.

7. Updating notification content

Notification updates are quite simple: just set the fields you want to change with notification builder and call NotificationManagers’ notify() method providing the ID that you assigned to the notification that you need to update. The notification will be updated accordingly.

Download the Source Code

All the source code for this tutorial you can download here.

Did I help you?
I manage this blog and share my knowledge for free, sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!








%d bloggers like this: