> Java has the Vector type, which allows for sequences of dynamically varying length
The Vector type in Java has been not best practice since Java 1.5 when the Collections framework came out. In particular, the Java 1.4 days and before all of the collection classes were synchronized leading to some not insignificant performance hits (even in single threaded applications). ArrayList and LinkedList are the classes that came with the rework. In particular, while Vector implements List, its backed by an array and so various list like operations (like adding a large number of elements without presizing the array) can take a performance hit.
> Automatic Storage Management. Java and Python support this. Lisp implementations tend to be more mature and perform better.
There have been numerous changes to the JVM for garbage collection since 1.4. While I can't speak to LISP's garbage collection implementations, Java has come a long ways in the past 16 years.
> Dynamic Typing. Java attaches run-time type information to instances of the class Object, but not to primitive data elements. However, Java requires a type declaration for every variable. This has some advantages for production code, but has disadvantages for rapid prototyping and evolution of programs. Java does not have a generic/template system that would allow types life Vector<String>, and suffers greatly because of it.
Specifically, Vector<String> has been available since Java 1.5. Java 10 brings local type inference ( https://developer.oracle.com/java/jdk-10-local-variable-type... ) so instead of
Map<User, List<String>> userChannel = new HashMap<User, List<String>>();
in Java 1.7 one can write:
Map<User, List<String>> userChannel = new HashMap<>();
and in Java 10:
var userChannels = new HashMap<User, List<String>>();
> First-Class Functions. Java has anonymous classes, which serve some of the purposes of closures, although in a less versatile way with a more clumsy syntax. In Lisp, we can say (lambda (x) (f (g x))) where in Java we would have to say
new UnaryFunction() {
public Object execute(Object x) {
return (Cast x).g().f();
}
}
Lambdas are available in Java 8. https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaex...
As a note, the bit about python closures being read only ("The only drawback is that closed-over variables are read-only.") gets to a very interesting debate on first class environments that is described at http://funcall.blogspot.com/2009/09/first-class-environments...
> Interactive Environment. Some Java environments allow Lisp-like features such as an intgeractive command loop and stop-and-fix debugging. Lisp environments are still ahead, but that probably won't last long. BlueJ in particular has most of the major features of a good Lisp environment: you can recompile a method into a running program, and you can type in an expression and have it evaluated immediately. It is intended for teaching purposes, and I can't tell if it is suitable for production use. Python has the same interactive approach as Lisp, but the environment is less mature than Lisp's.
Eclipse, Netbeans and IntelliJ all have rather advanced debuggers. Eclipse has a 'display' view as shown in https://www.ibm.com/developerworks/library/os-ecbug/ that allows compilation and execution of arbitrary Java code.
> Extensibility. This may prove to be Java's weak point. Java works well as long as you are willing to make everything a class. If something new like, say, aspect-oriented programming takes off, Lisp would be able to incorporate it with macros, but Java would not.
Aspect oriented coding is well supported in Java with libraries such as https://en.wikipedia.org/wiki/Spring_Framework#Aspect-orient... and https://en.wikipedia.org/wiki/AspectJ .
---------------
Yes, in the Java 1.4 world, what was said was true. That is a very, very long time ago for Java and many of the criticisms that were provided are no longer valid.
The higher order functions of Java are not as Lispy as Perl's, but they exist as Streams. In Java 8, one can write:
int sum = widgets.stream()
.filter(b -> b.getColor() == RED)
.mapToInt(b -> b.getWeight())
.sum();
Note that filter and mapToInt are both taking lambdas are arguments.
I would encourage you to glance at Groovy which in Java is my favorite Perl.
['a', 'b', 'c'].eachWithIndex { it, i ->
println "$i: $it"
}
or for a perl style map:
assert [1, 2, 3].collect { it * 2 } == [2, 4, 6]
and a perl style grep:
assert [1, 2, 3].findAll { it > 1 } == [2, 3]
It also has nice support of closures, lambdas currying and other functional programing concepts (
http://groovy-lang.org/closures.html ). There's also some neat things that one can do with JSR 223 and groovy -
http://groovy-lang.org/integrating.html#jsr223