List of String and long String

Viewed 65

Suppose I have a list of Book where the number of books can be quite large. I'm logging the isbn of those books. I've come up with two approaches, would there be any performance difference / which approach is considered as better ?

My concern with 2) will be whether the length of String is too long to become an issue. Refer to How many characters can a Java String have?, it's not likely it will hit the max number of characters, but I'm not sure on the point about "Half your maximum heap size", and whether it's actually a good practice to construct a long String.

  1. Convert to list of String
List<Book> books = new ArrayList<>();
books.add(new Book().name("book1").isbn("001"));
books.add(new Book().name("book2").isbn("002"));

if (books != null && books.size() > 0) {
  List<String> isbns = books.stream()
                            .map(Book:getIsbn)
                            .collect(Collectors.toList());
  logger.info("List of isbn = {}", isbns);
} else {
  logger.info("Empty list of isbn");
}
  1. Using StringBuilder and concatenate as one long String
List<Book> books = new ArrayList<>();
books.add(new Book().name("book1").isbn("001"));
books.add(new Book().name("book2").isbn("002"));

if (books != null && books.size() > 0) {
  StringBuilder strB = new StringBuilder();
  strB.append("List of isbn: ");
  books.stream()
       .forEach(book -> {
         strB.append(book.getIsbn());
         strB.append("; ");
       });
  logger.info("List of isbn = {}", strB.toString());
} else {
  logger.info("Empty list of isbn");
}

1 Answers

... but I'm not sure on the point about "Half your maximum heap size"

The JVM heap has a maximum size set by command line options, or by defaults. If you fill the heap, your JVM will throw and OutOfMemoryError (OOME) and that will typically cause your application to terminate (or worse!).

When you construct a string using a StringBuilder the builder uses a roughly exponential resizing strategy. When you fill the builder's buffer, it allocates a new one with double the size. But the old and new buffers need to exist at the same time. So when the buffer is between 1/2 and 2/3rds of the size of the entire heap, and the buffer fills up, the StringBuilder will attempt allocate a new buffer that is larger than the remaining available space and an OOME will ensue.


Having said that, assembling a single string containing a huge amount of data is going to be bad for performance even if you don't trigger an OOME. A better idea is to write the data via a buffers OutputStream or Writer.

This may be problematic if you are outputting the data via a Logger. But I wouldn't try to use a Logger for that. And I certainly wouldn't try to do it using a single Logger.info(...) call.

Related