Multi statement lambda and for each anti patterns

When I do a code review of lambda/stream code, I am immediately suspicious of two things – block statement lambdas and forEach().

What’s wrong with this? It’s functional programming right?

List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
		
AtomicInteger sum = new AtomicInteger();
List<Integer> odds = new ArrayList<>();
List<Integer> evens = new ArrayList<>();
		
list.forEach(n -> {
	sum.addAndGet(n);
	if (n % 2 == 0) {
		evens.add(n);
	} else {
		odds.add(n);
	}
});
		
odds.forEach(System.out::println);
System.out.println();
evens.forEach(System.out::println);
System.out.println();
System.out.println(sum);

Well? Not really. It does have a lambda. It doesn’t have a stream, but that’s easy enough to fix: list.stream().forEach(…).

All better? No. Just because you are using a stream doesn’t mean you are doing functional programming. I would much rather see this code as:

List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
		
		
list.stream()
   .filter(x -> x % 2 == 1)
   .forEach(System.out::println);

System.out.println();

list.stream()
   .filter(x -> x % 2 == 0)
   .forEach(System.out::println);

System.out.println();

list.stream()
   .mapToInt(x -> x)
   .sum();

Yes, I’m still using forEach(). But now I’m using it for one purpose (printing) rather than sticking logic in it.

Whenever I see a forEach() or lambda with more than one statement, my first thought is “could this be clearer or more functional.” Often the answer is yes. Filter(), map() and collect() are you friends.

And if I did need that List?

list.stream()
   .filter(x -> x % 2 == 1)
   .collect(Collectors.toList());

Supplemental Material: doPrivileged()

Privileged access was added to the Security objective for Oracle’s Java 11 1Z0-819 Exam, but was not part of the objectives for the now retired 1Z0-816 Exam. We created this Supplemental Material and are releasing it free of charge for all those readers who purchased one of our Java 11 Study Guides. You should read this section carefully before taking the 1Z0-819 Exam. See other changes on The 1Z0-819 Exam page.

Overview

Some Java programs run in an environment where the user does not have full control over the program. In other words, the program runs a privileged action on behalf of the user. The idea for the developer is straight-forward:

  • I have a privileged action I need run for a user
  • I need to verify the user has the proper permission before running the action
  • I need to make sure they are limited in what actions they can run
  • I need to make sure they don’t using caching or other tricks to skip the permission check

Java performs a privileged action using the AccessController.doPrivileged() method found in the java.security package. While using this method is not commonly used by most Java developers, it is required knowledge for the 1Z0-819 Exam.

1. The doPrivileged() method

A common example Oracle likes to use is reading a system property. The idea is that the programmer is only allowed to read a specific predefined system property.

import java.security.*;
public class MySecretReader {
   private static final String KEY = "secret.option";
   public String getSecret() {
      return AccessController.doPrivileged(
         new PrivilegedAction<String>() {
            public String run() {
               return System.getProperty(KEY);
            }
         });
   }
}

Here KEY is a constant that cannot be changed by the user. The idea here is that a user’s privilege is temporarily elevated so they can read the secret.option value within the system.

2. Ensure Principle of Least Privilege

When executing a privileged action, it is important to ensure that only the minimum access is granted. This is known as the principle of least privilege. Can you spot what’s wrong with the following example?

import java.security.*;
public class MySecretReader {
   public String getSecret(String magicWord) {
      return AccessController.doPrivileged(
         new PrivilegedAction<String>() {
            public String run() {
               return System.getProperty(magicWord);  // DON'T DO THIS!
            }
         });
   }
}

In this example, the caller is able to specify which value they want to read. This is considered a poor practice as it allows them to read any property within the system. Oracle refers this as a tainted input. Put simply, don’t trust anything the user provides when dealing with security. Also use a constant or predefined list to confirm they are accessing only what the original developer intended.

For the exam, be wary of any code that allows the user to access data that they specify, rather than the original programmer.

3. Don’t Expose Sensitive Information

Another important aspect of using doPrivileged() is ensuring sensitive data is protected. For example, can you spot the security risk in this code?

import java.security.*;
import java.util.*;
public class MySecretReader {
   private final List<Integer> codes = ...
   public List<Integer> getSecret() {
      return AccessController.doPrivileged(
         new PrivilegedAction<List<Integer>>() {
            public List<Integer> run() {
               return codes;  // DON'T DO THIS!
            }
         });
   }
}

Even though codes is marked final, the content can still be modified after the doPrivileged() is complete. This poses an unacceptable security risk. A much safer version would be to return an immutable copy of the list, such as:

      return AccessController.doPrivileged(
         new PrivilegedAction<List<Integer>>() {
            public List<Integer> run() {
               return Collections.unmodifiableList(codes);
            }
         });

Note that this works because Integer values are immutable. If the contents of the List were mutable, such as List<StringBuilder>, you want to copy them as well.

4. Don’t Elevate Permissions

Privilege elevation or escalation occurs when a user is mistakenly given access to a higher privilege than they should have access to. One way to prevent privilege elevation is to use to the AccessController.checkPermission() method before calling doPrivileged(), then execute the command with limited permissions.

import java.security.*;
public class MySecretReader {
   public void readData(Runnable task, String path) {
      // Check permission
      Permission permission = new java.io.FilePermission(path,"read");
      AccessController.checkPermission(permission);

      // Execute task with limited permission
      final var permissions = permission.newPermissionCollection();
      permissions.add(permission);
      AccessController.doPrivileged(
         new PrivilegedAction<Void>() {
            public Void run() {
               task.run();
               return null;
            }
         },
         // Using a limited context prevents privilege elevation
         new AccessControlContext(
            new ProtectionDomain[] {
               new ProtectionDomain(null, permissions)
            })
         );
   }
}

Don’t worry if you can’t write code like this, most developers never have to. For the exam, though, you should understand that the permission is being checked and the action is executed with a specific context.

5. Be wary of Permission Caching

The last rule you need to know for the exam is to be weary of cached permissions. It is perfectly acceptable to cache permission information, but the permission needs to be checked every time the user accesses it.

For example, assuming there’s a User class with appropriate attributes, methods and constructors, can you spot the problem in this code?

import java.security.*;
import java.util.*;
public class SecretFile {
   private static Map<String, User> data = new HashMap<>();
   public static SecretFile get(String key) {
      var cacheRecord = data.get(key);
      if (cacheRecord != null) {
         // DON'T DO THIS!
         return cacheRecord.getValue();
      }
      
      final var permission = Permission permission 
         = new PropertyPermission(key,"read");
      AccessController.checkPermission(permission);

      final var permissions = permission.newPermissionCollection();
      permissions.add(permission);
      var secret = AccessController.doPrivileged(
         new PrivilegedAction<SecretFile>() {
            public SecretFile run() {
               return new SecretFile();
            }
         }, new AccessControlContext(new ProtectionDomain[] {
               new ProtectionDomain(null, permissions) }));
      data.put(key, new User(secret, permission));
      return secret;
   }
}

Did you spot it? It might be hard to see, but there’s no permission check when the data is read from the cache! The permission is checked when the data is first read from the cache but not on subsequent calls. We can easily fix this though by checking the permission when it is read from the cache:

      var cacheRecord = data.get(key);
      if (cacheRecord != null) {
         AccessController.checkPermission(cacheRecord.getPermission());
         return cacheRecord.getValue();
      }

In this example, we see that cached permissions can be safe to use but we have to make sure the permission is validated when it is read the first time and on each request from the cache.

Conclusion

There, you’re done! This post covered the overall topics around Privileged Access that you need to know for the 1Z0-819 Exam. The following bullet points summarize the kinds of things you should be watching for on the 1Z0-819 Exam:

  • Always validate user input and never allow it to grant access to arbitrary data
  • Never give the user unlimited access to the system
  • Prevent privilege elevation by validating security
  • Never return privileged objects directly or in a way that they can be modified
  • Ensure cached permissions are validated on every call

If you enjoyed this section, you can read more about it in Oracle’s Secure Coding Guidelines for Java SE document.

Taking the 1Z0-819 Exam: Study Everything and Watch the Clock! (Part 2 of 2)

Update (11/05/2020): Read The 1Z0-819 Exam page to learn how you can easily our Java 11 Study Guides to prepare for Oracle’s 1Z0-819 Exam, as well as the 1Z0-817 Upgrade Exam.

In Part 1 of my experience taking the 1Z0-819 exam, I described my overall experience taking the new Java 11 Oracle Certified Professional exam. In Part 2, I’ll go into more detail about some of the finer points for those planning to take this new exam using our Programmer I or Programmer II books, or the combined Complete Study Guide.

TLDR: Yes, our Java 11 books are perfect for the new 1Z0-819 exam! I scored an 87% myself, although I was focused more on studying the exam than passing it. Read on if you plan to take the new 1Z0-819 exam!

1. Differences in Material between the Old and New Exams

By comparing the 1Z0-815/1Z0-816 and 1Z0-819 exam objectives, you might be inclined to think the material is radically different, but really isn’t. For most of the objectives, Oracle just took 2-3 objectives and rewrote the sentences to form a single objective. This is from someone who spent hours studying every word of all sets of objectives! See, not so scary is it?

That said, there are some differences between the 1Z0-815/1Z0-816 exams and the 1Z0-819 exam that you should be familiar with. Jeanne and I will be posting an addendum page on this blog for the people who purchase our Java 11 books to ensure they are properly prepared. For now, though, these are the important differences:

  • Assertions are gone! This is just since most Java developers tend to use JUnit rather than the built-in assert keyword. When you get to this section in our books, feel free to skip it and have a snack!
  • CallableStatement are also gone! Jeanne and I were never thrilled this was on the exam as the usage can dependent very much on the database. You can skip this section too and have a drink with your snack!
  • Oracle added the word privileged to the security objective and this results in the doPrivileged() method now being in scope. For these questions, you need to read Section 9 of the Oracle Secure Coding Guidelines for Java SE. Some people reported seeing doPrivileged() on the 1Z0-816 exam, though, so it’s possible Oracle updated the 1Z0-816 exam more recently with this topic.

2. Studying for the 1Z0-819 Exam using our Books

Since the changes between the old and new exams are minimal, we still strongly recommend our Java 11 books to study for the new 1Z0-819. Since we were part of the team that helped design the objectives for the new 1Z0-819 exam, we were careful to keep the amount of new material to an absolute minimum. After taking the new exam, we are confident they can be used to successfully prepare for an pass the 1Z0-819 exam.

Now you may be asking, which of our books should you use? We recommend one of the following two options:

Before you rush to buy the Java 11 Complete Study Guide (since it’s one book instead of two), be aware that the physical edition is 1200+ pages long! And, the other two books contain the same material. In other words, if you plan to carry the book around on a train or bus, I recommend buying the first two books over the Complete Study Guide. Although if you’re going with the eBook edition, then go with whatever is cheaper!

3. Coming Soon: 1Z0-819 Practice Test Book

Jeanne and I recently finished the manuscript for our new Java 11 Practice Test book. This book has been updated and custom fit for the new 1Z0-819 exam. It is scheduled be released at the end of the year or early 2021.

4. Missing Strikethrough Exam Software Feature

On previous exams, you could right-click on an answer choice and it would cause it to strikethrough. This was extremely helpful for process of elimination and especially now that some questions have up to 10 answer questions! Unfortunately, this feature was not available when we took the exam. It’s not clear if this was a bug or Oracle has since pulled the feature, but I hope they bring it back. I had to actually write ABCDEFGHIJ on my scratch pad for some questions and cross them out one by one! Especially difficult when you can’t erase on the whiteboard they give you.

5. 1Z0-819 Exam vs 1Z0-817 Upgrade Exam: Scott’s Recommendation

If you hold a previous Oracle Certified Professional (not Associate) title, then you can still take the Java 11 1Z0-817 Upgrade Exam rather than the Java 11 1Z0-819 Exam. At this time, Oracle does not have any plans to retire the Upgrade exam.

My recommendation is given the choice between the two exams, I’d rather take the 1Z0-817 Upgrade exam. First off, the material is narrower in scope. Very few of the topics from from the previous 1Z0-815 exam appear and many of the topics from the 1Z0-816 exam (annotations, JDBC, security) are gone as well. In other words, you only have to study a dozen chapters from our Programmer II book, along with the Upgrade Appendix we included in the book, rather than potentially all of the chapters in the Complete Study Guide.

While the 1Z0-817 upgrade exam has more questions than the 1Z0-819 exam, you have 3 hours. Since I found the questions on the 1Z0-817 exam to be often shorter with fewer answer choices than the questions on the 1Z0-819, I feel you have a lot more time to think on the upgrade exam. I was not remotely worried about running out of time when I took the 1Z0-817 upgrade exam.

The only downside to taking the 1Z0-817 upgrade exam is that it contains a lot of questions on modules. In fact, 3 out of 10 of the objective sets are modules on the 1Z0-817 exam! It is fair to say modules did not feature nearly as prominently on the 1Z0-819 exam, so if you don’t like modules than the 1Z0-819 might be a better fit for you.

6. Exam Center Process

I opted to take the exam in-person after hearing some scary stories about at-home software tracking your eye movement and what not. Below are my comments from taking it in the time of COVID:

  • Temperature check and handwash station as soon as I walked in the door. The testing center I was at had a thermometer mounted to the wall I had to stand in front of.
  • Had to keep my mask on the entire time, except when I was signing in and they wanted to check my ID and take my picture.
  • To my surprise, there were 3 other people taking tests too, we were placed on opposite corners of the room.
  • I received my score as soon as I clicked “Finish” to end the exam. It was shown on the screen.
  • The test center handed me “Score Report” which had nothing on it except instructions to go online. My score was not printed.

Conclusion

So, that’s my personal experience taking the new Java 11 1Z0-819 exam. At the end of the day, I’m actually happy Oracle dropped the two exam requirement for the certification. After all, it cuts the price for certification in half! I just wish they had started with this approach, rather than retiring the 1Z0-815/1Z0-816 merely a year after they were released. Their roll of out the new exam was hastily done to say the least.

Jeanne and I have heard from numerous readers that this has thrown their study plans into complete disarray. To those readers, I completely empathize. Just imagine how it’s impacted two authors who’ve devoted a significant amount of time in their lives to creating study material for the Java 11 exams. It’s been quite a ride, but happily our Java 11 books are still the best source of material for studying for the exam!