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);
Related
I have a method which accepts Mono as a param.
All I want is to get the actual String from it. Googled but didn't find answer except calling block() over Mono object but it will make a blocking call so want to avoid using block(). Please suggest other way if possible.
The reason why I need this String is because inside this method I need to call another method say print() with the actual String value.
I understand this is easy but I am new to reactive programming.
Code:
public String getValue(Mono<String> monoString) {
// How to get actual String from param monoString
// and call print(String) method
}
public void print(String str) {
System.out.println(str);
}
Getting a String from a Mono<String> without a blocking call isn't easy, it's impossible. By definition. If the String isn't available yet (which Mono<String> allows), you can't get it except by waiting until it comes in and that's exactly what blocking is.
Instead of "getting a String" you subscribe to the Mono and the Subscriber you pass will get the String when it becomes available (maybe immediately). E.g.
myMono.subscribe(
value -> System.out.println(value),
error -> error.printStackTrace(),
() -> System.out.println("completed without a value")
)
will print the value or error produced by myMono (type of value is String, type of error is Throwable). At https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html you can see other variants of subscribe too.
According to the doc you can do:
String getValue(Mono<String> mono) {
return mono.block();
}
be aware of the blocking call
Finally what worked for me is calling flatMap method like below:
public void getValue(Mono<String> monoString)
{
monoString.flatMap(this::print);
}
What worked for me was the following:
monoString.subscribe(this::print);
Simplest answer is:
String returnVal = mono.block();
This should work
String str = monoString.toProcessor().block();
Better
monoUser.map(User::getId)
Trying to split a String in certain ways without changing the
String(String embed, String payload)
structure.
System.out.println(embedCenter("<<>>", "Yay")); // => <<Yay>>
This is how it should look, so putting "<<>>" for embed and "Yay" for payload should return <<Yay>>, however for "()" embed and "Yay" Payload it should return "(Yay)" and for ":-)" embed and "Yay" payload it should return ":Yay-)"
So I'm just starting to learn, and kinda stuck at this question - I've tried doing substrings but while I could get one of those results, I cant find a way to get all of them with the same method.
public static String embedCenter(String embed, String payload) {
return ""; //
}
public static void main(String[] args) {
System.out.println(embedCenter("<<>>", "Yay")); // => <<Yay>>
System.out.println(embedCenter("()", "Yay")); // => (Yay)
System.out.println(embedCenter(":-)", "Example")); // :Example-)
Ok, I did it, I thought way too complicated, did it really easy simply by dividing the String with length()/2, perfectly worked. Thanks for the input!
int length = embed.length();
String subembed = embed.substring(0,embed.length()/2);
String finembed = embed.substring(embed.length()/2);
return subembed + payload + finembed;
I have a little method that amongst other things also converts a string into an integer. Since the string is a parameter of the method I want to make sure that that string is convertable. So I was just wondering what would be the safest and / or fastest way.
Version A: Just leave it as it is and take the risks (which I'm trying to avoid)
public static int stringToInt(String param) {
return Integer.valueOf(param);
}
(in terms of speed, what kind of difference would it make to version B and C?)
Version B: Catch the exception
public static int stringToInt(String param) {
try {
return Integer.valueOf(param);
} catch(NumberFormatException e) {
return -1;
}
}
Version C: Check each letter of the string to see, if it's a digit number or not
public static int stringToInt(String param) {
for(char c : param.toCharArray()) {
if(!Character.isDigit(c))
return -1;
}
return Integer.valueOf(param);
}
Note that the parameter has to be a positive number and the -1 is supposed to be the "error value" in my little program, in other words, all three versions of methods would work perfectally fine in my program.
I'm very open to any other suggestion you can give me, so feel free to create your own version, if you think yours is better.
Thank you very much for your support in advance.
Guava offers a utility method for this which returns null in case your String can't be parsed.
https://google.github.io/guava/releases/19.0/api/docs/com/google/common/primitives/Ints.html#tryParse(java.lang.String)
Integer result = Ints.tryParse("1"); //returns 1
Integer result = Ints.tryParse("-1"); //returns -1
Integer result = Ints.tryParse("a"); //returns null
First, note that version C is not bulletproof: it would reject negative numbers, and would not catch numbers that are too large.
Version B is OK, yet it makes the caller change the coding style: rather than catching an error and processing it together with other errors, the caller would need to check for -1 all the time. This may be suboptimal in situations where you read multiple integers, but the error processing does not depend on which particular one has failed. In addition, new coders using your API may forget to check for -1, and use the error code inadvertently.
That's why I would stay with the first option: the code using version A would look instantly familiar to anyone who knows Java API, without the need to learn what happens inside your function.
I believe a modified B to throw an exception rather than returning -1 will be the best choice. It is good to throw the exception up to the level, where it can be processed to send the proper response to the user. Returning a value like -1 will make your code error prone. Assume that a different programmer is consuming your method and he/she just have the signature of your method. So it is not clear from the signature what he/she should code to handle an exception or error scenario. But if you throw the exception and add it to your method declaration then it will enable the other programmer to consume your method properly alongwith the required exception handling. For me this looks the best:
public static int stringToInt(String param) throws NumberFormatException {
try {
return Integer.valueOf(param);
} catch(NumberFormatException e) {
// return -1;
throw e;
}
}
Java 8 without any API:
Optional.ofNullable(strNum)
.map(Integer::valueOf).orElse(null);
public int stringToInt(String param) throws NumberFormatException {
Optional.ofNullable(param.replaceAll("\\s+", ""))
.map(Integer::valueOf).orElse(null);
/*
or
Optional.ofNullable(param.replaceAll(" ", ""))
.map(Integer::valueOf).orElse(null);
*/
}
use the replaceAll to replace white spaces the plus is cpu friendly even though seems not needed.
I used a combination of 2 answers to have it safe for nulls, empty or blank strings, and non numeric characters:
public static Integer safeStringToInt(String param) {
return Optional.ofNullable(param).map(Ints::tryParse).orElse(null);
}
I've got this method I'm working on (I think that's the name) and it essentially tries to match a part of a string and then return the proceeding part of the string - that part I've got, easy stuff. The method is of type String.
When my method fails to find the pattern in the string I want it to return an empty string. I also want to send something along with the empty string to go "hey, I didn't find your key" but I want this to be optional.
This is essentially what I want the method to do:
public static String getKey(String key) throws KeyNotFoundException {
if (key.equals("something")) {
return "great";
} else {
throw new KeyNotFoundException();
return "";
}
}
But the problem with this code is that the return ""; is obviously unreachable due to throw new KeyNotFoundException();.
If I was going to call this method I'd have to use the try {} catch(KeyNotFoundException knf) {} block. It's this block that I want to make optional however.
If I choose to be oblivious to the fact the key was not found (e.g. don't use try catch) then I just want to be given the empty string on return.
But I also want to be able to surround it with a try-catch block if I need to know whether the key was found for my operation to complete correctly.
I think I'm going about this the wrong way but I can't seem to figure out an alternative (new to Java), could anyone shred some light on this please?
The usual way to do this would be to write two methods, one which returns a default value, and one which throws an exception. You can have one of these call the other, to avoid duplication:
public static String getKey(String key) throws KeyNotFoundException {
String value = getOptionalKey(key);
if (value.equals("")) throw new KeyNotFoundException(key);
return value;
}
public static String getOptionalKey(String key) {
if (key.equals("something")) {
return "great";
} else {
return "";
}
}
The caller can then choose which one to call, based on their needs:
String value = getOptionalKey("uma"); // oblivious
try {
String value = getKey("uma"); // cognisant
}
catch (KeyNotFoundException e) {
// panic
}
You should either use return values or exceptions to denote an error condition, but not both.
Generally, if you anticipate that something can go wrong, use a return value, and if the error is exceptional, throw an exception (as the name suggests).
By definition, an exception disrupts the normal program flow. The exception "bubbles up" until someone catches it or the thread terminates.
You can't do exactly what you're trying, but you have a couple options. You could write a "safe" version of the method that returns a default value if the key isn't found, like you're trying to do, and have a separate method that will throw the exception if the key isn't found.
Another option, if you've defined KeyNotFoundException yourself, would be to derive from RuntimeException instead of simply Exception. Then, you could remove the throws declaration from your method signature and not publish the fact that the method could throw an exception.
You can't, however, throw an exception from the method AND return a value from the method.
Another way you could deal with optional return values is to use Java 8's Optional class, and let the caller decide what to do when the value is not present:
public static Optional<String> getOptionalKey(String key) {
if (key.equals("something")) {
return Optional.of("great");
} else {
return Optional.empty();
}
}
You could combine it with the multiple methods approach discussed in other answers:
public static String getKey(String key) throws KeyNotFoundException {
return getOptionalKey(key).orElseThrow(() -> new KeyNotFoundException(key));
}
What about if you create your own Exception (extend Exception) which will have a constructor that takes a String or whatever you want to send to it (like error code or statement)?
Then you can have a getter method within your Custom Exception that will be used to "get" whatever the error message was.
nope. a method can only end with returning a value/end or return; if it is void OR throw an exception.
From what I understand of what you want to achieve, you could use a void returning method and provide a reference of a special object in argument. you would then set a field of this object to the result you want to 'return' and throw the exception.
Something like
class final ResultHoder {
String result;
public void setResult(String result) {
this.result = result;
}
public String getResult() {
return this.result;
}
}
public static void getKey(String key, ResultHolder result) throws KeyNotFoundException {
if (key.equals("something")) {
result.setResult("great");
return;
} else {
result.setResult("");
throw new KeyNotFoundException();
}
}
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.