Java Interview 1

Card Set Information

Author:
smlathro
ID:
173849
Filename:
Java Interview 1
Updated:
2012-09-27 12:08:25
Tags:
Java interview
Folders:

Description:
Practice key questions for a Java coding interview (http://java-success.blogspot.com.au/)
Show Answers:

Home > Flashcards > Print Preview

The flashcards below were created by user smlathro on FreezingBlue Flashcards. What would you like to do?


  1. write code to bubble sort { 30, 12, 18, 0, -5, 72, 424 }
    • package algorithms;
    • import java.util.Arrays;
    •   
    • public class BubbleSort {
    •   
    •     public static void main(String[ ] args) {
    •         Integer[ ] values = { 30, 12, 18, 0, -5, 72, 424 };
    •         int size = values.length;
    •         System.out.println("Before:" + Arrays.deepToString(values));
    •   
    •         for (int pass = 0; pass < size - 1; pass++) {
    •             for (int i = 0; i < size - pass - 1; i++) {
    •                 // swap if i > i+1
    •                 if (values[i] > values[i + 1])
    •                     swap(values, i, i + 1);
    •             }
    •         }
    •   
    •         System.out.println("After:" + Arrays.deepToString(values));
    •     }
    •   
    •     private static void swap(Integer[ ] array, int i, int j) {
    •         int temp = array[i];
    •         array[i] = array[j];
    •         array[j] = temp;
    •     }
    • }
  2.  Is there a more efficient sorting algorithm than Bubble? Explain.
    Although bubble-sort is one of the simplest sorting algorithms, it's also one of the slowest. It has the O(n^2) time complexity. Faster algorithms include quick-sort and heap-sort. The Arrays.sort( ) method uses the quick-sort algorithm, which on average has O(n * log n) but can go up to O(n^2) in a worst case scenario, and this happens especially with already sorted sequences.
  3. Write a program that will return whichever value is nearest to the value of 100 from two given int numbers.
    pseudo code as follows:

    • Compute the difference to 100.
    • Find out the absolute difference as negative numbers are valid.
    • Compare the differences to find out the nearest number to 100.
    • Write test cases for +ve, -ve, equal to, > than and < than values.


    • package chapter2.com; 
    •    
    • public class CloseTo100 { 
    •    
    •     public static int calculate(int input1, int input2) {
    •   
    •          //compute the difference. Negative values are allowed as well 
    •   
    •         int iput1Diff = Math.abs(100 - input1);
    •   
    •         int iput2Diff = Math.abs(100 - input2); 
    •    
    •         //compare the difference
    •   
    •         if (iput1Diff < iput2Diff) return input1;
    •         else if (iput2Diff < iput1Diff) return input2;
    •         else return input1;                                 //if tie, just return one
    •     }
    •       
    •     public static void main(String[ ] args) {
    •         //+ve numbers
    •         System.out.println("+ve numbers=" + calculate(50,90));
    •           
    •         //-ve numbers
    •         System.out.println("-ve numbers=" + calculate(-50,-90));
    •           
    •         //equal numbers
    •         System.out.println("equal numbers=" + calculate(50,50));
    •           
    •         //greater than 100
    •         System.out.println(">100 numbers=" + calculate(85,105));
    •   
    •         System.out.println("<100 numbers=" + calculate(95,110));
    •     } 
    • }

    • Output:
    • +ve numbers=90
    • -ve numbers=-50
    • equal numbers=50
    • >100 numbers=105
    • <100 numbers=95
  4. Write a method that reverses a given String.
    • public class ReverseString { 
    •    
    •     public static void main(String[ ] args) {
    •   
    •         System.out.println(reverse("big brown fox"));
    •   
    •         System.out.println(reverse(""));       
    •   
    •     }  
    •    
    •     public static String reverse(String input) {
    •   
    •         if(input == null || input.length( ) == 0){
    •   
    •             return input;
    •   
    •         } 
    •    
    •         return new StringBuilder(input).reverse( ).toString( );  
    •     } 
    • }

    It is always a best practice to reuse the API methods as shown above with the StringBuilder(input).reverse( ) method as it is fast, efficient (uses bitwise operations) and knows how to handle Unicode surrogate pairs, which most other solutions ignore. The above code handles null and empty strings, and a StringBuilder is used as opposed to a thread-safe StringBuffer, as the StringBuilder is locally defined, and local variables are implicitly thread-safe. Some interviewers might probe you to write other lesser elegant code using either recursion or iterative swapping. Some developers find it very difficult to handle recursion, especially to work out the termination condition. All recursive methods need to have a condition to terminate the recursion.

    • public class ReverseString2 {
    •       
    •     public String reverse(String str) {
    •         // exit or termination condition
    •         if ((null == str) || (str.length( )  <= 1)) {
    •             return str;
    •         }
    •           
    •         // put the first character (i.e. charAt(0)) to the end. String indices are 0 based. 
    •         // and recurse with 2nd character (i.e. substring(1)) onwards  
    •         return reverse(str.substring(1)) + str.charAt(0);
    •     }
    • }

    There are other solutions like

    • public class ReverseString3 {
    •       
    •     public String reverse(String str) {
    •         // validate
    •         if ((null == str) || (str.length( )  <= 1)) {
    •             return str;
    •         }
    •           
    •         char[ ] chars = str.toCharArray( );
    •         int rhsIdx = chars.length - 1;
    •           
    •         //iteratively swap until exit condition lhsIdx < rhsIdx is reached
    •         for (int lhsIdx = 0; lhsIdx < rhsIdx; lhsIdx++) {
    •             char temp = chars[lhsIdx];
    •             chars[lhsIdx] = chars[rhsIdx];
    •             chars[rhsIdx--] = temp;
    •         }
    •           
    •         return new String(chars);
    •     }
    • }

    • Or 
    •    
    • public class ReverseString4 {
    •        
    •     public String reverse(String str) {
    •         // validate
    •         if ((null == str) || (str.length( )  <= 1)) {
    •             return str;
    •         }
    •            
    •           
    •         char[ ] chars = str.toCharArray( );
    •         int length = chars.length;
    •         int last = length - 1;
    •            
    •         //iteratively swap until reached the middle
    •         for (int i = 0; i < length/2; i++) {
    •             char temp = chars[i];
    •             chars[i] = chars[last - i];
    •             chars[last - i] = temp;
    •         }
    •            
    •         return new String(chars);
    •     } 
    •        
    •     public static void main(String[] args) {
    •       String result = new ReverseString4().reverse("Madam, I'm Adam");
    •       System.out.println(result);
    •    }
    • }
  5. What will be the output of the following code snippet?
    Object s1 = new String("Hello");
    Object s2 = new String("Hello");
     
    if(s1 == s2) {
      System.out.println("s1 and s2 are ==");
    }else if (s1.equals(s2)) {
      System.out.println("s1 and s2 are equals()");
    }
    s1 and s2 are equals()
  6. What will be the output for the following code snippet?
    Object s1 = "Hello";
    Object s2 = "Hello";
     
    if (s1 == s2) {
     System.out.println("s1 and s2 are ==");
    } else if (s1.equals(s2)) {
     System.out.println("s1 and s2 are equals()");
    }
    s1 and s2 are ==
  7. What will be the output of the following code snippet and how do you fix the issue?
    public class MethodOverrideVsOverload {
        
     public boolean equals( MethodOverrideVsOverload other ) {
         System.out.println("MethodOverrideVsOverload equals method reached" );
         return true;
       }
       
     public static void main(String[] args) {
      Object o1 = new MethodOverrideVsOverload();
      Object o2 = new MethodOverrideVsOverload();
        
      MethodOverrideVsOverload o3 = new MethodOverrideVsOverload();
      MethodOverrideVsOverload o4 = new MethodOverrideVsOverload();
        
      if(o1.equals(o2)){
       System.out.println("objects o1 and o2 are equal");
      }
        
      if(o3.equals(o4)){
       System.out.println("objects o3 and o4 are equal");
      }
     }
    }
    • MethodOverrideVsOverload equals method reached
    • objects o3 and o4 are equal

    In Java 5, annotations were introduced and one of the handy compile time annotations is the @override, which will ensure that the methods are overridden correctly. If you had this annotation, when you override it incorrectly as in the above example, a compile time error will be thrown. 

    So, to fix it, add the @override annotation to the "boolean equals( MethodOverrideVsOverload other )" of the MethodOverrideVsOverload  class. This will give you a compile time error indicating that the method is not properly overridden
  8. Can you write a sample code that will count the number of "A"s in a given text? Show both iterative and recursive approaches?
    Let's assume the input string is "AAA rating". The iterative approach is pretty straight forward as illustrated below.

    • public class Iteration {
    •   
    •     public int countA(String input) {
    •         if (input == null || input.length( ) == 0) {
    •             return 0;
    •         }
    •   
    •         int count = 0;
    •         for (int i = 0; i < input.length( ); i++) {
    •             if(input.substring(i, i+1).equals("A")){
    •                 count++;
    •             }
    •         }
    •         return count;
    •     }
    •   
    •     public static void main(String[ ] args) {
    •           System.out.println(new Iteration( ).countA("AAA rating"));     // Ans.3
    •     }

    Now, let's look at the recursive approach.

    • public class RecursiveCall {
    •   
    •     public int countA(String input) {
    •          
    •         // exit condition – recursive calls must have an exit condition
    •         if (input == null || input.length( ) == 0) {
    •             return 0;
    •         }
    •   
    •         int count = 0;
    •            
    •         //check first character of the input 
    •         if (input.substring(0, 1).equals("A")) {
    •             count = 1;
    •         }
    •           
    •         //recursive call to evaluate rest of the input 
    •         //(i.e.  2nd character onwards)
    •         return count + countA(input.substring(1)); 
    •     }
    •   
    •     public static void main(String[ ] args) {
    •         System.out.println(new RecursiveCall( ).countA("AAA rating"));    // Ans. 3
    •     }
    • }
  9. What concepts do you need to know to understand recursion?
    A re-entrant method would be one that can safely be entered, even when the same method is being executed, further down the call stack of the same thread. A non-re-entrant method would not be safe to use in that way. For example, writing or logging to a file can potentially corrupt that file, if that method were to be re-entrant.A function is recursive if it calls itself. Given enough stack space, recursive method calls are perfectly valid in Java though it is tough to debug. Recursive functions are useful in removing iterations from many sorts of algorithms. All recursive functions are re-entrant, but not all re-entrant functions are recursive.Stack uses LIFO (Last In First Out), so it remembers its ‘caller’ and knows whom to return when the function has to return. Recursion makes use of system stack for storing the return addresses of the function calls.Java is a stack based language.
  10. When would you use recursion?
    Recursion might not be the efficient way to code the above example and iterative approach will do the job, but there are scenarios where recursion is preferred as recursive functions are shorter, simpler, and easier to read and understand. Recursive functions are very handy in working with tree structures and avoiding unsightly nested for loops.
  11. What is a tail recursion, and why would you need it? Can you rewrite the above code with tail recursion?
    Regular recursive function (aka head recursion) demonstrated above grows the size of the call stack. Each time the function calls itself, another entry has to be pushed onto the stack. The thing the function has to do before returning is add count with the result of countA(input.substring(1), assuming count is greater than 1, the computer has to evaluate count + countA(input.substring(1)), and in order to do that it must evaluate countA(input.substring(1)). This alse mean that you need to wait for the call to countA(input.substring(1) to complete so that you can add the value it returns with count. So, the last thing done here is actually the addition, not the recursive call.

    • What is the befit of tail recursion? 
    • In tail recursion, the last thing done is the recursion and the addition would have been done before. You don't have any use for the old information because there’s nothing to do after the recursive call. You can throw out all of your old information and simply run the function again with the new set of parameters. This means you run with shorter call stack leading to lower memory usage and better performance.

    • Here is the above rewritten with tail recursion.
    • public class TailRecursiveCall {
    •   
    •  public int countA(String input) {
    •   
    •   // exit condition – recursive calls must have an exit condition
    •   if (input == null || input.length() == 0) {
    •    return 0;
    •   }
    •     
    •   return countA(input, 0) ;
    •  }
    •    
    •  public int countA(String input, int count) {
    •   if (input.length() == 0) {
    •    return count;
    •   }
    •     
    •   // check first character of the input
    •   if (input.substring(0, 1).equals("A")) {
    •    count = count + 1;
    •   }
    •   
    •   // recursive call is the last call as the count is cumulative
    •   return countA(input.substring(1), count);
    •  }
    •   
    •  public static void main(String[] args) {
    •   System.out.println(new TailRecursiveCall().countA("AAA rating"));
    •  }
    • }
  12. How will you go about improving on the following code snippet that calculates the new balance based on the current balance, total debits, and total credits? Note: All amounts need to be positive values.
    import java.math.BigDecimal;
      
    public class CashCalculatorBasic {
      
     public BigDecimal getCalculatedAvailableBalance(BigDecimal currentBalance, BigDecimal totalDebits, 
                                               BigDecimal totalCredits) {
        
      BigDecimal result =  currentBalance
         .subtract(totalDebits)
         .add(totalCredits);
        
      System.out.println("The calculated result is " + result);
        
      return result;
      
     }
      
     public static void main(String[] args) {
          
        new CashCalculatorBasic().getCalculatedAvailableBalance(
        new BigDecimal("1250.00"), new BigDecimal("250.00"), new BigDecimal("500.00"));
     }
    }
    Firstly, a good thing about the above code is that it uses the BigDecimal class instead of a floating point type like float or double. Here are a number of things that can be improved.

    • 1. Don't use System.out.println(.....) and replace it with the log4j and slf4j framewowrks. It is a bad practice to use System.out.println because you cannot easily change log levels, turn it off, customize it, etc. A proper logging system, like Log4J, adds all sorts of features that are very useful in real applications. You can direct the output to different places (console, file, network, etc.). You can tell it to output only a subset of the messages, without having to recompile. You can get timestamp on each message, etc
    • 2. Don't use static void main method to test your class. Write unit tests using a unit testing framework like JUnit or TestNG.3. Don't test only the happy path. Include negative test scenarios as well. By writing proper test cases, the code can be refactored with confidence.
    • 4. The above code does not fail fast. A fail fast code is the one that performs input validation and throws any validation errors if the pre-conditions or post conditions are not met. For example, testing for null, empty String, negative values, etc.
    • 5. Your code should favour code to interface. What if you want to write an improved CashCalculator? You will have to go and change all your references where CashCalculatorBasic is used.
    • 6. The readability can be improved by abstracting out the calculation to a separate util class or an inner class as shown below. This will be really useful when you have more methods to calculate different values, which would be the case in real life scenario. This will also improve readability and reusability of the code. Here is the improved code. Define an interface, which is the contract for the invokers or callers.

    • import java.math.BigDecimal;
    •   
    •   
    • public interface CashCalculator {
    •    
    •   BigDecimal getCalculatedAvailableBalance(BigDecimal currentBalance, BigDecimal totalDebits, 
    •                                      BigDecimal totalCredits) ;
    •   
    • }

    http://java-success.blogspot.com.au/2012/06/reviewing-given-java-code-in-job.html
  13. Can you review the given code and provide your feedback?
    import java.text.SimpleDateFormat;
    import java.util.Date;
      
    public class DateUtil {
       
     SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
       
     public String formatDate(Date input) {
          return sdf.format(input);
     }
       
    }
    • 1. The code does not fail fast by checking for the preconditions.
    • 2. The above code is not thread-safe as the SimpleDateFormat class is not thread-safe. If you check the API documentation, you will see
    • Synchronization: Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally. Multiple threads are accessing the single instance of the "SimpleDateFormat" object via the reference "sdf". Since the methods in the SimpleDateFormat class are not properly synchronized, they are not thread-safe. 

    The thread-safety issue can be resolved a number of ways.

    • Solution 1: Here is the thread safe code.
    • import java.text.SimpleDateFormat;
    • import java.util.Date;
    •   
    • public class DateUtil {
    •    
    •  private static final String SIMPLE_FORMAT = "dd/MM/yyyy";
    •    
    •  public String formatDate(Date input) {
    •     
    •   if(input == null){
    •    return null;
    •   }
    •     
    •   SimpleDateFormat sdf = new SimpleDateFormat(SIMPLE_FORMAT);//local variable
    •   return sdf.format(input);
    •  }
    • }

    Solution 2: While the solution 1 is thread-safe, it will end up creating too many SimpleDateFormat objects in the heap if a single thread invokes the formatDate(Date input) method multiple times. This can be overcome by creating the SimpleDateFormat objects as "per thread singleton" with the ThreadLocal class.

    • import java.text.SimpleDateFormat;
    • import java.util.Date;
    •   
    • public class DateUtil {
    •   
    •  // anonymous inner class. Each thread will have its own copy of the SimpleDateFormat
    •  private final static ThreadLocal<SIMPLEDATEFORMAT> tl = new ThreadLocal<SIMPLEDATEFORMAT>() {
    •   protected SimpleDateFormat initialValue() {
    •    return new SimpleDateFormat("dd/MM/yyyy");
    •   }
    •  };
    •   
    •  public String formatDate(Date input) {
    •   if (input == null) {
    •    return null;
    •   }
    •   
    •   return tl.get().format(input);
    •  }
    • }
  14. How do you know that your classes are badly designed?
    If your application is fragile – when making a change, unexpected parts of the application can break.

    If your application is rigid – it is hard to change one part of the application without affecting too many other parts.

    If your application is immobile – it is hard to reuse the code in another application because it cannot be separated. Overly complex design is as bad as no design at all. Get the granularity of your classes and objects right without overly complicating them. Don't apply too many patterns and principles to a simple problem. Apply them only when they are adequate. Don't anticipate changes in requirements ahead of time. Preparing for future changes can easily lead to overly complex designs. Focus on writing code that is not only easy to understand, but also flexible enough so that it is easy to change if the requirements change.
  15. Can you explain if the following classes are badly designed? The following snippets design the classes & interfaces for the following scenario. Bob, and Jane work for a restaurant. Bob works as manager and a waiter. Jane works as a waitress. A waiter's behavior is to take customer orders and a manager's behavior is to manage employees.

    package badrestaurant;
      
    public interface Person {}

    package badrestaurant;
      
    public interface Manager extends Person {
        public void managePeople( );
    }

    package badrestaurant;
      
    public interface Waiter extends Person {
        public void takeOrders( ); 
    }

    package badrestaurant;
      
    public class Bob implements Manager, Waiter {
      
        @Override
        public void managePeople( ) {
            //implementation goes here
        }
      
        @Override
        public void takeOrders( ) {
            //implementation goes here
        }
    }

    package badrestaurant;
      
    public class Jane implements Waiter {
      
        @Override
        public List<string> takeOrders( ) {
            //implementation goes here
        }
    }
    The Restaurant class uses the above classes as shown below.

    package badrestaurant;
      
    public class Restaurant {
          
        public static void main(String[ ] args) {
              
            Bob bob = new Bob( );
            bob.managePeople( );
            bob.takeOrders( );
              
            Jane jane = new Jane( );
            jane.takeOrders( );
        }
    }
    The name should be an attribute, and not a class like Bob or Jane. A good OO design should hide non-essential details through abstraction. If the restaurant employs more persons, you don't want the system to be inflexible and create new classes like Peter, Jason, etc for every new employee.

    The above solution's incorrect usage of the interfaces for the job roles like Waiter, Manager, etc will make your classes very rigid and tightly coupled by requiring static structural changes. What if Bob becomes a full-time manager? You will have to remove the interface Waiter from the class Bob. What if Jane becomes a manager? You will have to change the interface Waiter with Manager.

    The above drawbacks in the design can be fixed as shown below by asking the right questions. Basically waiter, manager, etc are roles an employee plays. You can abstract it out as shown below.

    • package goodrestuarant;
    •   
    • public interface Role {
    •     public String getName( );
    •     public void perform( );
    • }

    • package goodrestuarant;
    •   
    • public class Waiter implements Role {
    •       
    •     private String roleName;
    •       
    •     public Waiter(String roleName) {
    •         this.roleName = roleName;
    •     }
    •   
    •     @Override
    •     public String getName( ) {
    •        return this.roleName;
    •     }
    •   
    •     @Override
    •     public void perform( ) {
    •        //implementation goes here
    •     }
    • }

    • package goodrestuarant;
    •   
    • public class Manager implements Role {
    •       
    •     private String roleName;   
    •       
    •     public Manager(String roleName) {
    •         this.roleName = roleName;
    •     }
    •   
    •     @Override
    •     public String getName( ) {
    •        return this.roleName;
    •     }
    •   
    •     @Override
    •     public void perform( ) {
    •        //implementation goes here
    •     }
    • }

    The Employee class defines the employee name as an attribute as opposed to a class. This makes the design flexible as new employees can be added at run time by instantiating new Employee objects with appropriate names. This is the power of abstraction. You don't have to create new classes for each new employee. The roles are declared as a list using aggregation (i.e. containment), so that new roles can be added or existing roles can be removed at run time as the roles of employees change. This makes the design more flexible.

    • package goodrestuarant;
    •   
    • import java.util.ArrayList;
    • import java.util.List;
    •   
    • public class Employee {
    •       
    •     private String name;
    •     private List<role> roles = new ArrayList<role>(10);
    •       
    •     public Employee(String name){
    •         this.name = name;
    •     }
    •   
    •     public String getName( ) {
    •         return name;
    •     }
    •   
    •     public void setName(String name) {
    •         this.name = name;
    •     }
    •   
    •     public List<role> getRoles( ) {
    •         return roles;
    •     }
    •   
    •     public void setRoles(List<role> roles) {
    •         this.roles = roles;
    •     }
    •       
    •     public void addRole(Role role){
    •         if(role == null){
    •             throw new IllegalArgumentException("Role cannot be null");
    •         }
    •         roles.add(role);
    •     }
    •       
    •     public void removeRole(Role role){
    •         if(role == null){
    •             throw new IllegalArgumentException("Role cannot be null");
    •         }
    •         roles.remove(role);
    •     }
    • }

    The following Restaurant class shows how flexible, extensible, and maintainable the above design is.

    • package goodrestuarant;
    •   
    • import java.util.List;
    •   
    • public class Restaurant {
    •       
    •     public static void main(String[ ] args) {
    •           
    •         Employee emp1 = new Employee ("Bob");
    •         Role waiter = new Waiter("waiter");
    •         Role manager = new Manager("manager");
    •           
    •         emp1.addRole(waiter);
    •         emp1.addRole(manager);
    •           
    •         Employee emp2 = new Employee("Jane");
    •         emp2.addRole(waiter);
    •           
    •         List<role> roles = emp1.getRoles( );
    •         for (Role role : roles) {
    •             role.perform( );
    •         }
    •           
    •         //you can add more employees or change roles based on 
    •         //conditions here at runtime. More flexible.   
    •     }
    • }
  16. What do you achieve through good class and interface design?
    Loosely coupled classes, objects, and components enabling your application to easily grow and adapt to changes without being rigid or fragile.

    Less complex and reusable code that increases maintainability, extendability and testability.
  17. What are the 3 main concepts of OOP?
    Encapsulation, polymorphism, and inheritance are the 3 main concepts or pillars of an object oriented programming. Abstraction is another important concept that can be applied to both object oriented and non object oriented programming. [Remember: a pie ? abstraction, polymorphism, inheritance, and encapsulation.]
  18. What problem(s) does abstraction and encapsulation solve?
    Both abstraction and encapsulation solve same problem of complexity in different dimensions. Encapsulation exposes only the required details of an object to the caller by forbidding access to certain members, whereas an abstraction not only hides the implementation details, but also provides a basis for your application to grow and change over a period of time. For example, if you abstract out the make and model of a vehicle as class attributes as opposed to as individual classes like Toyota, ToyotaCamry, ToyotaCorolla, etc, you can easily incorporate new types of cars at runtime by creating a new car object with the relevant make and model as arguments as opposed to having to declare a new set of classes.
  19. How would you go about designing a “farm animals” application where animals like cow, pig, horse, etc move from a barn to pasture, a stable to paddock, etc? The solution should also cater for extension into other types of animals like circus animals, wild animals, etc in the future.
    • package subclass0;
    •   
    • public abstract class Animal {
    •     private int id;                                // id is encapsulated
    •   
    •     public Animal(int id) {
    •         this.id = id;
    •     }
    •   
    •     public int getId( ) {
    •         return id;
    •     }
    •   
    •     public abstract void move(Location location);
    • }

    • package subclass0;
    •   
    • public class FarmAnimal extends Animal {
    •   
    •     private Location location = null;                   // location is encapsulated
    •   
    •     public FarmAnimal(int id, Location defaultLocation) {
    •         super(id);
    •         validateLocation(defaultLocation);
    •         this.location = defaultLocation;
    •     }
    •   
    •     public Location getLocation( ) {
    •         return location;
    •     }
    •   
    •     public void move(Location location) {
    •         validateLocation(location);
    •         System.out.println("Id=" + getId( ) + " is moving from "
    •                 + this.location + " to " + location);
    •         this.location = location;
    •     }
    •   
    •     private void validateLocation(Location location) {
    •         if (location == null) {
    •             throw new IllegalArgumentException("location=" + location);
    •         }
    •     }
    • }

    • package subclass0;
    •   
    • public enum Location  {
    •     Barn, Pasture, Stable, Cage, PigSty, Paddock, Pen
    • }

    • package subclass0;
    •   
    • public class Example {
    •   
    •     public static void main(String[ ] args) {
    •         Animal pig = new FarmAnimal(1, Location.Barn);
    •         Animal horse = new FarmAnimal(2, Location.Stable);
    •         Animal cow = new FarmAnimal(3, Location.Pen);
    •   
    •         pig.move(Location.Paddock);
    •         horse.move(Location.Pen);
    •         cow.move(Location.Pasture);
    •     }
    • }

    • Output:
    • Id=1 is moving from Barn to Paddock
    • Id=2 is moving from Stable to Pen
    • Id=3 is moving from Pen to Pasture

    In the above example, the class FarmAnimal is an abstraction used in place of an actual farm animal like horse, pig, cow, etc. In future, you can have WildAnimal, CircusAnimal, etc extending the Animal class to provide an abstraction for wild animals like zebra, giraffe, etc and circus animals like lion, tiger, elephant, etc respectively. An Animal is a further abstraction generalizing FarmAnimal, WildAnimal, and CircusAnimal. The Location is coded as an enumeration for simplicity. The Location itself can be an abstract class or an interface providing an abstraction for OpenLocation, EnclosedLocation, and SecuredLocation further abstracting specific location details like barn, pen, pasture, pigsty, stable, cage, etc. The location details can be represented with attributes like “name”, “type”, etc.

    The FarmAnimal class is also well encapsulated by declaring the attribute “location” as private. Hence the “location” variable cannot be directly accessed. Assignment is only allowed through the constructor and move(Location location) method, only after a successful precondition check with the validateLocation(...) method. The validateLocation(...) itself marked private as it is an internal detail that does not have to be exposed to the caller. In practice, the public move(..) method can make use of many other private methods that are hidden from the caller. The caller only needs to know what can be done with an Animal. For example, they can be moved from one location to another. The internal details as to how the animals are moved is not exposed to the caller. These implementation details are specific to FarmAnimal, WildAnimal, and CircusAnimal classes.
  20. How will you go about writing code for counting the number of repeated words in the order of decreasing count for a given text input?

    For example, input text = "The third-rate mind is only happy when it is thinking with the majority. The second-rate mind is only happy when it is thinking with the minority. The first-rate mind is only happy when it is thinking."

    NOTE:
    As mentioned before, the interviewer is not expecting you to come up with the perfect solution. He/she will be more interested in finding out the following:
    1. Can you write pseudo code?
    2. Do you analyze the requirements properly by asking the right questions?
    3. Can you write basic code by referring to the Java API, etc?
    4. Do you write unit tests?
    1.Can you write pseudo code?

    • Tokenize the input text into words
    • Build a map<word, count> to store the individual words and its relevant count
    • Iterate through the tokenized words and if the word is already stored, increment its count and if not already stored, store it with the count of 1.
    • Sort the map by count in decrementing order
    • Loop through the sorted map and print the "word" and its count

    2.Do you analyze the requirements properly by asking the right questions?

    How are the words tokenized? by whitespace character only, white space and punctuations, how about URLs? , etc, The regular expression can be used for splitting the text. [ignore URL to keep it simple]

    Are there any common words that need to be ignored? For example, 'the', 'a', 'or', 'and', etc. [yes]

    Is it case sensitive? Should word and WORD be treated as the same word? [yes]

    3.Can you write basic code by referring to the Java API, etc?

    Use regex to split string into tokens

    Use a Map that has o(1) look up to save the tokens and increment the count

    Use a custom comparator to sort the map by its count in descending order. This means most repeated words at the top.

    http://java-success.blogspot.com.au/2012/07/can-you-write-code-by-asking-right.html
  21. Can you write a function to determine the nth Fibonacci number?
    This can be achieved with recursion or iteration. You can learn more about recursion at iteration Vs recursion. If you provide an iterative solution then there will be follow up question to write recursive solution and vice versa.

    • Recursive solution:
    • public class RecursiveFibonacci {
    •    
    •  public int fibonacci(int n){
    •   if(n<0){
    •     throw new IllegalArgumentException("Input parameter is invalid " + n); 
    •   }
    •     
    •   if(n == 0){
    •     return 0;
    •   }
    •     
    •   else if(n <= 2){
    •     return 1;
    •   }
    •   else {
    •     return fibonacci(n-1)+fibonacci(n-2); // head recursion
    •   } 
    •  }
    •    
    •  public static void main(String[] args) {
    •    int nThfibonacciNo = new RecursiveFibonacci().fibonacci(17);
    •    System.out.println(nThfibonacciNo);
    •  }
    •   
    • }

    Iterative Solution:

    • public class IterativeFibonacci {
    •   
    •  public int fibonacci(int n) {
    •   if (n < 0) {
    •    throw new IllegalArgumentException("Input parameter is invalid " + n);
    •   }
    •   
    •   int num1 = 0, num2 = 1;
    •     
    •   //zeroth fibonacci number is 0
    •   if (n == 0)
    •    return 0;
    •     
    •   //first and second fibonacci numbers are 1 and 1
    •   if (n == 1 || n == 2)
    •    return 1;
    •     
    •   int current = num1 + num2;
    •     
    •   //compute from the third number onwards by adding the previous fibonacci number
    •   for (int i = 3; i <= n; i++) {
    •    num1 = num2;            
    •    num2 = current;            
    •    current = num1 + num2;
    •   }
    •     
    •   return current;
    •  }
    •   
    •  public static void main(String[] args) {
    •   int nThfibonacciNo = new IterativeFibonacci().fibonacci(17);
    •   System.out.println(nThfibonacciNo);
    •  }
    •   
    • }
  22. How will you compute the sum of all even Fibonacci numbers under 2000?
    This is a bit of a twist to evaluate your ability to construct the logic

    • public class TwistedFibonacci {
    •   
    •  public static void main(String args[]) {
    •   int num1, num2, current, evenSum;
    •   num1 = 0;
    •   num2 = 1;
    •   current = num1 + num2;
    •   evenSum = 0;
    •   
    •   while (current + num2 < 2000) {
    •    num1 = num2;
    •    num2 = current;
    •    current = num1 + num2;
    •      
    •    if (current % 2 == 0) { // if the remainder is zero then even number
    •     if (current > 0) {
    •      System.out.println(current);
    •     }
    •   
    •     evenSum += current;
    •    }
    •   }
    •   
    •   System.out.println("Sum of the even Fibonacci numbers  under 2000: " + evenSum);
    •  }
    • }

    • The output is:
    • 2
    • 8
    • 34
    • 144
    • 610
    • Sum of the even Fibonacci numbers  under 2000: 798

What would you like to do?

Home > Flashcards > Print Preview