I need something similar to String.format(...) method, but with lazy evaluation.
This lazyFormat method should return some object whose toString() method would then evaluate the format pattern.
I suspect that somebody has already done this. Is this available in any libararies?
I want to replace this (logger is log4j instance):
if(logger.isDebugEnabled() ) {
logger.debug(String.format("some texts %s with patterns %s", object1, object2));
}
with this:
logger.debug(lazyFormat("some texts %s with patterns %s", object1, object2));
I need lazyFormat to format string only if debug logging is enabled.
if you are looking for a "simple" solution:
public class LazyFormat {
public static void main(String[] args) {
Object o = lazyFormat("some texts %s with patterns %s", "looong string", "another loooong string");
System.out.println(o);
}
private static Object lazyFormat(final String s, final Object... o) {
return new Object() {
#Override
public String toString() {
return String.format(s,o);
}
};
}
}
outputs:
some texts looong string with
patterns another loooong string
you can of course add any isDebugEnabled() statement inside lazyFormat if you will.
It can be done by using parameter substitution in newest log4j 2.X version http://logging.apache.org/log4j/2.x/log4j-users-guide.pdf:
4.1.1.2 Parameter Substitution
Frequently the purpose of logging is to provide information about what is happening in the system, which
requires including information about the objects being manipulated. In
Log4j 1.x this could be accomplished by doing:
if (logger.isDebugEnabled()) {
logger.debug("Logging in user " + user.getName() + " with id " + user.getId());
}
Doing this repeatedly has the effect of making the
code feel like it is more about logging than the actual task at hand.
In addition, it results in the logging level being checked twice; once
on the call to isDebugEnabled and once on the debug method. A better
alternative would be:
logger.debug("Logging in user {} with id {}", user.getName(), user.getId());
With the code above the logging level
will only be checked once and the String construction will only occur
when debug logging is enabled.
if you are looking for lazy concatenation for the sake of efficient logging, take a look at Slf4J
this allows you to write:
LOGGER.debug("this is my long string {}", fatObject);
the string concatenation will only take place if the debug level is set.
IMPORTANT NOTE: It is strongly recommended all logging code be moved to use SLF4J (especially log4j 1.x). It protects you from being stuck with any sort of idiosyncratic issues (i.e. bugs) with specific logging implementations. Not only does it have "fixes" for well know backend implementation issues, it also works with newer faster implementations which have emerged over the years.
In direct response to your question, here what it would look like using SLF4J:
LOGGER.debug("some texts {} with patterns {}", object1, object2);
The most important bit of what you have provided is the fact you are passing two Object instances. The object1.toString() and the object2.toString() methods are not immediately evaluated. More importantly, the toString() methods are only evaluated if the data they return is actually going to be used; i.e. the real meaning of lazy evaluation.
I tried to think of a more general pattern I could use which didn't require my having to override toString() in tons of classes (and there are classes where I don't have access to do the override). I came up with a simple drop-in-place solution. Again, using SLF4J, I compose the string only if/when logging for the level is enabled. Here's my code:
class SimpleSfl4jLazyStringEvaluation {
private static final Logger LOGGER = LoggerFactory.getLogger(SimpleSfl4jLazyStringEvaluation.class);
...
public void someCodeSomewhereInTheClass() {
//all the code between here
LOGGER.debug(
"{}"
, new Object() {
#Override
public String toString() {
return "someExpensiveInternalState=" + getSomeExpensiveInternalState();
}
}
//and here can be turned into a one liner
);
}
private String getSomeExpensiveInternalState() {
//do expensive string generation/concatenation here
}
}
And to simplify into the one-liner, you can shorten the LOGGER line in someCodeSomewhereInTheClass() to be:
LOGGER.debug("{}", new Object(){#Override public String toString(){return "someExpensiveInternalState=" + getSomeExpensiveInternalState();}});
I have now refactored all my logging code to follow this simple model. It has tidied things up considerably. And now when I see any logging code which does not use this, I refactor the logging code to use this new pattern even if it is needed yet. That way, if/when a change is made later to need to add some "expensive" operation, the infrastructure boilerplate is already there simplifying the task to just adding the operation.
Building upon Andreas' answer, I can think of a couple of approaches to the issue of only performing the formatting if the Logger.isDebugEnabled returns true:
Option 1: Pass in a "do formatting" flag
One option is to have a method argument that tells whether or not to actually perform the formatting. A use case could be:
System.out.println(lazyFormat(true, "Hello, %s.", "Bob"));
System.out.println(lazyFormat(false, "Hello, %s.", "Dave"));
Where the output would be:
Hello, Bob.
null
The code for lazyFormat is:
private String lazyFormat(boolean format, final String s, final Object... o) {
if (format) {
return String.format(s, o);
}
else {
return null;
}
}
In this case, the String.format is only executed when the format flag is set to true, and if it is set to false it will return a null. This would stop the formatting of the logging message to occur and will just send some "dummy" info.
So a use case with the logger could be:
logger.debug(lazyFormat(logger.isDebugEnabled(), "Message: %s", someValue));
This method doesn't exactly fit the formatting that is asked for in the question.
Option 2: Check the Logger
Another approach is to ask the logger directly if it isDebugEnabled:
private static String lazyFormat(final String s, final Object... o) {
if (logger.isDebugEnabled()) {
return String.format(s, o);
}
else {
return null;
}
}
In this approach, it is expected that logger will be visible in the lazyFormat method. And the benefit of this approach is that the caller will not need to be checking the isDebugEnabled method when lazyFormat is called, so the typical use can be:
logger.debug(lazyFormat("Debug message is %s", someMessage));
You could wrap the Log4J logger instance inside your own Java5-compatible/String.format compatible class. Something like:
public class Log4jWrapper {
private final Logger inner;
private Log4jWrapper(Class<?> clazz) {
inner = Logger.getLogger(clazz);
}
public static Log4jWrapper getLogger(Class<?> clazz) {
return new Log4jWrapper(clazz);
}
public void trace(String format, Object... args) {
if(inner.isTraceEnabled()) {
inner.trace(String.format(format, args));
}
}
public void debug(String format, Object... args) {
if(inner.isDebugEnabled()) {
inner.debug(String.format(format, args));
}
}
public void warn(String format, Object... args) {
inner.warn(String.format(format, args));
}
public void error(String format, Object... args) {
inner.error(String.format(format, args));
}
public void fatal(String format, Object... args) {
inner.fatal(String.format(format, args));
}
}
To use the wrapper, change your logger field declaration to:
private final static Log4jWrapper logger = Log4jWrapper.getLogger(ClassUsingLogging.class);
The wrapper class would need a few extra methods, for example it does not currently handle of logging exceptions (ie logger.debug(message, exception)), but this shouldn't be hard to add.
Using the class would be almost identical to log4j, except strings are formatted:
logger.debug("User {0} is not authorized to access function {1}", user, accessFunction)
Introduced in Log4j 1.2.16 are two classes that will do this for you.
org.apache.log4j.LogMF which uses a java.text.MessageFormat for format you messages and org.apache.log4j.LogSF which uses the "SLF4J pattern syntax" and is said to be faster.
Here are examples:
LogSF.debug(log, "Processing request {}", req);
and
LogMF.debug(logger, "The {0} jumped over the moon {1} times", "cow", 5);
If you like the String.format Syntax better than the {0} Syntax and can use Java 8 / JDK 8 you can use lambdas / Suppliers:
logger.log(Level.FINER, () -> String.format("SomeOperation %s took %04dms to complete", name, duration));
()->... acts as a Supplier here and will be evaluated lazily.
Or you could write it as
debug(logger, "some texts %s with patterns %s", object1, object2);
with
public static void debug(Logger logger, String format, Object... args) {
if(logger.isDebugEnabled())
logger.debug(String.format("some texts %s with patterns %s", args));
}
You could defined a wrapper in order to call the String.format() only if needed.
See this question for a detailed code example.
The same question has also a variadic function example, as suggested in Andreas's answer.
Related
We have some code like:
public class ErrorCodeUtil {
public static void handleErrorCode(String errorCode) {
if (errorCode.equals("1")) {
handleErrorCode1();
} else if (errorCode.equals("2")) {
handleErrorCode2();
} else if (errorCode.equals("3")) {
handleErrorCode3();
} else {
handleErrorCodeByDefault(errorCode);
}
}
public static void logByErrorCode(String errorCode) {
if (errorCode.equals("1")) {
logErrorCode1();
} else if (errorCode.equals("2")) {
logErrorCode2();
} else if (errorCode.equals("3")) {
logErrorCode3();
} else {
logErrorCodeByDefault(errorCode);
}
}
//... a lot of method about error code
}
As you see, we have a Util to handle all things about ErrorCode, and when we want to add a special logic to an error code, we have to change many method of that utils class.
As expected, the value of error code varies in large range(possibly "112345" or "error_code_001"). So what design pattern is proper for that case?
I would implement a decision table.
The table would consist of a set of mappings between one or more Predicates as key and Function as a value. If a Predicate condition is met, then the corresponding Function is executed. If no Predicate condition is met, then a default Function should be executed. This can (easily) replace the humongous "if-else" statement and should be easier for maintenance.
How a Predicate should look like? It should take a String (in your case) and should return a boolean indicating whether a condition is met or no:
interface Predicate {
public boolean test(String x);
}
In the decision table, you'd add (anonymous) implementations of this interface as keys.
Hint: If you are already on Java8, even better, there's a built-in Predicate<T> interface. But if you're not, then you can introduce a Predicate interface of your own. :-)
The Function for the decision table's values will be a similar interface. It may (or may not) use an input parameters and should return void. In Java8 this is called a Consumer, however in my example I'll stick to the Function naming:
interface Function<T> {
void apply(T t);
}
By constructing pairs between Predicate as a key and Function<ErrorCodeUtil> as a value, we'll populate the decision table. When a Predicate condition is met, then we'll invoke the corresponding Function's .apply() method:
The decision table itself can be a simple Map<Predicate, Function<ErrorCodeUtil>>:
Map<Predicate, Function<ErrorCodeUtil>> decisionTable = new HashMap<>();
and you should populate it at construction time or whenever you wish (just before the handleErrorCode() method logic):
Predicate equalsOne = new Predicate() {
public void test(String x) {
return "1".equals(x);
}
};
Function<ErrorCodeUtil> actionOne = new Function<ErrorCodeUtil>() {
public void apply(ErrorCodeUtil t) {
t.handleErrorCode1();
}
}
decisionTable.put(equalsOne, actionOne);
and so for the other "condition-action" pairs, including the default action (i.e. the last else statement) for which the Predicate will always return true.
Note that in Java8, those anonymous classes can be significantly reduced by just using lambdas.
Finally, your "if-elseif" statements would be re-factored to a simple loop:
for (Map.Entry<Predicate, Function<ErrorCodeUtil>> entry: decisionTable.entrySet()){
Predicate condition = entry.getKey();
Function<ErrorCodeUtil> action = entry.getValue();
if (condition.test(errorCode)) {
action.apply(this);
}
}
So, everytime you add a new condition, you won't have to touch the handleErrorCode(String error) method, but you'll have to just introduce a new (anonymous) implementation of Predicate and Function and .put() it into the decision table.
I'd use Enum in that case.
public enum ErrorCodeEnum {
1 {
#Override
public void handleErrorCode() {
//doSomething
}
},
2 {
#Override
public void handleErrorCode() {
//doSomething
}
};
public abstract void handleErrorCode();
}
Then, having the error code in hands...
ErrorCodeEnum.valueOf("1").handleErrorCode();
PS: This is what I'd use to replace if-else statement, as you asked. But I'd use a Logger API for that specific problem (seems like you're logging erros).
You can keep all errorcodes in a list in one class. And check if list contains errorcode or not.
So this will reduce your if...else logic.
You have written different methods to handle error codes like handleErrorCode1(), handleErrorCode2() etc. Now if list contains desired error code then you can invoke these methods through java reflection.
regarding logging of errors, if all that is required is matching a code with a message, then a text file with mapping of codes to messages is the right way. the text file may be properties:
1=Item not Found
2=Item not valid
that can be loaded to a java.util.Properties instance, it may be xml that can be loaded into DOM or HashMap
<errors>
<error>
<code>1</code>
<msg>Item not Found</msg>
</error>
<error>
<code>2</code>
<msg>Item not Valid</msg>
</error>
<errors>
one advantage of this approach is that it can be made to support i18n if you specify language code in the file name and then get user language code from your client
How is it possible, to improve your logging mechanism, by not having the overhead of string concatenations?
Consider the following example:
import java.util.logging.Level;
import java.util.logging.Logger;
public class LoggerTest {
public static void main(String[] args) {
// get logger
Logger log = Logger.getLogger(LoggerTest.class.getName());
// set log level to INFO (so fine will not be logged)
log.setLevel(Level.INFO);
// this line won't log anything, but will evaluate the getValue method
log.fine("Trace value: " + getValue());
}
// example method to get a value with a lot of string concatenation
private static String getValue() {
String val = "";
for (int i = 0; i < 1000; i++) {
val += "foo";
}
return val;
}
}
The log method log.fine(...) will not log anything, because the log level is set to INFO. The problem is, that the method getValue will be evaluated anyway.
And this is a big performance issue in big applications with a lot of debug statements.
So, how to solve this problem?
Since Java8 it is possible to use the new introduced lambda expressions for this scenario.
Here is a modified example of the logging:
LoggerTest.class
import java.util.logging.Level;
import java.util.logging.Logger;
public class LoggerTest {
public static void main(String[] args) {
// get own lambda logger
LambdaLogger log = new LambdaLogger(LoggerTest.class.getName());
// set log level to INFO (so fine will not be logged)
log.setLevel(Level.INFO);
// this line won't log anything, and will also not evaluate the getValue method!
log.fine(()-> "Trace value: " + getValue()); // changed to lambda expression
}
// example method to get a value with a lot of string concatenation
private static String getValue() {
String val = "";
for (int i = 0; i < 1000; i++) {
val += "foo";
}
return val;
}
}
LambdaLogger.class
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LambdaLogger extends Logger {
public LambdaLogger(String name) {
super(name, null);
}
public void fine(Callable<String> message) {
// log only, if it's loggable
if (isLoggable(Level.FINE)) {
try {
// evaluate here the callable method
super.fine(message.call());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
With this modification you can improve the performance of your applications a lot, if you have many log statements, which are only for debugging purposes.
Of course you can use any Logger you want. This is only an example of the java.util.Logger.
#bobbel has explained how to do it.
I'd like to add that while this represents a performance improvement over your original code, the classic way of dealing with this is still faster:
if (log.isLoggable(Level.FINE)) {
log.fine("Trace value: " + getValue());
}
and only marginally more verbose / wordy.
The reason it is faster is that the lambda version has the additional runtime overheads of creating the callable instance (capture cost), and an extra level of method calls.
And finally, there is the issue of creating the LambdaLogger instances. #bobbel's code shows this being done using a constructor, but in reality java.util.logging.Logger objects need to be created by a factory method to avoid proliferation of objects. That implies a bunch of extra infrastructure (and code changes) to get this to work with a custom subclass of Logger.
Apparently Log4j 2.4 includes support for lambda expressions which are exactly useful for your case (and which other answers have replicated manually):
From https://garygregory.wordpress.com/2015/09/16/a-gentle-introduction-to-the-log4j-api-and-lambda-basics/
// Uses Java 8 lambdas to build arguments on demand
logger.debug("I am logging that {} happened.", () -> compute());
Just create wrapper methods for your current logger as:
public static void info(Logger logger, Supplier<String> message) {
if (logger.isLoggable(Level.INFO))
logger.info(message.get());
}
and use it:
info(log, () -> "x: " + x + ", y: " + y);
Reference: JAVA SE 8 for the Really Impatient eBook, pages 48-49.
use a format String, and an array of Supplier<String>. this way no toString methods are called unless the the log record is actually publishable. this way you dont have to bother with ugly if statements about logging in application code.
I'm currently working in a project in Liferay in which i'd like to be able to access my method and parameters these methods were given, in the history. This is done in case there is an exception being thrown in certain blocks of code.
I've already searched and it is easy to get the method name history (Thread.currentThread().getStackTrace();) but i'd like to also know what parameters were given to these methods.
For example:
public class A {
public static void main(String[] Args) {
try {
System.out.println(new B().someMethod(5));
} catch (Exception e) {
//GET HISTORY
}
}
}
public class B {
public int someMethod(int i) throws Exception {
i += 2;
throw new Exception("Expected Exception to Generate History Search");
return i;
}
}
Is it possible to learn how can i, in class A, when I catch the exception, all that data? And of so, how do I do that?
You can use Aspect Oriented Programming. Look at AspectJ for example.
The following aspect will trace all public method calls during your programs execution.
This can be fine-tuned to work with your own requirements. The pointcut can for example be adjusted to only take your own packages. The print statements can be changed into using some logging framework.
public aspect Trace {
pointcut publicMethodExecuted(): execution(public * *(..));
after(): publicMethodExecuted() {
System.out.printf("Enters on method: %s. \n", thisJoinPoint.getSignature());
Object[] arguments = thisJoinPoint.getArgs();
for (int i =0; i < arguments.length; i++){
Object argument = arguments[i];
if (argument != null){
System.out.printf("With argument of type %s and value %s. \n", argument.getClass().toString(), argument);
}
}
System.out.printf("Exits method: %s. \n", thisJoinPoint.getSignature());
}
}
You should consider using logging in your application.
You should definitely look in to logging in your application. If you want to avoid cluttering your code too much (I personally hate the constant log.debug(...) statements at start and end of each method), consider using Aspect Oriented Programming (google it for a whole host of good guides on it, or there's a decent aop guide using Spring here, just scroll down to the LoggingAspect), which will allow you to simply annotate methods or entire classes that you want logged.
In the last time I often write long functions that have several parameters but use only one of them and the functionality is only different at a few keypoints that are scattered around the function. Thus splitting the function would create too many small functions without a purpose. Is this good style or is there a good general refactoring pattern for this? To be more clear, an example:
public performSearch(DataBase dataBase, List<List<String>> segments) {performSearch(dataBase,null,null,segments);}
public performSearch(DataBaseCache dataBaseCache,List<List<String>> segments) {performSearch(null,dataBaseCache,null,segments);}
public performSearch(DataBase dataBase, List<String> keywords {performSearch(dataBase,null,keywords,null);}
public performSearch(DataBaseCache dataBaseCache,List<String> keywords) {performSearch(null,dataBaseCache,keywords,null);}
/** either dataBase or dataBaseCache may be null, dataBaseCache is used if it is non-null, else dataBase is used (slower). */
private void performSearch(DataBase dataBase, DataBaseCache dataBaseCache, List<String> keywords, List<List<String>> segments)
{
SearchObject search = new SearchObject();
search.setFast(true);
...
search.setNumberOfResults(25);
if(dataBaseCache!=null) {search.setSource(dataBaseCache);}
else {search.setSource(dataBase);}
... do some stuff ...
if(segments==null)
{
// create segments from keywords
....
segments = ...
}
}
This style of code works but I don't like all those null parameters and the possibilities of calling methods like this wrong (both parameters null, what happens if both are non-null) but I don't want to write 4 seperate functions either... I know this may be too general but maybe someone has a general solution to this principle of problems :-)
P.S.: I don't like to split up a long function if there is no reason for it other than it being long (i.e. if the subfunctions are only ever called in that order and only by this one function) especially if they are tightly interwoven and would need a big amount of parameters transported around them.
I think it is very bad procedural style. Try to avoid such coding. Since you already have a bulk of such code it may be very hard to re-factor it because each method contains its own logic that is slightly different from other. BTW the fact that it is hard is an evidence that the style is bad.
I think you should use behavioral patterns like
Chain of responsibilities
Command
Strategy
Template method
that can help you to change your procedural code to object oriented.
Could you use something like this
public static <T> T firstNonNull(T...parameters) {
for (T parameter: parameters) {
if (parameter != null) {
return parameter;
}
}
throw new IllegalArgumentException("At least one argument must be non null");
}
It does not check if more than one parameter is not null and they must be of the same type, but you could use it like this:
search.setSource(firstNonNull(dataBaseCache, database));
Expecting nulls is an anti-pattern because it litters your code with NullPointerExceptions waiting to happen. Use the builder pattern to construct the SearchObject. This is the signature you want, I'll let you figure out the implementation:
class SearchBuilder {
SearchObject search = new SearchObject();
List<String> keywords = new ArrayList<String>();
List<List<String>> segments = new ArrayList<List<String>>();
public SearchBuilder(DataBase dataBase) {}
public SearchBuilder(DataBaseCache dataBaseCache) {}
public void addKeyword(String keyword) {}
public void addSegment(String... segment) {}
public void performSearch();
}
I agree with what Alex said. Without knowing the problem I would recommend following structure based on what was in the example:
public interface SearchEngine {
public SearchEngineResult findByKeywords(List<String> keywords);
}
public class JDBCSearchEngine {
private DataSource dataSource;
public JDBCSearchEngine(DataSource dataSource) {
this.dataSource = dataSource;
}
public SearchEngineResult findByKeywords(List<String> keywords) {
// Find from JDBC datasource
// It might be useful to use a DAO instead of datasource, if you have database operations other that searching
}
}
public class CachingSearchEngine {
private SearchEngine searchEngine;
public CachingSearchEngine(SearchEngine searchEngine) {
this.searchEngine = searchEngine;
}
public SearchEngineResult findByKeywords(List<String> keywords) {
// First check from cache
...
// If not found, then fetch from real search engine
SearchEngineResult result = searchEngine.findByKeywords(keywords);
// Then add to cache
// Return the result
return result;
}
}
I'm using String.format method of Java API to log something. My method is like:
public static void log(String message, Object... params){
System.out.println(String.format(message, params));
}
However the problem is, if the user sends a message that has % character somewhere in it, it throws exception. Here's a scenario:
log("SELECT * FROM my WHERE name like '%six%'");
and Java looks for something to replace %s (that's ok) and %' (oops). I want to fix that. Because there there are no params and %s will be lost and %' causes exception.
One solution can be message.replace("%", "%%") but I'm not sure it is an elegant solution or not.
log has no idea whether a given % is meant as a format specifier or as a percent sign. Consider the following example:
log("%s%s", "test");
Is that "test%s", "%stest", or an error?
Therefore, the problem will have to be addressed at the call site:
log(escape("SELECT * FROM my WHERE name like '%six%'"));
where escape() is a function you'll need to write that'll replace all % with %%.
Alternatively, the following can be used at the call site:
log("%s", "SELECT * FROM my WHERE name like '%six%'");
A simple solution for the most likely misuse (using %s or % somewhere in the String but providing no parameters) would be to provide a no-params overload to your method in addition to your original method:
public static void log(String message) {
System.out.println(message);
}
Alternatively you can dynamically try to detect the no-params case, but that's a bit more work:
public static void log(String message, Object... params) {
final String output;
if (params == null || params.length = 0) {
output = message;
} else {
output = String.format(message, params);
}
System.out.println(output);
}
One option would be to pass the string directly into the println if the length of params is 0.
Another options would be to have two overloads.
public static void log(String message);
public static void log(String format, String param, String...params);