A Java Crash Course for Ruby Developers, Part 1
(Part 1 of a multi-part series. Introduction.)
Welcome! Let's get right to it. This is going to be largely unstructured and reflects the current state of my Java experience, which is very little. It will hopefully help other devs who are getting started. I expect that:
- You know some basics about Java
- You know Ruby basics
I'm not going to mention many things that should be obvious, like... lines are terminated with semi-colons, Java is not sensitive to whitespace, etc,...
Let's do this.
#### Use an IDE for Development.While you can use a text editor to write Java, every resource I encountered referenced some IDE or another. The two big ones seem to be Eclipse and NetBeans. I ended up with NetBeans, though I honestly can't remember why. Having just switched from SublimeText to RubyMine, this was a pretty easy transition for me, as NetBeans feels a hell of a lot like RM, but it might take some getting used to for you. (Incidentally, JetBrains are the developers of IntelliJ, a Java IDE that I imagine is pretty amazing. It's also not free, so...)
If this is your first time using an IDE, the key features that I can no longer live without are:
- Command + Click on a method to find its definition.
- Right-click a method and click "Find Usages" to find everywhere that it's used
- Highlight, right-click, "Refactor" menu to easily move pieces of code into methods, new classes, sub/parent classes, etc,...
- Built in test integration and compilation
- Easy dependency management
- Flagging unused variables and dependencies
- Hints RE: object types required during method calls or class initialization
Focus on that and you'll adjust in no time.
Don't start from nothing. Find an open source project to modify.
Starting a new language can be daunting, especially something like Java that introduces some concepts that are very different from Ruby. I set my sights on GraphAware's TimeTree plugin for Neo4j, found where the public API endpoints were exposed, copied the methods, and started modifying from there. Anyone who learned HTML in the days before CodeAcademy and sites like it will probably have done this at some point.
Plan on writing tests.
Because Java is compiled, it's very annoying to test your code by poking at it in your app. Write small methods, test carefully, and you'll save yourself a lot of time. There's JUnit, which uses methods and simple assert
methods to test behavior (sound familiar?) and there's also Cucumber-JVM, if you're more comfortable there.
Class Definitions
One of the hardest parts of figuring out Java for me was just reading the damn code. You should already know that Java is strongly typed, but... final? Static? Void? WTF? This ends up being very easy.
Basic class Signature Examples
The typical Java class signature looks like this:
public class MyClass {}
That makes sense, right? public
, protected
, or private
define visibility, just like Ruby. The rest is self-explanatory. Java has single inheritance and uses extends
, so:
public class MyClass extends AnotherClass {}
Interfaces
Instead of modules, Java has interfaces. An interface
lists methods that must be implemented in the class. It deals with what is there but not how they will behave. (NOTE: In Java 8, you can define default behavior for interface methods. This helps you out in the event you want to add a method to an interface that is widely implemented.) A class that includes an interface looks like this:
public class MyClass implements MyInterface {}
At that point, any methods defined in MyInterface
are expected to also be defined in MyClass
. If they aren't and default behavior isn't provided in the interface, your code will not compile.
Interfaces are extremely helpful because when it comes to method signatures, you can say that a method expects or returns a MyInterface
instead of MyClass
. It would be like doing this in Ruby:
module MyModule; end class MyClass extend MyModule end # Will return true MyClass.new.is_a?(MyModule)
Ruby doesn't work that way; instead, we'd use respond_to?
, but Java's way gets us to the same place by a different route: we are checking that a given object has specific behavior implemented. We care less about the object and more about what it can or cannot do.
There's a lot more to interfaces than I'm going to get into now, but this is a good start.
There is no initialize
method, but...
Instead of initialize
, you define a method of the same name as the class and do not include a return value.
public class MyClass { public AnotherClass myVar; public MyClass(AnotherClass myVar) { this.myVar = myVar; } }
That means that MyClass
is initialized with one argument, an object of type AnotherClass
, that will be referred to within its init method as myVar
. Once instantiated, myObj.myVar
will be set to this argument. For example:
# Define the variable MyClass myObj; # Instantiate the object myObj = new MyClass(myOtherObj); # call `myVar`, will return `myOtherObj` return myObj.myVar;
There can be multiple constructors for a class
Java makes it possible to instantiate a new object using many different arguments, just define multiple constructor methods.
public class MyClass { public MyClass(AnotherClass myVar) { # do something } public MyClass(DifferentClass myMar, AnotherClass myOtherVar) { # do something } }
Of course, the constructor methods would do something with those vars. Point is, you have flexibility in how you instantiate objects. This same rule holds true for methods.
Method definitions
Basic Method Signature Examples
Method signatures can omit visibility and will default to public
but the best practice seems to always include it. They look like this:
public ReturnType methodName(FirstArgClass firstVar, SecondArgClass secondVar) { # Some code return # something here }
Note that every method identifies not only what types of objects it expects but what it returns. To define a method that does not return anything, use the void
keyword.
public void ReturnType methodName() { # do something but do not call `return`! }
To define a class method, use the static
keyword.
public static ReturnType methodName() { return null; }
Method arguments are typed
Method arguments follow the simple pattern of ObjectType variableName
, separated by commas.
public String myMethod(String firstVar, int secondVar) { return firstVar; }
There's not much more to it than that.
Variables
Variables are declared with types
This shouldn't have to be said at this point but:
String myVar;
That would allocate memory for a new String with name myVar
.
Declarations can be assigned immediately... but this does not seem to be best practice
You can do this:
# assume `thisOtherMethod` returns something of type MyObj... MyObj var1 = thisOtherMethod(anotherVar);
My IDE corrects me when I do this, though, so I get the sense that it's a best practice to declare first, then assign.
Instance variables
Define instance variables in the body of your class.
public class MyClass { public String myString; public List myList; }
Those can now be assigned within methods. This is the equivalent of @var
in Ruby.
Class variables
Define class variables using the static
keyword in the body of the class.
public class MyClass { public static String myString; }
Constants
Define constants using both static
and final
.
public class MyClass { private static final String myString = 'oh hai'; }
The final
keyword indicates a value that cannot be changed.
That's it for now. Keep an eye out for part two. Hope this helps someone out.