Sunday, February 4, 2018

Does Java pass by reference or pass by value? Why can't you swap in Java?

Q: If Java uses the pass-by reference, why won't a swap function work?
A: Java does manipulate objects by reference, and all object variables are references. However, Java doesn't pass method arguments by reference; it passes them by value.
Take the badSwap() method for example:
public void badSwap(int var1, int var2)
{
  int temp = var1;
  var1 = var2;
  var2 = temp;
}
When badSwap() returns, the variables passed as arguments will still hold their original values. The method will also fail if we change the arguments type from int to Object, since Java passes object references by value as well. Now, here is where it gets tricky:
public void tricky(Point arg1, Point arg2)
{
  arg1.x = 100;
  arg1.y = 100;
  Point temp = arg1;
  arg1 = arg2;
  arg2 = temp;
}
public static void main(String [] args)
{
  Point pnt1 = new Point(0,0);
  Point pnt2 = new Point(0,0);
  System.out.println("X: " + pnt1.x + " Y: " +pnt1.y); 
  System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
  System.out.println(" ");
  tricky(pnt1,pnt2);
  System.out.println("X: " + pnt1.x + " Y:" + pnt1.y); 
  System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);  
}
If we execute this main() method, we see the following output:
X: 0 Y: 0
X: 0 Y: 0
X: 100 Y: 100
X: 0 Y: 0
The method successfully alters the value of pnt1, even though it is passed by value; however, a swap of pnt1 and pnt2 fails! This is the major source of confusion. In the main() method, pnt1 and pnt2 are nothing more than object references. When you pass pnt1 and pnt2 to the tricky() method, Java passes the references by value just like any other parameter. This means the references passed to the method are actually copies of the original references. Figure 1 below shows two references pointing to the same object after Java passes an object to a method.
Figure 1. After being passed to a method, an object will have at least two references
Java copies and passes the reference by value, not the object. Thus, method manipulation will alter the objects, since the references point to the original objects. But since the references are copies, swaps will fail. As Figure 2 illustrates, the method references swap, but not the original references. Unfortunately, after a method call, you are left with only the unswapped original references. For a swap to succeed outside of the method call, we need to swap the original references, not the copies.
Figure 2. Only the method references are swapped, not the original ones
O'Reilly's Java in a Nutshell by David Flanagan (see Resources) puts it best: "Java manipulates objects 'by reference,' but it passes object references to methods 'by value.'" As a result, you cannot write a standard swap method to swap objects.

Tuesday, January 23, 2018

log4j - Logging Levels

The org.apache.log4j.Level levels. You can also define your custom levels by sub-classing the Level class.
Level Description
ALL All levels including custom levels.
DEBUG Designates fine-grained informational events that are most useful to debug an application.
ERROR Designates error events that might still allow the application to continue running.
FATAL Designates very severe error events that will presumably lead the application to abort.
INFO Designates informational messages that highlight the progress of the application at coarse-grained level.
OFF The highest possible rank and is intended to turn off logging.
TRACE Designates finer-grained informational events than the DEBUG.
WARN Designates potentially harmful situations.

How do Levels Works?

A log request of level p in a logger with level q is enabled if p >= q. This rule is at the heart of log4j. It assumes that levels are ordered. For the standard levels, we have ALL < DEBUG < INFO < WARN < ERROR < FATAL < OFF.
The Following example shows how we can filter all our DEBUG and INFO messages. This program uses of logger method setLevel(Level.X) to set a desired logging level:
This example would print all the messages except Debug and Info:
import org.apache.log4j.*;

public class LogClass {
   private static org.apache.log4j.Logger log = Logger.getLogger(LogClass.class);
   
   public static void main(String[] args) {
      log.setLevel(Level.WARN);

      log.trace("Trace Message!");
      log.debug("Debug Message!");
      log.info("Info Message!");
      log.warn("Warn Message!");
      log.error("Error Message!");
      log.fatal("Fatal Message!");
   }
}
When you compile and run the LogClass program, it would generate the following result −
Warn Message!
Error Message!
Fatal Message!

Setting Levels using Configuration File

log4j provides you configuration file based level setting which sets you free from changing the source code when you want to change the debugging level.
Following is an example configuration file which would perform the same task as we did using the log.setLevel(Level.WARN) method in the above example.
# Define the root logger with appender file
log = /usr/home/log4j
log4j.rootLogger = WARN, FILE

# Define the file appender
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=${log}/log.out

# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n
Let us now use our following program −
import org.apache.log4j.*;

public class LogClass {

   private static org.apache.log4j.Logger log = Logger.getLogger(LogClass.class);
   
   public static void main(String[] args) {
   
      log.trace("Trace Message!");
      log.debug("Debug Message!");
      log.info("Info Message!");
      log.warn("Warn Message!");
      log.error("Error Message!");
      log.fatal("Fatal Message!");
   }
}
Now compile and run the above program and you would get following result in /usr/home/log4j/log.out file −
Warn Message!
Error Message!
Fatal Message!

Friday, January 5, 2018

Java String new line

System.out.println("I\nam\na\nboy");

System.out.println("I am a boy".replaceAll("\\s+","\n"));

System.out.println("I am a boy".replaceAll("\\s+",System.getProperty("line.separator"))); // portable way