The two are logically the same, but one is less efficient than the other.
This is one logical unit of execution:
String test1; // Declare
This is two logical units of execution:
String test2 = null; // Declare/assignment
This leads to a small performance penalty that you can observe in large loops:
Long t1 = DateTime.now().getTime();
for(Integer i = 0; i < 100000; i++) {
String s = null;
}
Long t2 = DateTime.now().getTime();
for(Integer i = 0; i < 100000; i++) {
String s;
}
Long t3 = DateTime.now().getTime();
System.debug(LoggingLevel.ERROR, t2-t1);
System.debug(LoggingLevel.ERROR, t3-t2);
Typical examples:
09:48:26.028 (28836934)|CODE_UNIT_STARTED|[EXTERNAL]|execute_anonymous_apex
09:48:26.113 (113284690)|USER_DEBUG|[10]|ERROR|47
09:48:26.113 (113325519)|USER_DEBUG|[11]|ERROR|36
09:48:20.024 (24803638)|CODE_UNIT_STARTED|[EXTERNAL]|execute_anonymous_apex
09:48:20.100 (100566826)|USER_DEBUG|[10]|ERROR|39
09:48:20.100 (100609709)|USER_DEBUG|[11]|ERROR|36
09:48:04.068 (68311804)|CODE_UNIT_STARTED|[EXTERNAL]|execute_anonymous_apex
09:48:04.151 (151989844)|USER_DEBUG|[10]|ERROR|44
09:48:04.152 (152032421)|USER_DEBUG|[11]|ERROR|39
This yields about a 10% increase in execution time. Of course, in all but the largest loops, this difference would be inconsequential.
null
to a variable, albeit on declaration or just somewhere after it's been declared.