JavaプログラマのためのApex入門 その1

Apexは見た目がJavaっぽいですが微妙にJavaと違うという部分をまとめました。

tamuです。

Apex入門記事です。

「JavaやってたからApexも書けるよね」と言われても大丈夫なように、主にJavaと違う部分についてまとめています。

package について

Javaでいうところの package はありません。

AppExchange を開発する際にその AppExchange を識別するための名前空間(namespace)を登録することはありますが、それもJavaでいうところの package ではありません。

package は存在しない、と思っておきましょう。

class の書き方

↓ ここにすべてが書いてあるのですが抜粋して説明します。

https://developer.salesforce.com/docs/atlas.ja-jp.234.0.apexcode.meta/apexcode/apex_classes_defining.htm

1
2
3
4
5
6
7
8
9
[global|public|private|(何もつけない)] /* アクセス範囲 */
[with sharing|without sharing|(何もつけない)] /* レコードへのアクセス権限 */
[virtual|abstract|(何もつけない)] /* overrideさせるかどうか */
class
AnyClassName
(extends BaseClass) /* 拡張クラスかどうか */
(implements Interface[, Interface]] /* interfaceの実装かどうか */
{
}

アクセス範囲

global

  • すべての Apex クラスからアクセス可能
  • 外部から呼び出すような class に使う
  • global を使うことはあまりお勧めしないとのこと

これは Java にはないです。 ほとんどの場合で global が必要なことはないので、次で説明する public を使っておきましょう。 逆にいうと global がついている class は「外部から呼び出される class」と思って読んでおきましょう。

public

  • 同じ名前空間であればアクセス可能
  • トップレベルでクラス宣言をするのであればこれを指定しておけば良い

テストコードじゃないコードは public をつけてクラス宣言をすれば良いです。

「同じ名前空間であれば」とあるのは、たとえば AppExchange のクラスが public で宣言してあれば、AppExchange 外のクラスは AppExchange のクラスを読んだり実行したりすることはできません。

private

  • 外から参照しない inner class だったらこれをつければ良い
  • テストコードはトップレベルで宣言するときにつける
  • private と(何もつけない)は同じ扱い

余談

Java でいうところの static class はありません。

Java で inner class を static で定義するとこのように書きますが、

1
2
3
4
5
6
public class ClassA {
    public static class ClassB {
    }
}

ClassA.ClassB b = new ClassA.ClassB();

Apex では inner class はこのように書きます。

1
2
3
4
5
6
public class ClassA {
    public class ClassB {
    }
}

ClassA.ClassB b = new ClassA.ClassB();

アクセス権限

Apex クラスがアクセスするレコードの取り扱いについて定義します。 sharing rule の範囲で動くのか、 sharing rule を無視して動くのか、のように sharing の語源を頭においておくとイメージしやすいかと思います。

with sharing

  • 共有ルールの範囲内でレコードにアクセスできる
    • → そのコードを実行したユーザがアクセスできるレコードのみアクセスできる。アクセスできないレコードはアクセスできない

without sharing

  • 共有ルールを超えてレコードにアクセスできる
    • → そのコードを実行したユーザがアクセスできるレコード以外にも、すべてのレコードにアクセスできる

(何もつけない)

  • with sharing と同じです
  • 「必ず付けましょう」 by Salesforce

override させるかどうか

virtual

  • 拡張クラス側での override を可能にします

以下は Java であればコンパイルできますが、 Apex ではコンパイルエラーになります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class BaseClass {
    public void foo() {
        System.debug('foo');
    }
}

// できない
public class ExtendClass extends BaseClass {
    public void foo() {
        System.debug('bar');
    }
}

このように virtual が必要になります。 (Kotlin で class に open を付けないと継承できないのに似てます)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public virtual class VirtualBaseClass {
    public void foo() {
        System.debug('foo');
    }
}

// できる
public class ExtendClass extends VirtualBaseClass {
    public void foo() {
        System.debug('bar');
    }
}

abstract

  • 抽象メソッドが含まれることを宣言します
  • 抽象メソッドが存在していなくてもこのクラスを直接 new することはできません
  • Java でいうところの匿名クラスはないため、かならず実装クラスの定義が必要になります
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public abstract class AbstractFoo {
    public void foo() {
        System.debug('foo');
    }
}

public class ConcreteFoo extends AbstractFoo {
}

// できない (Javaでもできない)
AbstractFoo f = new AbstractFoo();

// できない (Javaだとできる)
AbstractFoo f = new AbstractFoo(){};

// できる
AbstractFoo f = new ConcreteFoo();

// できる
new ConcreteFoo().foo();

// できない (Javaだとできる)
AbstractFoo f = new ConcreteFoo() {
    public void foo() {
        System.debug('bar');
    }
};

// できない (Javaだとできる)
new ConcreteFoo() {
    public void foo() {
        System.debug('bar');
    }
}.foo();

拡張クラスかどうか

extends

  • 元の virtual クラスまたは abstract クラスを拡張する場合はこれを付けます

Java と同じです。

interface の実装かどうか

implements

  • interface を実装する場合はこれをつけます

Java と同じです。

できないこと

クラス拡張の禁止 (final)

  • 拡張禁止を明示することはできません
  • virtual を付けなければ拡張できないので、それで代用します

ここはKotlinと同じです。

generics

generics は事前に用意されているクラスでしか使えません。 このような宣言ができません。 宣言はできないのですが、キャストはできるので Java 1.3 時代だと思えばなんとかなります。

1
2
3
public abstract class AbstractClass<T> {
    abstract public void process(List<T> l);
}

匿名クラス

abstract のところで触れましたが、 匿名クラスは書けません。 abstract クラスや interface を使うには必ずリテラルに書いた実装クラスが必要になります。

interface の書き方

class 宣言に似てます。

というか Java とほとんど同じです。

1
2
3
4
5
6
[global|public|private|(何もつけない)] /* アクセス範囲 */
interface
AnyInterfaceName
(extends Interface) /* 拡張するかどうか */
{
}

アクセス範囲

class のものと同じです。 トップレベルで宣言する場合は global or public を付けましょう。

AppExchange 開発では globalinterface はリリースすると変更できないそうなのでお気をつけて。 (https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_classes_interfaces.htm の一番下に書いてあります)

拡張するかどうか

ちゃんとドキュメントには書いてないのですが、 Java と同じように interface を拡張することができます。 (コンパイルは通ります)

がちゃんとドキュメント化されていないので、 interface を拡張するのではなく、 abstract classimplements するほうが良いかなと思います。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public interface PurchaseOrder {
    void order(String productName);
}

// コンパイルは通るけど interface は extends できるとは書いていない
public interface PurchaseManagement extends PurchaseOrder {
    void cancel(String productName);
}

// こちらのほうがドキュメント化された仕様に基づいたコードになっている
public abstract AbstractPurchaseManagement implements PurchaseOrder {
    public abstract void cancel(String productName);
}

余談

私は publicinterface を宣言することはあまりありません。

Java で interface を定義するときは、同じI/Fで呼び出したい処理がいろいろなパッケージにまたがるときが多いです。 Apex はパッケージで namespace を分けるわけではないため、その interface を定義するメリットがあまりないためです。

Licensed under CC BY 4.0
Built with Hugo
Theme Stack designed by Jimmy