SlideShare une entreprise Scribd logo
1  sur  25
Télécharger pour lire hors ligne
Java Pitfalls and Good-to-Knows
Miquel Martin – contact@miquelmartin.org
Benjamin Hebgen – benjamin.hebgen@gmx.de
What’s this?

      This slide set covers some Java tidbits you might not
      encounter on your day-to-day java development.
      Perhaps some of them will improve your coding and
      save you some debugging!




Photo credits:
The splashing coffe cup at the title by 96dpi on flicker: http://www.flickr.com/photos/96dpi/
Coffee beans on the watermark by wiedmaier on flicker: http://www.flickr.com/photos/wiedmaier/
Padlock on the ReadWriteLock slide by darwinbell on flicker: http://www.flickr.com/photos/darwinbell/
                                                                                                        2
Tree in the dune by suburbanbloke on flickr: http://www.flickr.com/photos/suburbanbloke/
PermGen and Strings
 The Java Garbage Collector works
  on generations. The permanent
  one hosts internalized Strings and
  classes.                                Permanent Generation:
 When the compiler finds a literal       Class objects, Strings. Won’t
  String in your code, it allocates it    be Garbage Collected
  (if not yet there) in the string pool       Tenured Generation:
  at the PermGen heap. All instances          Multi Garbage Collection
  of the same String will point to the        survivors
  same PermGen instance.
                                                  Young Generation:
                                                  New objects
 Too many literal Strings (bad
  design) or thinks like classloader
  leaks (http://goo.gl/LIodj) can lead
  to “Out of MemoryError: PermGen
  space”.


                                                                  3
StringBuilders and StringBuffers
 Strings are immutable.                    String numberList = "";
                                            for(int i = 0; i < 1000; i++){
 The example on the right will:                numberList+= i + ", ";
    1. Create the numberList String         }
    2. Create a newNumberList with the
       numberList, I and a “, “
    3. Assign newNumberList to numberList
    4. Repeat 1000 times 2 & 3
 This is slow, fills up your heap and
  therefore forces more costly garbage
  collections

 Use instead a mutable StringBuilder. If   StringBuilder builder= new
                                            StringBuilder();
  you have multiple threads accessing       for(int i = 0; i < 1000; i++){
  it, use the synchronized version,             builder.append(i+", ");
                                            }
  StringBuffer.                             String numberList = builder.toString();



                                                                             4
From numbers to Strings
   How do you quickly convert a number to a String?        int i = 42;
                                                            String str = i; //Error, i not a String
   Case 1: easy but slow, a new String is created that
    concatenates the literal “” and i.
                                                            // Case1: All time favorite (and slowest)
   Case 2: a new String is directly created for the        String str = "" + i;
    number. This is 2x faster than Case 1                   String str = i + "";
   Case 3: it internally calls Case 2, and has roughly
    the same performance.
                                                            // Case2: the fastest one
                                                            String str = Integer.toString(myNumber);
   Exception: in “The number is “ + i, all three cases
    are similar since String concatenation must happen
    anyway, but Case 2 and 3 need to explicitly create      // Case3: Also fast (calls Case 2)
    an additional String.                                   String str = String.valueOf(myNumber);

   This also works on: short, float, double, long, etc..

   Take home lesson: ignore this and do whatever’s
    more readable, unless performance is really critical




                                                                                                       5
Comparing floating point numbers
 Floating point numbers are encoded       float f = 25
                                           In Hexadecimal:
  using IEEE754-2008. Not all real
                                           0100 0001 1100 1000 0000 0000 0000 00002
  numbers can be represented (e.g. 0.2)
                                                              Significand: bit ?: 1x1/1 = 1x1 = 1
 Extra caution is needed when                                             bit 9: 1x1/2 = 1x0.5 = 0.5
                                                                           bit 10: 0x1/4 = 0x0.25 = 0
  comparing floats (see examples)                                          bit 11: 0x1/8 = 0x0.125 = 0
                                                                           bit 11: 1x1/16 = 0x0.0625 = 0.0625
 Also, portability issues due to                                          .
                                                                           .
  evolution:
                                                              Total = 1 + 0.5 + 0.0625 = 1.5625
    Java ≤ 1.2: intermediate                 Bits 1 to 8: Exponent: 1000 00112 is 13110
       calculation steps done using                        and then: 131-127 = 4

       single or double precision           Bit 0: the sign, 0 is positive
                                           Result: + 1.5625 x 24 = 25
    Java > 1.2: to decrease rounding
                                           //This is true (uses floats)
       errors the highest platform         boolean floatResult =
       supported precision is used for                0.1f + 0.1f + 0.1f == 0.3f;
                                           //This is false (uses doubles)
       intermediate results.               boolean doubleResult =
                                                      0.1 + 0.1 + 0.1 == 0.3;
 Note: the strictfp keyword forces Java   //Also false (also doubles)
                                           boolean doubleResult =
  1.2 behavior                                        0.1d + 0.1d + 0.1d == 0.3d;
                                                                                                    6
Volatile variables
 Depending on the JVM, threads          package operators;

  may work on copies of variables        class Test extends Thread {
                                             boolean done = false;
  and never re-check the original            public void run() {
                                                                      1

  reference.                                     while (!done) {
 This does not happen if the                    }
  variable is marked volatile, or the            System.out.println("Thread terminated.");
  variable access is synchronized.           }
  Both tell the JVM that multi-
  thread access is likely and to check       public static void main(String[] args) throws
                                                 InterruptedException {
  the original reference.                            Test t = new Test();
 The code on the right will never                   t.start();
  finish unless (1) is volatile. The                 Thread.sleep(1000);
  behavior can change between                        t.done = true;
  JVMs. Also, volatile does not solve                System.out.println("done");

  concurrent modification issues.                }
                                         }
  Don’t rely on volatile unless you
  know exactly what you’re doing.


                                                                                       7
Breaking out of the right loop
 The break keyword takes a label as a   mytag: for(int i =0; i < 10; i++){
  parameter and breaks out of the             for(j =0; j < 10; j++){
                                                   if(done) {
  scope tagged for it                                       break mytag;
                                                   }
                                              }
                                         }


 This works also on
  switch, for, while and do-while
  both for
  continue and break




                                                                              8
Preventing inheritance, overriding and
instantiating
 Controlling how your class is used        // A Utility class has only static methods
  comes in handy: singletons, factories,    public class UtilityClass {
  utility classes, etc…                         // Private constructor prevents
                                                // external class instantiation
                                                private TestClass() {
 The final keyword applied to a:               }
    Class: prevents extending                  public static int getInstance() {
    method: prevents overriding                  return new TestClass();

    primitive field: prevents changing     }
                                                }

      the value
    Object field: prevents changing        // Final class cannot be extended
      the reference (you can still          public final class FinalClass {
      change the object)                      // Final primitive cannot be modified
                                              final boolean something = false;

 A private default constructor will            // Reference to final object cannot
  additionally prevent external                 //be modified
                                                final StringBuilder builder= new StringBuilder();
  instantiation
 A final Class with only one private        // Final method cannot be overriden
  constructor cannot be extended or           public final void someMethod() {
                                              }
  overridden: it will never be externally   }
  instantiated
                                                                                           9
Static code blocks
 Static blocks let you execute      public class StaticBlocks {
                                         private static int number = 1;
                                         static {
  something at class loading time            System.out.println(number);
                                         }
  (e.g. assign a value to a static       static {
                                             number = 2;
  field)                                 }


 Static blocks and static field
                                          static {
                                             System.out.println(number);
                                         }
  assignment is done once at             static {
  class loading                          }
                                             number = increaseNumber(number);


 The execution order is the same        static {
                                             System.out.println(number);
  as the order in the code               }

                                         public static int increaseNumber(int i) {
                                             return i + 1;
                                         }

                                         public static void main(String[] args) {
                                             System.out.println(number);

                                             //Aggregatted output: 1, 2, 3, 3
                                         }
                                     }

                                                                                10
Finally we finalize the final.
 final is already covered                   try {
                                                 System.out.println("In try");
                                                 throw new Exception();
 finalize will be called on an instance     } catch (Exception e) {
  when (if!) it is garbage collected.
                                                 System.out.println("In catch");
     You have no real control of when       } finally {
       the GC will pass. Plus it’s bad             System.out.println("In finally");
       practice and often ignored by JVMs    }
     Do not use it to free resources.       // Outputs: In try, In catch, In finally
     It’s not the C++ destructor,

 finally goes after a try…catch block:
                                             BufferedWriter writer = null;
     First, run the code in the try         try {
     If an exception is thrown, run the         writer = Files.newBufferedWriter(file,
        appropriate code in catch                charset);
     Then, no matter what, run the code         writer.write(s, 0, s.length());
        in finally. Even after a return in   } catch (IOException x) {
        catch or try.                            System.err.println("Error happened");
 It’s worth using finally even if no        } finally {
  exceptions are expected. They might be         if (writer != null) writer.close();
  thrown in a future code change.            }



                                                                                        11
Keywords you don’t see so often
• assert: evaluate a boolean expression and throw an AssertionException if false. Useful to
 write your assumptions in the code, and get notified if you were wrong

• continue: skip to the next iteration of a loop

• strictfp: ensures consistent floating point operations on different platforms

• transient: keep the field from being serialized when using standard java serialization
 mechanisms

• volatile: prevents threads from working with a thread local copy of a variable when not
 using synchronized access

• native: denotes that the method is provided by an external non-java library using JNI

• goto: it’s a reserved keyword but a valid keyword. The compiler will throw a syntax error

• const: same as goto

                                                                                       12
Protective copies
 In this code, some internal logic    class Test {

  occurs on adding/removing                private List<String> internalStuff = new
                                               ArrayList<String>();
  stuff.                                   public void addStuff(String stuff) {
                                               //Do internal logic
 If getAllStuff returns                       internalStuff.add(stuff);

  internalStuff, the caller can            }
                                           public void removeStuff(String stuff) {
  add/remove items without                     //Do internal logic

  going through removeStuff                    internalStuff.remove(stuff);
                                           }
 If this is (or could be) an issue,       public List<String> getAllStuff(){
                                               //Dangerous: return internalStuff;
  create a protective copy of                  //Better:
  internalStuff first                          return new ArrayList<String>(internalStuff);
                                           }
                                       }




                                                                                      13
Shallow comparison and Arrays
 Comparison types:              String[] a1 = new String[] { "0", "1", "2" };
                                 String[] a2 = new String[] { "0", "1", "2" };
    Shallow: uses == and        System.out.println(a1 == a2); // false
     compares object             System.out.println(a1.equals(a2)); // false 1
                                 System.out.println(Arrays.equals(a1, a2)); // true
     references
    Deep: uses equals and is    List<String> list1 = new ArrayList<String>(3);
                                 List<String> list2 = new ArrayList<String>(3);
     as good as your equals      list1.add("0");
     implementation              list2.add("0");
                                 list1.add("1");
                                 list2.add("1");
                                 list1.add("2");
                                 list2.add("2");
 Notable exception: equals is
                                 System.out.println(list1 == list2); // false
  odd for arrays (1) and will    System.out.println(list1.equals(list2));
  perform a shallow              // true if the elements in the list properly
                                     implement equals
  comparison. Use
  Arrays.equals instead


                                                                                14
Checked VS Unchecked exceptions
 Unlike Unchecked exceptions,                         Throwable
  Checked exceptions need to be
  caught or declared
 Pros of unchecked exceptions:            Exception                  Error

    Clearer code
    You can still treat them like   ? extends
                                                    Runtime
                                                                    ? extends
                                                   Exception
     checked exceptions if you       Exception                        Error
     want                                              ? extends
                                                        Runtime
 Cons: Easy to miss                                   Exception
                                                                   Unchecked
                                                                   Exceptions
    JsonParseException in Gson
    NumberFormatException from
     new Integer(“3,4”) in some
     locales



                                                                          15
Testing with Hamcrest Matchers
 In JUnit, assertTrue,           public class RegexMatcher extends
                                       BaseMatcher<String> {
  assertEquals, etc… perform          private final String regex;


  specific assertions                 public RegexMatcher(String regex) {
                                          this.regex = regex;
                                      }
 For arbitrary assertions, you       @Override
  can use a Hamcrest Matcher          public boolean matches(Object s) {
                                          return ((String) s).matches(regex);
  and run it with assertThat          }

                                      @Override
                                      public void describeTo(Description description)
                                       {
                                          description.appendText("matches " + regex);
                                      }

                                      public static RegexMatcher matches(String regex)
                                       {
                                          return new RegexMatcher(regex);
                                      }
                                  }

                                  //Allows you to do:
                                  assertThat(actual, matches(regex));




                                                                                16
Type erasure
 The Java generics implementation      public void doSomething(List<String>
  does not change the compiler             list) {}
  much, instead, it pre-processes       public void doSomething(List<Integer>
  away the generics                        list) { }

 At compile time, type parameters      // Compiler error: both methods can’t
  are replaced with their bounds           be in the same class, since they
                                           have the same type erasure
 Types are “erased” in the compiled
  bytecode
 Famous pitfall: after type erasure,
  List<String> is the same as
  List<Integer>
 There’s plenty more interesting
  gotchas in generics, check:
  http://goo.gl/0AeYW


                                                                         17
Read/Write Locks
 Case: you don’t care how many
  threads read your object, as long as
  no one is modifying it, and then, only
  one at a time.
 Solution: replace your synchronized
  methods with ReadWriteLocks
 Beware of the details:
    in balanced read/write scenarios,
      the overhead of a ReadWriteLock
      will likely degrade performance.
    Thread starvation and fairness
      are an issue. Check
      ReentrantLocks
 A good discussionL http://goo.gl/zRjvL




                                           18
Synchronized Collections
 You’ll still find online that:          List<String> unsynchronizedList = new
     A Hashtable is like a HashMap but      ArrayList<String>();
      synchronized (there’s more to it,   List<String> synchronizedList =
      like null values)                      Collections.synchronizedList(unsynchro
     A Vector is like an ArrayList but      nizedList);
      synchronized (it isn’t)
 This hasn’t been true since Java        Map<String, String> unsynchronizedMap =
  1.3 introduced the Synchronized            new LinkedHashMap<String, String>();
  Collections
                                          Map<String, String> synchronizedMap =
 Note that Read/Write locks are             Collections.synchronizedMap(unsynchron
  Java >=1.5 so there’s plenty room          izedMap);
  for optimizing if you need to.
 Notable exception:
  ConcurrentHashMap is (probably)
  your high-performance map for
  multi-threaded access

                                                                             19
Legacy Classes
Legacy classes are not (yet) deprecated but their use is
discouraged. They still pop up in plenty of tutorials and
snippets.
 Vector and Dictionary/Hashtable should not be used
    as synchronized List and Map. Use
    Collections.synchronizedList and
    Collections.synchronizedMap instead. Also consider
    ConcurrentHashMap.
 Properties extends Hashtable with file writing
    capabilities, but there’s no replacement.
 Stack is a revamp of Vector to work like a LinkedList.
    Use that instead.
 StringTokenizer is better implemented by String.split
    and also handles encoding better
 Enumeration is very close to an Iterator but does less
    (e.g. remove)

   Most discouraged classes are parallel implementations
    of existing classes with a minor (often mis-
    implemented) delta.


                                                            20
equals, hashCode and Comparable
                                     // HashMap put
  Different collections use         public V put(K key, V value) {
                                       if (key == null)
   different mechanisms to sort          return putForNullKey(value);
                                       int hash = hash(key.hashCode());
   out objects, for example:
                                         // Locate the bucket by hashCode
     HashMap uses hashCode              int i = indexFor(hash, table.length);

                                       for (Entry<K,V> e = table[i]; e != null; e =
     TreeSet uses Comparable        e.next) {
                                           Object k;
  If hashCode and Comparable              // Check for equality only in the bucket
                                            if (e.hash == hash && ((k = e.key) == key ||
   are not consistent with equals,   key.equals(k))) {
                                              V oldValue = e.value;
   expect inconsistencies! Check              e.value = value;
                                              e.recordAccess(this);
   the contract.                          }
                                              return oldValue;

                                         }
                                         modCount++;
                                         addEntry(hash, key, value, i);
                                         return null;
                                     }




                                                                                    21
Java 7’s NIO.2
Java 7’s new file I/O makes file system    Files.copy(source, target,
                                               StandardCopyOption.REPLACE_EXISTING);
interactions much easier
                                           WatchService
 Implemented in java.nio.file.Files and       watchService = new WatchService() {
                                           ...
    java.nio.file.Path                     };
                                           path.register(watchService, ENTRY_CREATE,
 It provides common file operations           ENTRY_DELETE, ENTRY_MODIFY);

    like copy or readAllLines
                                           Files.getPosixFilePermissions(path,
 You can get notifications on Path            LinkOption.NOFOLLOW_LINKS);
    modifications                          Files.isExecutable(path);
                                           Files.isReadable(path);
 Support for permission and owner         Files.isWritable(path);
    handling and links                     Files.readAllLines(path,
                                               Charset.forName("utf-8"));
 Fine grained exception handling
                                           Files.write(path, "mytext".getBytes(Charset.
                                               forName("utf-8")),
                                               StandardOpenOption.CREATE);




                                                                                 22
Where to store resources
 Best practice for user specific             String winPath = System.getProperty("
                                                 user.home") + File.separator +
  configuration options per OS:                   "Application Data" +
                                                 File.separator + "myApp";
                                              String linuxPath = System.getProperty
                                                 ("user.home") + File.separator +
                                                  ".myApp";




 Storing in your classpath (e.g. in your     TestClass.class.getResourceAsStream("
                                                 myresource.xml")
  jar) using Class.getResourceAsStream




 If you really really want, there is a way   //This will find your class
  to find the path to your class, allowing    MyClass.class.getProtectionDomain().g
                                                 etCodeSource().getLocation().getP
  for storage relative to the installation       ath();
  folder

                                                                               23
(Avoid) Reinventing the wheel
 There are a lot of 3rd party libraries for Java. Avoid reinventing
  the wheel! Also beware of very alpha libraries!
 You will only use stuff you know exists. Consider browsing
  through the documentation of libraries like:
    Apache Commons: for anything from logging to collections
      and much more http://commons.apache.org/
    Google’s Guava: for a ton of convenience classes and very
      interesting containers http://code.google.com/p/guava-libraries/
    OPS4J: for all sort of OSGi related helpers http://team.ops4j.org




                                                                    24
Thanks and Happy Coding!



                           25

Contenu connexe

Tendances

exception handling in java
exception handling in java exception handling in java
exception handling in java aptechsravan
 
Types of exceptions
Types of exceptionsTypes of exceptions
Types of exceptionsmyrajendra
 
Exception handling in java
Exception handling in javaException handling in java
Exception handling in javapriyankazope
 
Chap2 exception handling
Chap2 exception handlingChap2 exception handling
Chap2 exception handlingraksharao
 
Exception Handling
Exception HandlingException Handling
Exception HandlingReddhi Basu
 
Exceptionhandling
ExceptionhandlingExceptionhandling
ExceptionhandlingNuha Noor
 
Exception handling in java
Exception handling in javaException handling in java
Exception handling in javaPratik Soares
 
Exception handling in Java
Exception handling in JavaException handling in Java
Exception handling in JavaPrasad Sawant
 
Exception handling
Exception handlingException handling
Exception handlingIblesoft
 
Exception handling in java
Exception handling in javaException handling in java
Exception handling in javaARAFAT ISLAM
 
Exception Handling
Exception HandlingException Handling
Exception Handlingbackdoor
 
Java exception handling
Java exception handlingJava exception handling
Java exception handlingBHUVIJAYAVELU
 

Tendances (20)

exception handling in java
exception handling in java exception handling in java
exception handling in java
 
Types of exceptions
Types of exceptionsTypes of exceptions
Types of exceptions
 
Exception handling
Exception handlingException handling
Exception handling
 
Built in exceptions
Built in exceptions Built in exceptions
Built in exceptions
 
Exception handling in java
Exception handling in javaException handling in java
Exception handling in java
 
Exception handling in java
Exception handling in java Exception handling in java
Exception handling in java
 
Chap2 exception handling
Chap2 exception handlingChap2 exception handling
Chap2 exception handling
 
Exception Handling
Exception HandlingException Handling
Exception Handling
 
Exceptionhandling
ExceptionhandlingExceptionhandling
Exceptionhandling
 
Exception handling in java
Exception handling in javaException handling in java
Exception handling in java
 
Exception handling
Exception handlingException handling
Exception handling
 
exception handling
exception handlingexception handling
exception handling
 
Exception handling in Java
Exception handling in JavaException handling in Java
Exception handling in Java
 
Exception handling
Exception handlingException handling
Exception handling
 
Java exception handling
Java exception handlingJava exception handling
Java exception handling
 
Exception handling
Exception handling Exception handling
Exception handling
 
Java exception
Java exception Java exception
Java exception
 
Exception handling in java
Exception handling in javaException handling in java
Exception handling in java
 
Exception Handling
Exception HandlingException Handling
Exception Handling
 
Java exception handling
Java exception handlingJava exception handling
Java exception handling
 

Similaire à Java Pitfalls and Good-to-Knows (20)

Java tut1
Java tut1Java tut1
Java tut1
 
Tutorial java
Tutorial javaTutorial java
Tutorial java
 
Java Tut1
Java Tut1Java Tut1
Java Tut1
 
Java Tutorial
Java TutorialJava Tutorial
Java Tutorial
 
Java tut1
Java tut1Java tut1
Java tut1
 
Java tut1 Coderdojo Cahersiveen
Java tut1 Coderdojo CahersiveenJava tut1 Coderdojo Cahersiveen
Java tut1 Coderdojo Cahersiveen
 
Java tut1
Java tut1Java tut1
Java tut1
 
Javatut1
Javatut1 Javatut1
Javatut1
 
Java Tutorial
Java TutorialJava Tutorial
Java Tutorial
 
Java basic tutorial by sanjeevini india
Java basic tutorial by sanjeevini indiaJava basic tutorial by sanjeevini india
Java basic tutorial by sanjeevini india
 
Java basic tutorial by sanjeevini india
Java basic tutorial by sanjeevini indiaJava basic tutorial by sanjeevini india
Java basic tutorial by sanjeevini india
 
Java Tutorial | My Heart
Java Tutorial | My HeartJava Tutorial | My Heart
Java Tutorial | My Heart
 
Synapseindia reviews.odp.
Synapseindia reviews.odp.Synapseindia reviews.odp.
Synapseindia reviews.odp.
 
Java tutorials
Java tutorialsJava tutorials
Java tutorials
 
Java tutorial PPT
Java tutorial PPTJava tutorial PPT
Java tutorial PPT
 
Java tutorial PPT
Java tutorial  PPTJava tutorial  PPT
Java tutorial PPT
 
Unit I Advanced Java Programming Course
Unit I   Advanced Java Programming CourseUnit I   Advanced Java Programming Course
Unit I Advanced Java Programming Course
 
Ruby Gotchas
Ruby GotchasRuby Gotchas
Ruby Gotchas
 
Unit 2-data types,Variables,Operators,Conitionals,loops and arrays
Unit 2-data types,Variables,Operators,Conitionals,loops and arraysUnit 2-data types,Variables,Operators,Conitionals,loops and arrays
Unit 2-data types,Variables,Operators,Conitionals,loops and arrays
 
Java Tutorial
Java Tutorial Java Tutorial
Java Tutorial
 

Dernier

08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 

Dernier (20)

08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 

Java Pitfalls and Good-to-Knows

  • 1. Java Pitfalls and Good-to-Knows Miquel Martin – contact@miquelmartin.org Benjamin Hebgen – benjamin.hebgen@gmx.de
  • 2. What’s this? This slide set covers some Java tidbits you might not encounter on your day-to-day java development. Perhaps some of them will improve your coding and save you some debugging! Photo credits: The splashing coffe cup at the title by 96dpi on flicker: http://www.flickr.com/photos/96dpi/ Coffee beans on the watermark by wiedmaier on flicker: http://www.flickr.com/photos/wiedmaier/ Padlock on the ReadWriteLock slide by darwinbell on flicker: http://www.flickr.com/photos/darwinbell/ 2 Tree in the dune by suburbanbloke on flickr: http://www.flickr.com/photos/suburbanbloke/
  • 3. PermGen and Strings  The Java Garbage Collector works on generations. The permanent one hosts internalized Strings and classes. Permanent Generation:  When the compiler finds a literal Class objects, Strings. Won’t String in your code, it allocates it be Garbage Collected (if not yet there) in the string pool Tenured Generation: at the PermGen heap. All instances Multi Garbage Collection of the same String will point to the survivors same PermGen instance. Young Generation: New objects  Too many literal Strings (bad design) or thinks like classloader leaks (http://goo.gl/LIodj) can lead to “Out of MemoryError: PermGen space”. 3
  • 4. StringBuilders and StringBuffers  Strings are immutable. String numberList = ""; for(int i = 0; i < 1000; i++){  The example on the right will: numberList+= i + ", "; 1. Create the numberList String } 2. Create a newNumberList with the numberList, I and a “, “ 3. Assign newNumberList to numberList 4. Repeat 1000 times 2 & 3  This is slow, fills up your heap and therefore forces more costly garbage collections  Use instead a mutable StringBuilder. If StringBuilder builder= new StringBuilder(); you have multiple threads accessing for(int i = 0; i < 1000; i++){ it, use the synchronized version, builder.append(i+", "); } StringBuffer. String numberList = builder.toString(); 4
  • 5. From numbers to Strings  How do you quickly convert a number to a String? int i = 42; String str = i; //Error, i not a String  Case 1: easy but slow, a new String is created that concatenates the literal “” and i. // Case1: All time favorite (and slowest)  Case 2: a new String is directly created for the String str = "" + i; number. This is 2x faster than Case 1 String str = i + "";  Case 3: it internally calls Case 2, and has roughly the same performance. // Case2: the fastest one String str = Integer.toString(myNumber);  Exception: in “The number is “ + i, all three cases are similar since String concatenation must happen anyway, but Case 2 and 3 need to explicitly create // Case3: Also fast (calls Case 2) an additional String. String str = String.valueOf(myNumber);  This also works on: short, float, double, long, etc..  Take home lesson: ignore this and do whatever’s more readable, unless performance is really critical 5
  • 6. Comparing floating point numbers  Floating point numbers are encoded float f = 25 In Hexadecimal: using IEEE754-2008. Not all real 0100 0001 1100 1000 0000 0000 0000 00002 numbers can be represented (e.g. 0.2) Significand: bit ?: 1x1/1 = 1x1 = 1  Extra caution is needed when bit 9: 1x1/2 = 1x0.5 = 0.5 bit 10: 0x1/4 = 0x0.25 = 0 comparing floats (see examples) bit 11: 0x1/8 = 0x0.125 = 0 bit 11: 1x1/16 = 0x0.0625 = 0.0625  Also, portability issues due to . . evolution: Total = 1 + 0.5 + 0.0625 = 1.5625  Java ≤ 1.2: intermediate Bits 1 to 8: Exponent: 1000 00112 is 13110 calculation steps done using and then: 131-127 = 4 single or double precision Bit 0: the sign, 0 is positive Result: + 1.5625 x 24 = 25  Java > 1.2: to decrease rounding //This is true (uses floats) errors the highest platform boolean floatResult = supported precision is used for 0.1f + 0.1f + 0.1f == 0.3f; //This is false (uses doubles) intermediate results. boolean doubleResult = 0.1 + 0.1 + 0.1 == 0.3;  Note: the strictfp keyword forces Java //Also false (also doubles) boolean doubleResult = 1.2 behavior 0.1d + 0.1d + 0.1d == 0.3d; 6
  • 7. Volatile variables  Depending on the JVM, threads package operators; may work on copies of variables class Test extends Thread { boolean done = false; and never re-check the original public void run() { 1 reference. while (!done) {  This does not happen if the } variable is marked volatile, or the System.out.println("Thread terminated."); variable access is synchronized. } Both tell the JVM that multi- thread access is likely and to check public static void main(String[] args) throws InterruptedException { the original reference. Test t = new Test();  The code on the right will never t.start(); finish unless (1) is volatile. The Thread.sleep(1000); behavior can change between t.done = true; JVMs. Also, volatile does not solve System.out.println("done"); concurrent modification issues. } } Don’t rely on volatile unless you know exactly what you’re doing. 7
  • 8. Breaking out of the right loop  The break keyword takes a label as a mytag: for(int i =0; i < 10; i++){ parameter and breaks out of the for(j =0; j < 10; j++){ if(done) { scope tagged for it break mytag; } } }  This works also on switch, for, while and do-while both for continue and break 8
  • 9. Preventing inheritance, overriding and instantiating  Controlling how your class is used // A Utility class has only static methods comes in handy: singletons, factories, public class UtilityClass { utility classes, etc… // Private constructor prevents // external class instantiation private TestClass() {  The final keyword applied to a: }  Class: prevents extending public static int getInstance() {  method: prevents overriding return new TestClass();  primitive field: prevents changing } } the value  Object field: prevents changing // Final class cannot be extended the reference (you can still public final class FinalClass { change the object) // Final primitive cannot be modified final boolean something = false;  A private default constructor will // Reference to final object cannot additionally prevent external //be modified final StringBuilder builder= new StringBuilder(); instantiation  A final Class with only one private // Final method cannot be overriden constructor cannot be extended or public final void someMethod() { } overridden: it will never be externally } instantiated 9
  • 10. Static code blocks  Static blocks let you execute public class StaticBlocks { private static int number = 1; static { something at class loading time System.out.println(number); } (e.g. assign a value to a static static { number = 2; field) }  Static blocks and static field static { System.out.println(number); } assignment is done once at static { class loading } number = increaseNumber(number);  The execution order is the same static { System.out.println(number); as the order in the code } public static int increaseNumber(int i) { return i + 1; } public static void main(String[] args) { System.out.println(number); //Aggregatted output: 1, 2, 3, 3 } } 10
  • 11. Finally we finalize the final.  final is already covered try { System.out.println("In try"); throw new Exception();  finalize will be called on an instance } catch (Exception e) { when (if!) it is garbage collected. System.out.println("In catch");  You have no real control of when } finally { the GC will pass. Plus it’s bad System.out.println("In finally"); practice and often ignored by JVMs }  Do not use it to free resources. // Outputs: In try, In catch, In finally  It’s not the C++ destructor,  finally goes after a try…catch block: BufferedWriter writer = null;  First, run the code in the try try {  If an exception is thrown, run the writer = Files.newBufferedWriter(file, appropriate code in catch charset);  Then, no matter what, run the code writer.write(s, 0, s.length()); in finally. Even after a return in } catch (IOException x) { catch or try. System.err.println("Error happened");  It’s worth using finally even if no } finally { exceptions are expected. They might be if (writer != null) writer.close(); thrown in a future code change. } 11
  • 12. Keywords you don’t see so often • assert: evaluate a boolean expression and throw an AssertionException if false. Useful to write your assumptions in the code, and get notified if you were wrong • continue: skip to the next iteration of a loop • strictfp: ensures consistent floating point operations on different platforms • transient: keep the field from being serialized when using standard java serialization mechanisms • volatile: prevents threads from working with a thread local copy of a variable when not using synchronized access • native: denotes that the method is provided by an external non-java library using JNI • goto: it’s a reserved keyword but a valid keyword. The compiler will throw a syntax error • const: same as goto 12
  • 13. Protective copies  In this code, some internal logic class Test { occurs on adding/removing private List<String> internalStuff = new ArrayList<String>(); stuff. public void addStuff(String stuff) { //Do internal logic  If getAllStuff returns internalStuff.add(stuff); internalStuff, the caller can } public void removeStuff(String stuff) { add/remove items without //Do internal logic going through removeStuff internalStuff.remove(stuff); }  If this is (or could be) an issue, public List<String> getAllStuff(){ //Dangerous: return internalStuff; create a protective copy of //Better: internalStuff first return new ArrayList<String>(internalStuff); } } 13
  • 14. Shallow comparison and Arrays  Comparison types: String[] a1 = new String[] { "0", "1", "2" }; String[] a2 = new String[] { "0", "1", "2" };  Shallow: uses == and System.out.println(a1 == a2); // false compares object System.out.println(a1.equals(a2)); // false 1 System.out.println(Arrays.equals(a1, a2)); // true references  Deep: uses equals and is List<String> list1 = new ArrayList<String>(3); List<String> list2 = new ArrayList<String>(3); as good as your equals list1.add("0"); implementation list2.add("0"); list1.add("1"); list2.add("1"); list1.add("2"); list2.add("2");  Notable exception: equals is System.out.println(list1 == list2); // false odd for arrays (1) and will System.out.println(list1.equals(list2)); perform a shallow // true if the elements in the list properly implement equals comparison. Use Arrays.equals instead 14
  • 15. Checked VS Unchecked exceptions  Unlike Unchecked exceptions, Throwable Checked exceptions need to be caught or declared  Pros of unchecked exceptions: Exception Error  Clearer code  You can still treat them like ? extends Runtime ? extends Exception checked exceptions if you Exception Error want ? extends Runtime  Cons: Easy to miss Exception Unchecked Exceptions  JsonParseException in Gson  NumberFormatException from new Integer(“3,4”) in some locales 15
  • 16. Testing with Hamcrest Matchers  In JUnit, assertTrue, public class RegexMatcher extends BaseMatcher<String> { assertEquals, etc… perform private final String regex; specific assertions public RegexMatcher(String regex) { this.regex = regex; }  For arbitrary assertions, you @Override can use a Hamcrest Matcher public boolean matches(Object s) { return ((String) s).matches(regex); and run it with assertThat } @Override public void describeTo(Description description) { description.appendText("matches " + regex); } public static RegexMatcher matches(String regex) { return new RegexMatcher(regex); } } //Allows you to do: assertThat(actual, matches(regex)); 16
  • 17. Type erasure  The Java generics implementation public void doSomething(List<String> does not change the compiler list) {} much, instead, it pre-processes public void doSomething(List<Integer> away the generics list) { }  At compile time, type parameters // Compiler error: both methods can’t are replaced with their bounds be in the same class, since they have the same type erasure  Types are “erased” in the compiled bytecode  Famous pitfall: after type erasure, List<String> is the same as List<Integer>  There’s plenty more interesting gotchas in generics, check: http://goo.gl/0AeYW 17
  • 18. Read/Write Locks  Case: you don’t care how many threads read your object, as long as no one is modifying it, and then, only one at a time.  Solution: replace your synchronized methods with ReadWriteLocks  Beware of the details:  in balanced read/write scenarios, the overhead of a ReadWriteLock will likely degrade performance.  Thread starvation and fairness are an issue. Check ReentrantLocks  A good discussionL http://goo.gl/zRjvL 18
  • 19. Synchronized Collections  You’ll still find online that: List<String> unsynchronizedList = new  A Hashtable is like a HashMap but ArrayList<String>(); synchronized (there’s more to it, List<String> synchronizedList = like null values) Collections.synchronizedList(unsynchro  A Vector is like an ArrayList but nizedList); synchronized (it isn’t)  This hasn’t been true since Java Map<String, String> unsynchronizedMap = 1.3 introduced the Synchronized new LinkedHashMap<String, String>(); Collections Map<String, String> synchronizedMap =  Note that Read/Write locks are Collections.synchronizedMap(unsynchron Java >=1.5 so there’s plenty room izedMap); for optimizing if you need to.  Notable exception: ConcurrentHashMap is (probably) your high-performance map for multi-threaded access 19
  • 20. Legacy Classes Legacy classes are not (yet) deprecated but their use is discouraged. They still pop up in plenty of tutorials and snippets.  Vector and Dictionary/Hashtable should not be used as synchronized List and Map. Use Collections.synchronizedList and Collections.synchronizedMap instead. Also consider ConcurrentHashMap.  Properties extends Hashtable with file writing capabilities, but there’s no replacement.  Stack is a revamp of Vector to work like a LinkedList. Use that instead.  StringTokenizer is better implemented by String.split and also handles encoding better  Enumeration is very close to an Iterator but does less (e.g. remove)  Most discouraged classes are parallel implementations of existing classes with a minor (often mis- implemented) delta. 20
  • 21. equals, hashCode and Comparable // HashMap put  Different collections use public V put(K key, V value) { if (key == null) different mechanisms to sort return putForNullKey(value); int hash = hash(key.hashCode()); out objects, for example: // Locate the bucket by hashCode  HashMap uses hashCode int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e =  TreeSet uses Comparable e.next) { Object k;  If hashCode and Comparable // Check for equality only in the bucket if (e.hash == hash && ((k = e.key) == key || are not consistent with equals, key.equals(k))) { V oldValue = e.value; expect inconsistencies! Check e.value = value; e.recordAccess(this); the contract. } return oldValue; } modCount++; addEntry(hash, key, value, i); return null; } 21
  • 22. Java 7’s NIO.2 Java 7’s new file I/O makes file system Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); interactions much easier WatchService  Implemented in java.nio.file.Files and watchService = new WatchService() { ... java.nio.file.Path }; path.register(watchService, ENTRY_CREATE,  It provides common file operations ENTRY_DELETE, ENTRY_MODIFY); like copy or readAllLines Files.getPosixFilePermissions(path,  You can get notifications on Path LinkOption.NOFOLLOW_LINKS); modifications Files.isExecutable(path); Files.isReadable(path);  Support for permission and owner Files.isWritable(path); handling and links Files.readAllLines(path, Charset.forName("utf-8"));  Fine grained exception handling Files.write(path, "mytext".getBytes(Charset. forName("utf-8")), StandardOpenOption.CREATE); 22
  • 23. Where to store resources  Best practice for user specific String winPath = System.getProperty(" user.home") + File.separator + configuration options per OS: "Application Data" + File.separator + "myApp"; String linuxPath = System.getProperty ("user.home") + File.separator + ".myApp";  Storing in your classpath (e.g. in your TestClass.class.getResourceAsStream(" myresource.xml") jar) using Class.getResourceAsStream  If you really really want, there is a way //This will find your class to find the path to your class, allowing MyClass.class.getProtectionDomain().g etCodeSource().getLocation().getP for storage relative to the installation ath(); folder 23
  • 24. (Avoid) Reinventing the wheel  There are a lot of 3rd party libraries for Java. Avoid reinventing the wheel! Also beware of very alpha libraries!  You will only use stuff you know exists. Consider browsing through the documentation of libraries like:  Apache Commons: for anything from logging to collections and much more http://commons.apache.org/  Google’s Guava: for a ton of convenience classes and very interesting containers http://code.google.com/p/guava-libraries/  OPS4J: for all sort of OSGi related helpers http://team.ops4j.org 24
  • 25. Thanks and Happy Coding! 25