Skip to: Site menu | Main content

Jedi

Decluttering Java

Examples Print

Does A Collection Contain an Item With a Property of a Particular Value?

This example uses FirstOrderLogic.exists(java.util.Collection, Filter).

Conventional Java

Foo.java
...
public Bar getBar() {
    return bar;
}
...
SomeClass.java
...
public boolean containsFooWithBar(Bar requiredBar) {
    Iterator<Foo> iter = foos.iterator();
    while (iter.hasNext()) {
        Foo foo = iter.next();
        if (foo.getBar().equals(requiredBar)) {
            return true;
        }
    }

    return false;
}
...

Jedi Java

Foo.java
// Annotate the accessor
@JediFilter
public Bar getBar() {
    return bar;
}
...
SomeClass.java
...
public boolean containsFooWithBar(Bar requiredBar) {
    return exists(foos, getBarEqualsFilter(requiredBar));
}
...

The getBarEqualsFilter method was generated by the @JediFilter annotation and statically imported.

Select All Items From a Collection Where The Item's Property Matches a Given Value

This example uses FunctionalPrimitives.select(java.util.Collection, Filter).

Conventional Java

Conventional Foo.java as in previous example.

SomeClass.java
...
public List<Foo> getFoosWithBar(Bar requiredBar) {
    List<Foo> matching = new ArrayList<Foo>();
    Iterator<Foo> iter = foos.iterator();
    while (iter.hasNext()) {
        Foo foo = iter.next();
        if (foo.getBar().equals(requiredBar)) {
            matching.add(foo);
        }
    }

    return matching;
}
...

Jedi Java

Jedi Foo.java as in previous example.

SomeClass.java
...
public List<Foo> getFoosWithBar(Bar requiredBar) {
    return select(foos, getBarEqualsFilter(requiredBar));
}
...

Get The Values of A Property For All Items In A Collection

This example uses FunctionalPrimitives.collect(java.util.Collection, Functor).

Conventional Java

Conventional Foo.java as in previous example.

SomeClass.java
...
public List<Bar> getBars() {
    List<Bar> bars = new ArrayList<Bar>();
    Iterator<Foo> iter = foos.iterator();
    while (iter.hasNext()) {
        Foo foo = iter.next();
        bars.add(foo.getBar());
    }

    return bars;
}
...

Jedi Java

Foo.java
// Annotate the accessor
@JediFunctor
public Bar getBar() {
    return bar;
}
...
SomeClass.java
...
public List<Bar> getBars() {
    return collect(foos, getBarFunctor());
}
...

The getBarFunctor method was generated by the @JediFunctor annotation and statically imported.

Quick Sort

This example uses:

Conventional Java

Quicksort.java
public <T> void qsort(T[] collection, Comparator<T> comparator, int lo, int hi) {
    int h, l, p, t;
 
    if (lo < hi) {
        l = lo;
        h = hi;
        p = collection[hi];
 
        do {
            while ((l < h) && (comparator.compareTo(collection[l], p) < 0)) {
                l = l+1;
            }
            while ((h > l) && (comparator.compareTo(collection[h], p) >= 0)) {
                h = h-1;
            }
            if (l < h) {
                t = collection[l];
                collection[l] = collection[h];
                collection[h] = t;
            }
        } while (l < h);
 
        t = collection[l];
        collection[l] = collection[hi];
        collection[hi] = t;
 
        qsort( collection, lo, l-1 );
        qsort( collection, l+1, hi );
    }
}

Jedi Java

QuickSort.java
 
    public static <T> List<T> sort(final List<T> collection, final Comparator<T> comparator) {
        if (collection.size() < 2) {
            return asList(collection);
        }

        final T head = head(collection);
        final List<T> tail = tail(collection);
        final List<T> lower = select(tail, lessThan(head, comparator));
        final List<T> upper = select(tail, not(lessThan(head, comparator)));
        return append(sort(lower, comparator), list(head), sort(upper, comparator));
    }

Get All Non-Empty Strings From a Collection

Conventional Java

This example uses:

SomeClass.java
...
public List<String> getNonEmptyStrings(Collection<String> strings) {
    List<String> result = new ArrayList<String>();
    Iterator<String> iter = strings.iterator();
    while (iter.hasNext()) {
        String s = iter.next();
        if (s.length() > 0) {
            result.add(s);
        }
    }

    return result;
}
...

Jedi Java

SomeClass.java
...
@SithFilter(type = String.class, methods = @SithMethod(name = "length"))
public List<String> getNonEmptyStrings(Collection<String> strings) {
    return select(strings, not(lengthEqualsFilter(0)));
}
...

Options

(see Options)

Everyone has come across nasty code like this in many languages:

SomeClass.java
String foo = map.get("key");
if (foo == null) {
  throw new WhatsItException("Where's the foo");
}
// use foo

These situations occur during lazy initialisation, retrieving values from maps, retrieving data from a database. It's everywhere and it's nasty.

The reason it's nasty is that a null reference sits around waiting for some unfortunate code to dereference it. The even more unfortunate programmer has to then figure where it came from which is not always trivial.

This is where Option comes in. Let's rewrite the above code block:

SomeClass.java
Option<String> foo = Options.get(map, "key");
foo.match(new OptionMatcher() {
  public void caseSome(String value) { // excellent we can use the value }
  public void caseNone(None<String> none) { throw new WhatsItException("Where's the foo?"); }
});

The point is that there are no nulls in this code and the possibility that the value may not exist has to be dealt with.

If you just want a default value if the Option is a None then:

SomeClass.java
String foo = myOption.getOrElse("default value");
// or
String foo = myOption.getOrElse(aFunctor);

where aFunctor is a Jedi Functor0 that will generate the value you need.

This is JEDI though, so there is also another way to use Options:

SomeClass.java
Option<String> foo = Options.get(map, "key");
foo.match(someCommand, noneCommand);

Where someCommand and noneCommand are Commands to be executed depending on whether foo is a Some or None. (The commands could be generated by annotations against existing methods of course.) The someCommand will be given the actual value contained in the Some instance so it does not need to match on an Option. This can be much more concise with a static import:

SomeClass.java
get(map, "key").match(someCommand, noneCommand);

Another use is performing some action if a value exists. Normally this requires a null check. In Jedi, with Commands and Option:

SomeClass.java
Option<String> foo = ...
foo.forEach(commandTakingString);

Project Euler Example

This example illustrates solutions to Project Euler problems using Jedi.

The code was compiled with the jediSuppressProxySuffix switch which is why none of the factory methods have the word 'proxy' in them - see the example build file included in the distribution's examples.

ProjectEuler.java
package jedi.example;

import static jedi.assertion.Assert.assertEqual;
import static jedi.assertion.Assert.assertTrue;
import static jedi.example.ProjectEulerStaticClosureFactory.divFilter;
import static jedi.example.ProjectEulerStaticClosureFactory.isPalindromeFilter;
import static jedi.example.ProjectEulerStaticClosureFactory.multiplyFunctor2;
import static jedi.example.ProjectEulerStaticClosureFactory.sumFunctor2;
import static jedi.functional.Coercions.list;
import static jedi.functional.Comparables.sort;
import static jedi.functional.FirstOrderLogic.or;
import static jedi.functional.FunctionalPrimitives.fold;
import static jedi.functional.FunctionalPrimitives.head;
import static jedi.functional.FunctionalPrimitives.produce;
import static jedi.functional.FunctionalPrimitives.reverse;
import static jedi.functional.FunctionalPrimitives.select;

import java.util.ArrayList;
import java.util.List;

import jedi.annotation.JediCut;
import jedi.annotation.JediFilter;
import jedi.annotation.JediFunctor;

public class ProjectEuler {
 
 /**
  * Find the sum of all the multiples of 3 or 5 below 1000.
  */
 @SuppressWarnings("unchecked")
 public void problemOne() {
  assertEqual(new Integer(233168),      
    fold(0,          
     select(         
      range(1,1000),       
      or(         
       divFilter(this, 3),    
       divFilter(this, 5))),   
      sumFunctor2(this)),     
     "Problem one: Find the sum of all the multiples of 3 or 5 below 1000.");
 }
 
 /**
  * The sum of the even Fibonacci numbers which are at most 4,000,000
  */
 public void problemTwo() {
  assertEqual(new Integer(4613732),    
    fold(0,        
     select(       
      fib(4000000),     
      divFilter(this, 2)),   
     sumFunctor2(this)),    
     "Problem two: The sum of the even Fibonacci numbers which are at most 4,000,000");
 }
 
 /**
  * what is the largest prime factor of the number 600851475143 ?
  */
 public void problemThree() {
  assertTrue(true, "Problem three: Nothing interesting for JEDI to do!");
 }
 
 /**
  * Find the largest palindrome made from the product of two 3-digit numbers.
  */
 public void problemFour() {
  assertEqual(new Integer(906609),         
    head(              
     reverse(            
      sort(            
       select(           
        produce(         
         range(100,1000),       
         range(100,1000),       
         multiplyFunctor2(this)),     
        isPalindromeFilter(this))))),    
     "Problem four: Find the largest palindrome made from the product of two 3-digit numbers.");
 }
 
 /**
  * This method has a JediFilter which creates the isPalindromeFilter statically imported above.
  */
 @JediFilter
 boolean isPalindrome(Integer x) {
  String s = x.toString();
  return s.equals(new StringBuffer(s).reverse().toString());
 }
 
 /**
  * This method has a JediFilter which creates the divFilter statically imported above.
  * @return x % y == 0
  */
 @JediFilter(cut= {@JediCut(parameters="y")})
 boolean div(Integer x, Integer y) {
  return x % y == 0;
 }
 
 /**
  * This method has a JediFunctor which creates the sumFunctor2 statically imported above.
  * @return a + b
  */
 @JediFunctor
 Integer sum(Integer a, Integer b) {
  return a + b;
 }

 /**
  * This method has a JediFunctor which creates the multiplyFunctor2 statically imported above.
  * @return a * b
  */
 @JediFunctor
 Integer multiply(Integer a, Integer b) {
  return a * b;
 }
 
 public List<Integer> fib(int limit) {
  return fibh(new ArrayList<Integer>(), limit);
 }
 
 private List<Integer> fibh(List<Integer> c, int limit) {
  if (c.isEmpty()) return fibh(list(new Integer(1), new Integer(0)), limit);
  final int sum = c.get(0) + c.get(1);
  if (sum > limit) return c;
  c.add(0, sum);
  return fibh(c, limit);
 }
 
 public List<Integer> range(int a, int b) {
  List<Integer> list = new ArrayList<Integer>(b - a);
  for (int i = a; i < b; i++) {
   list.add(i);
  }
  return list;
 }
 
 public static void main(String[] args) {
  ProjectEuler projectEuler = new ProjectEuler();
  projectEuler.problemOne();
  projectEuler.problemTwo();
  projectEuler.problemThree();
  projectEuler.problemFour();
 }
 
}