Limited size queue

04 January 2017

The Java Collections Queue implementations will either grow without limit, or block if it grows beyond a given size, like the LinkedBlockingDeque. However, what if you need a non-blocking queue which drops its oldest elements? The Apache Commons CircularFifoQueue covers that. The snippet below shows typical use, with a queue size of two, and where the first element of three is dropped.

  public void testDrop() {
    CircularFifoQueue<Integer> queue = new CircularFifoQueue<>(2);

    queue.add(1);
    queue.add(2);
    queue.add(3);

    assertTrue(2 == queue.poll());
    assertTrue(3 == queue.poll());
    assertTrue(queue.isEmpty());
  }

To install the Apache Commons 4.0 library on Debian / Ubuntu:

apt-get install libcommons-collections4-java libcommons-collections4-java-doc
apt-get source libcommons-collections4-java

The relevant files will be located at:

/usr/share/java/commons-collections4.jar  
/usr/share/maven-repo/org/apache/commons/commons-collections4/4.0/commons-collections4-4.0-javadoc.jar

Often, a queue is populated on one thread, and consumed by another. In this case, the access methods have to be synchronized, as seen in this example. Both offer() and poll() methods are non-blocking, and null is returned if the queue is empty.

  public void testMultithreaded() {
    CircularFifoQueue<Integer> queue = new CircularFifoQueue<>(5);

    Thread insertThread = new Thread(() -> {
      int i = 0;
      while (true) {
        synchronized (queue) {
          queue.offer(i++);
        }
      }
    });
    insertThread.start();

    sleep(1);
    for (int i = 0; i < 10; i++) {
      synchronized (queue) {
        System.out.println("" + i + ": " + queue.poll());
      }
    }
  }

Finally, how does this queue work with Streams? In a single-thread context, there shouldn’t be a problem. However, when multithreaded it gets more tricky. The example below fails since the two threads operate on the queue concurrently, and a NoSuchElementException is often thrown. The ConcurrentLinkedQueue is thread-safe, but unbounded. Furthermore, its documentation states that “the size method is NOT a constant-time operation. Because of the asynchronous nature of these queues, determining the current number of elements requires a traversal of the elements, and so may report inaccurate results if this collection is modified during traversal”. Which means we’re back to square one.

  public void streamFail() {
    CircularFifoQueue<Integer> queue = new CircularFifoQueue<>(10);

    Thread insertThread = new Thread(() -> {
      int i = 0;
      while (true) {
        queue.offer(i++);
      }
    });
    insertThread.start();

    sleep(1000);
    System.out.println("size=" + queue.size());
    // throws NoSuchElementException
    queue.stream().forEach(System.out::println);
  }

There are a few work-arounds, mentioned in this discussion. One trick is to use the Stream.generate() method, which will loop indefinilty, and synchronize on the queue within. The problem is, that this will never stop, which might be okey depending on your application. However, you’d have to run this on a spearate thread. Alternativly, use the limit() method or a stream terminating operation (e.g. findFirst()).

  public void streamGenerate() {
    CircularFifoQueue<Integer> queue = new CircularFifoQueue<>(10);

    Thread insertThread = new Thread(() -> {
      int i = 0;
      while (true) {
        synchronized (queue) {
          queue.offer(i++);
        }
      }
    });
    insertThread.start();

    Stream.generate(() -> {
      synchronized (queue) {
        return queue.poll();
      }
    })
    // Never stops without the limit
    .limit(20)
    .forEach(System.out::println);
  }

Also worth mentioning, is the Google Guava implementation EvictingQueue. However, it it also not thread-safe.

Here’s the full listing with all test methods.

CircularFifoQueueTest.java
GitHub Raw
/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */
package com.rememberjava.apache;

import static org.junit.Assert.assertTrue;

import java.util.stream.Stream;

import org.apache.commons.collections4.queue.CircularFifoQueue;
import org.junit.Test;

public class CircularFifoQueueTest {

  @Test
  public void testDrop() {
    CircularFifoQueue<Integer> queue = new CircularFifoQueue<>(2);

    queue.add(1);
    queue.add(2);
    queue.add(3);

    assertTrue(2 == queue.poll());
    assertTrue(3 == queue.poll());
    assertTrue(queue.isEmpty());
  }

  @Test
  public void testMultithreaded() {
    CircularFifoQueue<Integer> queue = new CircularFifoQueue<>(5);

    Thread insertThread = new Thread(() -> {
      int i = 0;
      while (true) {
        synchronized (queue) {
          queue.offer(i++);
        }
      }
    });
    insertThread.start();

    sleep(1);
    for (int i = 0; i < 10; i++) {
      synchronized (queue) {
        System.out.println("" + i + ": " + queue.poll());
      }
    }
  }

  @Test
  public void streamFail() {
    CircularFifoQueue<Integer> queue = new CircularFifoQueue<>(10);

    Thread insertThread = new Thread(() -> {
      int i = 0;
      while (true) {
        queue.offer(i++);
      }
    });
    insertThread.start();

    sleep(1000);
    System.out.println("size=" + queue.size());
    // throws NoSuchElementException
    queue.stream().forEach(System.out::println);
  }

  @Test
  public void streamGenerate() {
    CircularFifoQueue<Integer> queue = new CircularFifoQueue<>(10);

    Thread insertThread = new Thread(() -> {
      int i = 0;
      while (true) {
        synchronized (queue) {
          queue.offer(i++);
        }
      }
    });
    insertThread.start();

    Stream.generate(() -> {
      synchronized (queue) {
        return queue.poll();
      }
    })
    // Never stops without the limit
    .limit(20)
    .forEach(System.out::println);
  }

  private void sleep(long millis) {
    try {
      Thread.sleep(millis);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

Sequential vs. Parallel Streams

31 December 2016

The Java 8 Streams API offers functional-style operations, and a simple way to execute such operations in parallel. To jump right into an example, the following two test methods show the difference between sequential and parallel execution of the the println() method over each of the elements of the stream.

    range = IntStream.range(1, RANGE);
  }

  @Test
  public void sequential() {
    range.forEach(PRINTLN);
  }

  @Test
  public void parallel() {
    range.parallel().forEach(PRINTLN);
  }

As is expected, the default sequential execution will print the elements of the stream, which in this example are integers from 1 to 14, in natural order. By using the parallel() method to create a parallel stream and call the same print method, the only noticeable difference is that they are printed out of order.

 --- sequential ---      --- parallel ---
1                       9
2                       12
3                       5
4                       4
5                       13
6                       7
7                       6
8                       11
9                       10
10                      1
11                      2
12                      14
13                      3
14                      8

To see how the parallel stream behaves, the last test applies a different method to each of the elements of the stream. In this example, the time spent by the work() method on each element is linearly proportional to its value. That is, for the element of value 1 it spends 100ms, for 2 its 200 ms and so on. The “work” it does, is simply to sleep for intervals of 100 ms, and the rest of the code is dedicated to printing and formatting the table below. However, it serves the purpose of demonstrating how parallel execution behaves, and how it relates to the underlying CPU(s).

    range.parallel().forEach(this::work);

In the result table, each element of the stream is represented by a row. Each row shows the value of the element, the time-slots the work() method was executing, and to the right the time in milliseconds when work started and finished. Each 100 ms slot is represented by a hash. As can be seen, the first row was element 9, thus it marked off nine slots, and the starting time was at 6 ms, and finish at 909 ms.

Furthermore, since this was run on a machine with four CPU cores, the stream will execute four calls in parallel. This can be seen by both the hashes and the start times of the first four rows. Next, when element 2 (fourth row) finishes at 207 ms, a new element is immediately started (element 3, fifth row).

In this example, the total number of 100 ms “units of work” can be found by the formula for the triangular number where n = 14, or 14 * (14 + 1) / 2 = 105. Meaning that, sequential execution would have taken 10.5 seconds, while four parallel CPUs managed in 3 seconds.

In the second table below, the same code is executed on a dual core CPU, and it is clear that now only two methods execute in parallel. That will of course lead to a longer overall runtime, of about 5.4 seconds for this example. This could lead to a discussion on task and scheduling optimisation, however it goes beyond this article, and what is possible with the simple parallel Stream construct.

 --- parallelWork ---
CPU count: 4

    0000000000111111111122222222223333
    0123456789012345678901234567890123
 9:  #########                          [   6 -  909]
13:  #############                      [   6 - 1312]
 5:  #####                              [   6 -  507]
 2:  ##                                 [   6 -  207]
 3:    ###                              [ 207 -  507]
 4:       ####                          [ 507 -  909]
 1:       #                             [ 507 -  608]
 7:        #######                      [ 609 - 1312]
10:           ##########                [ 911 - 1915]
12:           ############              [ 911 - 2116]
14:               ##############        [1313 - 2719]
 6:               ######                [1313 - 1915]
 8:                     ########        [1915 - 2719]
11:                     ###########     [1915 - 3021]
    0123456789012345678901234567890123
    0000000000111111111122222222223333
 --- parallelWork ---
CPU count: 2

    00000000001111111111222222222233333333334444444444555555555
    01234567890123456789012345678901234567890123456789012345678
 8:  ########                                                    [  23 -  825]
 4:  ####                                                        [  23 -  424]
 5:      #####                                                   [ 424 -  926]
 9:          #########                                           [ 826 - 1727]
 6:           ######                                             [ 926 - 1527]
 7:                 #######                                      [1527 - 2228]
10:                   ##########                                 [1727 - 2729]
 1:                        #                                     [2229 - 2329]
 2:                         ##                                   [2329 - 2529]
 3:                           ###                                [2530 - 2830]
13:                             #############                    [2729 - 4031]
11:                              ###########                     [2831 - 3932]
12:                                         ############         [3933 - 5134]
14:                                          ##############      [4031 - 5433]
    01234567890123456789012345678901234567890123456789012345678
    00000000001111111111222222222233333333334444444444555555555

The full code list is here.

ParallelCount.java
GitHub Raw
/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */
package com.rememberjava.lambda;

import java.time.Duration;
import java.time.Instant;
import java.time.temporal.TemporalAmount;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
import java.util.function.IntConsumer;
import java.util.stream.IntStream;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;

public class ParallelCount {

  @Rule
  public TestName name = new TestName();

  private static final IntConsumer PRINTLN = System.out::println;

  private static final int RANGE = 15;

  private int axisWidth;

  private static final int WORK_UNIT_MILLIS = 100;

  private List<StringBuilder> results = new Vector<>(RANGE);

  private TemporalAmount start;

  private IntStream range;

  @Before
  public void setup() {
    String methodName = name.getMethodName().split("\\[")[0];
    System.out.println("\n --- " + methodName + " ---");

    int cpus = Runtime.getRuntime().availableProcessors();
    int workUnits = RANGE * (RANGE + 1) / 2;
    axisWidth = (int) ((workUnits / cpus) * 1.3);

    start = Duration.between(Instant.EPOCH, Instant.now());

    range = IntStream.range(1, RANGE);
  }

  @Test
  public void sequential() {
    range.forEach(PRINTLN);
  }

  @Test
  public void parallel() {
    range.parallel().forEach(PRINTLN);
  }

  @Test
  public void parallelWork() {
    System.out.printf("CPU count: %d\n\n",
        Runtime.getRuntime().availableProcessors());
    printAxis(true);

    range.parallel().forEach(this::work);

    results.stream().map(sb -> sb.toString()).forEach(System.out::println);
    printAxis(false);
  }

  void work(int units) {
    StringBuilder result = new StringBuilder();
    results.add(result);

    char[] timestampSlots = new char[axisWidth];
    Arrays.fill(timestampSlots, ' ');

    long startMillis = getNowMillis();

    try {
      for (int i = 0; i < units; i++) {
        Thread.sleep(WORK_UNIT_MILLIS);

        int nowSlot = (int) (getNowMillis() / WORK_UNIT_MILLIS);
        timestampSlots[nowSlot] = '#';
      }
    } catch (InterruptedException e) { // ignore
    }

    long endMillis = getNowMillis();

    result.append(String.format("%2d: %s [%4d - %4d]",
        units, new String(timestampSlots), startMillis, endMillis));
  }

  private void printAxis(boolean header) {
    String row1 = "";
    String row2 = "";
    for (int i = 0; i < axisWidth - 1; i++) {
      row1 += i / 10;
      row2 += i % 10;
    }

    System.out.println("    " + (header ? row1 : row2));
    System.out.println("    " + (header ? row2 : row1));
  }

  private long getNowMillis() {
    return Instant.now().minus(start).toEpochMilli();
  }
}

TrayIcon Example

17 December 2016

Tray Icon

Since Java 6, adding a system tray icon has been straight forward. The two main classes involved are SystemTray and TrayIcon. Various OS might render and operate the icon differently. Typically, there is a status message on hover, a short-cut action on left click, and possibly a menu on right click. The TrayIcon supports all this. In the example code below, an 16x16 pixel PNG is used, and auto-scaled up to about 24 pixels, which is what I’ve configured by XFCE panel.

  private void initIcon() throws AWTException {
    if (!SystemTray.isSupported()) {
      System.err.println("System tray not supported.");
      return;
    }

    Image image = Toolkit.getDefaultToolkit().getImage(
        "com/rememberjava/ui/favicon_16.png");

    TrayIcon trayIcon = new TrayIcon(image, "RJ Tray Demo", popup);
    trayIcon.setImageAutoSize(true);

    SystemTray tray = SystemTray.getSystemTray();
    tray.add(trayIcon);
  }

Here’s the full example class listing.

TestTrayIcon.java
GitHub Raw
/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */
package com.rememberjava.ui;

import java.awt.AWTException;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;

public class TestTrayIcon {

  private PopupMenu popup;

  public static void main(String[] args) throws Exception {
    TestTrayIcon test = new TestTrayIcon();
    test.initMenu();
    test.initIcon();
  }

  private void initMenu() {
    popup = new PopupMenu();

    addMenuItem("item1");
    addMenuItem("item2");
  }

  private void addMenuItem(String label) {
    MenuItem item = new MenuItem(label);
    item.addActionListener(this::click);
    popup.add(item);
  }

  private void click(ActionEvent e) {
    System.out.println("Clicked: " + e.getSource());
  }

  private void initIcon() throws AWTException {
    if (!SystemTray.isSupported()) {
      System.err.println("System tray not supported.");
      return;
    }

    Image image = Toolkit.getDefaultToolkit().getImage(
        "com/rememberjava/ui/favicon_16.png");

    TrayIcon trayIcon = new TrayIcon(image, "RJ Tray Demo", popup);
    trayIcon.setImageAutoSize(true);

    SystemTray tray = SystemTray.getSystemTray();
    tray.add(trayIcon);
  }
}

A simple stupid calculator

12 December 2016

Calculator

This post includes the UI (Swing) for a very simple calculator. There’s not much to say about the code, except for the rather stupid way it handles the calculator operation itself: Using a JavaScript engine! The ScriptEngineManager and the internal NashornScriptEngineFactory JavaScript implementation have been around since Java 6 and 8 receptively. It makes it easy to execute a string as snippet of code, as seen below.

Here the model for the display of the calculator is just a plain string. That string is then evaluated as a line of JavaScript, and the output is returned and put back into the “model”.

  {
    NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
    engine = factory.getScriptEngine();
  }

  ...
  String model = "1 + 1";

  void calculate() {
    try {
      Object eval = engine.eval(model);
      model = eval.toString();
    } catch (ScriptException e) {
      // If the expression was invalid,
      // don't modify the calculator display.
    }
  }

In terms of the calculator functionality, this implementation is very simple, but therfore also limited. A more common way of implementing this would be through some object expression representation which can be evaluated. However, the Script Engine implementation has the benefit of supporting functionality which is not even implemented in the UI, like brackets or other operators like power-to (^). It works nicely has a prototype and quick mock, so maybe not so stupid after all.

To be continued…

For the full source of this first version, see here.

Tutorialspoint - compile and run code online

05 December 2016

Over at Tutorialspoint.com they have created a superb well of study material and tools. Most impressive are the online compiler and runtime terminals, dubbed Coding Ground, for a large selection of popular and obscure languages and tools. Here’s an example Java project, based on the previous article on word counting. Click Compile followed by Execute and the output from the snippet will show in the terminal. The data file “words” is included in the project. (Note that these terminal seems to run best in Chrome based browsers, and fails to load in Firefox).

Also worth checking out is their long list of tutorials for everything from Java; other programming languages; to sports and “soft skills”. Especially with the programming tutorials, their embedded online compiler & terminal feels very slick, as seen below.

My personal site fades in comparison, however, my goal is not to offer complete university courses. Remember Java will remain focused on exploration and examples of interesting aspects of the Java language.

Demo project

Tutorial

Word count

26 November 2016

Here’s another neat streams snippet, which in three lines handles what would take at least two loops in pre-Java 8 code. The task at hand is to count the number of occurrences of each unique word in a file. Given the content shown below, this Bash command line would solve it.

cat words | tr ' ' '\n' | sort | uniq -c

File content:

one two three four
two three four
three four four

Shell output:

  4 four
  1 one
  3 three
  2 two

The Java code follows a similar flow as seen in the pipes above: Read the file, split each line by space, and flatten the result from all lines into a single stream. Finally, the collect() function is used with the groupingBy() helper, to map each token (or word) in the stream (the identity) to its count.

    Map<String, Long> map = Files.lines(path)
        .flatMap(line -> Stream.of(line.split(" ")))
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

The Java map will contain the following key-value pairs. Here, the words are also accidentally sorted alphabetically. However, the order is not guaranteed by collect() function, since it returns a HashMap.

  {four=4, one=1, three=3, two=2}

The full listing:

WordCount.java
GitHub Raw
/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */
package com.rememberjava.lambda;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.Test;

public class WordCount {

  @Test
  public void countWords() throws IOException {
    Path path = Paths.get("com/rememberjava/lambda/words");

    Map<String, Long> map = Files.lines(path)
        .flatMap(line -> Stream.of(line.split(" ")))
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

    System.out.println(map);
  }
}

Fun with IO Streams

21 November 2016

With Java 8, file IO became a pleasure to work with. It was a drastic break from the old verbose syntax and awkward ((line = in.readLine()) != null) and try/try/close idioms. With the new Stream based methods and lambda functions, the IO API becomes more similar to Python in ease of use.

In the code snippet below, all the lines of a file is read, sorted, and printed.

    Path p = Paths.get("/etc/passwd");
    Files.lines(p).sorted().forEach(System.out::println);

The following lines do the same, but break up the in-line method invocations and returned objects, to more clearly see what’s going on.

    Path p = Paths.get("/etc", "passwd");
    Stream<String> lines = Files.lines(p);
    Stream<String> sorted = lines.sorted();
    sorted.forEach(System.out::println);
    lines.close();

Traversing the directory hierarchy is similarly easy and compact:

    Path p = Paths.get("/proc/bus");
    Files.walk(p).forEach(System.out::println);

Finally, here’s an idea for an assertFileEquals() method. It takes two file names, one which is the expected “golden” file which would contain the output from the test. (The example file names below are to make sure the test passes).

  @Test
  public void testGoldenFile() throws IOException {
    assertFileEquals("/proc/cpuinfo", "/proc/cpuinfo");
  }

  private void assertFileEquals(String expectedFile, String actualFile)
      throws IOException {
    String[] actual = readFile(expectedFile);
    String[] expected = readFile(actualFile);

    Assert.assertArrayEquals(expected, actual);
  }

  private String[] readFile(String filename) throws IOException {
    return Files.lines(Paths.get(filename)).toArray(String[]::new);
  }

Finally, here’s the full test file listing.

StreamFun.java
GitHub Raw
/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */
package com.rememberjava.lambda;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

import org.junit.Assert;
import org.junit.Test;

public class StreamFun {

  @Test
  public void printFile() throws IOException {
    Path p = Paths.get("/etc/passwd");
    Files.lines(p).sorted().forEach(System.out::println);
  }

  @Test
  public void printFileAlternative() throws IOException {
    Path p = Paths.get("/etc", "passwd");
    Stream<String> lines = Files.lines(p);
    Stream<String> sorted = lines.sorted();
    sorted.forEach(System.out::println);
    lines.close();
  }

  @Test
  public void walkDirectories() throws IOException {
    Path p = Paths.get("/proc/bus");
    Files.walk(p).forEach(System.out::println);
  }

  @Test
  public void testGoldenFile() throws IOException {
    assertFileEquals("/proc/cpuinfo", "/proc/cpuinfo");
  }

  private void assertFileEquals(String expectedFile, String actualFile)
      throws IOException {
    String[] actual = readFile(expectedFile);
    String[] expected = readFile(actualFile);

    Assert.assertArrayEquals(expected, actual);
  }

  private String[] readFile(String filename) throws IOException {
    return Files.lines(Paths.get(filename)).toArray(String[]::new);
  }
}

Hello Junit Test!

08 October 2016

Unit testing can sometimes be like washing the dishes: You know it should be done, that you’ll have to do it eventually, but it can always be postponed. On the other hand, executing your code through unit tests is a great way to verify that it works as expected, in a short amount of time and with little code overhead. Furthermore, writing unit tests is a convenient way to execute any kind of code easily, especially from within a modern IDE, where it is typically easier to run a single test method than a full executable. Many of the examples on this site will use unit tests as the driver.

Test Method

The “Hello World” minimal example of a Junit 4 test method can be seen in the first example below. All it takes, is a method (of any name) annotated with the @Test annotation. Typically, a test method will assert something against expected values, albeit in the examples below this is ineffectual.

package com.rememberjava.junit;

import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class HelloJunit {

  @Test
  public void test() {
    assertTrue(true);
  }
}

Setup and teardown

The anatomy of a test case class is as seen in the following example. Again, the method names are not relevant, and only the annotations indicate at what point they will be executed. All the annotations can appear on multiple methods, and the only additional requirements are that all annotated methods have to be public; and that the before and after class methods have to be static.

package com.rememberjava.junit;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class JunitTestMethods {

  @BeforeClass
  public static void setUpBeforeClass() {}

  @AfterClass
  public static void tearDownAfterClass() {}

  @Before
  public void setUp() {}

  @After
  public void tearDown() {}

  @Test
  public void test() {}
}

Order of execution

The final example below adds some flesh to the body of each of the methods, and illustrates a few basic principles of how the different methods are used.

  • The annotations indicate the order: BeforeClass, Before, Test, After, AfterClass.
  • BeforeClass and AfterClass methods are run once, while Before and After methods are executed for every Test method.
  • Since the Class level methods are static, any global fields they use also have to be static.
  • The class is re-constructed for every single Test method. This will reset all global fields, as seen in the output below.
  • The order between Test methods is typically chronological as they appear in the file, however, it is good practice not to rely on this. Or rather, Test methods should not depend on each other.
package com.rememberjava.junit;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class JunitTestMethodsOrder {

  private static int a;
  private int b;

  @BeforeClass
  public static void setUpBeforeClass() throws Exception {
    a = 1;
    System.out.println(a + " beforeClass");
  }

  @Before
  public void setUp() throws Exception {
    a++;
    b++;
    System.out.println(a + " setup " + b);
  }

  @Test
  public void firstTest() {
    a++;
    b++;
    System.out.println(a + " first " + b);
    assertTrue(a > 2);
  }

  @Test
  public void secondTest() {
    a++;
    b++;
    System.out.println(a + " second " + b);
    assertFalse(false);
  }

  @After
  public void tearDown() throws Exception {
    a++;
    b++;
    System.out.println(a + " tearDown " + b);
  }

  @AfterClass
  public static void tearDownAfterClass() throws Exception {
    a++;
    System.out.println(a + " afterClass");
  }
}

The test case above gives the following output. Notice the static a counter, and the global non-static b counter which is reset.

1 beforeClass
2 setup 1
3 first 2
4 tearDown 3
5 setup 1
6 second 2
7 tearDown 3
8 afterClass
Newer posts Older posts